@@ -2983,21 +2983,32 @@ namespace ts {
2983
2983
}
2984
2984
2985
2985
function tryGetGlobalSymbols ( ) : boolean {
2986
- let containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion ( contextToken ) ;
2987
- if ( containingObjectLiteral ) {
2986
+ let objectLikeContainer = tryGetObjectLikeCompletionContainer ( contextToken ) ;
2987
+ if ( objectLikeContainer ) {
2988
2988
// Object literal expression, look up possible property names from contextual type
2989
2989
isMemberCompletion = true ;
2990
2990
isNewIdentifierLocation = true ;
2991
2991
2992
- let contextualType = typeChecker . getContextualType ( containingObjectLiteral ) ;
2993
- if ( ! contextualType ) {
2992
+ let typeForObject : Type ;
2993
+ let existingMembers : Declaration [ ] ;
2994
+
2995
+ if ( objectLikeContainer . kind === SyntaxKind . ObjectLiteralExpression ) {
2996
+ typeForObject = typeChecker . getContextualType ( < ObjectLiteralExpression > objectLikeContainer ) ;
2997
+ existingMembers = ( < ObjectLiteralExpression > objectLikeContainer ) . properties ;
2998
+ }
2999
+ else {
3000
+ typeForObject = typeChecker . getTypeAtLocation ( objectLikeContainer ) ;
3001
+ existingMembers = ( < BindingPattern > objectLikeContainer ) . elements ;
3002
+ }
3003
+
3004
+ if ( ! typeForObject ) {
2994
3005
return false ;
2995
3006
}
2996
3007
2997
- let contextualTypeMembers = typeChecker . getPropertiesOfType ( contextualType ) ;
2998
- if ( contextualTypeMembers && contextualTypeMembers . length > 0 ) {
3008
+ let typeMembers = typeChecker . getPropertiesOfType ( typeForObject ) ;
3009
+ if ( typeMembers && typeMembers . length > 0 ) {
2999
3010
// Add filtered items to the completion list
3000
- symbols = filterContextualMembersList ( contextualTypeMembers , containingObjectLiteral . properties ) ;
3011
+ symbols = filterObjectMembersList ( typeMembers , existingMembers ) ;
3001
3012
}
3002
3013
}
3003
3014
else if ( getAncestor ( contextToken , SyntaxKind . ImportClause ) ) {
@@ -3185,17 +3196,18 @@ namespace ts {
3185
3196
return false ;
3186
3197
}
3187
3198
3188
- function getContainingObjectLiteralApplicableForCompletion ( previousToken : Node ) : ObjectLiteralExpression {
3189
- // The locations in an object literal expression that are applicable for completion are property name definition locations.
3190
-
3191
- if ( previousToken ) {
3192
- let parent = previousToken . parent ;
3193
-
3194
- switch ( previousToken . kind ) {
3199
+ /**
3200
+ * Returns the immediate owning object literal or binding pattern of a context token,
3201
+ * on the condition that one exists and that the context implies completion should be given.
3202
+ */
3203
+ function tryGetObjectLikeCompletionContainer ( contextToken : Node ) : ObjectLiteralExpression | BindingPattern {
3204
+ if ( contextToken ) {
3205
+ switch ( contextToken . kind ) {
3195
3206
case SyntaxKind . OpenBraceToken : // let x = { |
3196
3207
case SyntaxKind . CommaToken : // let x = { a: 0, |
3197
- if ( parent && parent . kind === SyntaxKind . ObjectLiteralExpression ) {
3198
- return < ObjectLiteralExpression > parent ;
3208
+ let parent = contextToken . parent ;
3209
+ if ( parent && ( parent . kind === SyntaxKind . ObjectLiteralExpression || parent . kind === SyntaxKind . ObjectBindingPattern ) ) {
3210
+ return < ObjectLiteralExpression | BindingPattern > parent ;
3199
3211
}
3200
3212
break ;
3201
3213
}
@@ -3234,8 +3246,7 @@ namespace ts {
3234
3246
containingNodeKind === SyntaxKind . ClassDeclaration || // class A<T, |
3235
3247
containingNodeKind === SyntaxKind . FunctionDeclaration || // function A<T, |
3236
3248
containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A<T, |
3237
- containingNodeKind === SyntaxKind . ArrayBindingPattern || // var [x, y|
3238
- containingNodeKind === SyntaxKind . ObjectBindingPattern ; // function func({ x, y|
3249
+ containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [x, y|
3239
3250
3240
3251
case SyntaxKind . DotToken :
3241
3252
return containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [.|
@@ -3253,8 +3264,7 @@ namespace ts {
3253
3264
case SyntaxKind . OpenBraceToken :
3254
3265
return containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { |
3255
3266
containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface a { |
3256
- containingNodeKind === SyntaxKind . TypeLiteral || // let x : { |
3257
- containingNodeKind === SyntaxKind . ObjectBindingPattern ; // function func({ x|
3267
+ containingNodeKind === SyntaxKind . TypeLiteral ; // let x : { |
3258
3268
3259
3269
case SyntaxKind . SemicolonToken :
3260
3270
return containingNodeKind === SyntaxKind . PropertySignature &&
@@ -3346,26 +3356,39 @@ namespace ts {
3346
3356
return filter ( exports , e => ! lookUp ( exisingImports , e . name ) ) ;
3347
3357
}
3348
3358
3349
- function filterContextualMembersList ( contextualMemberSymbols : Symbol [ ] , existingMembers : Declaration [ ] ) : Symbol [ ] {
3359
+ function filterObjectMembersList ( contextualMemberSymbols : Symbol [ ] , existingMembers : Declaration [ ] ) : Symbol [ ] {
3350
3360
if ( ! existingMembers || existingMembers . length === 0 ) {
3351
3361
return contextualMemberSymbols ;
3352
3362
}
3353
3363
3354
3364
let existingMemberNames : Map < boolean > = { } ;
3355
- forEach ( existingMembers , m => {
3356
- if ( m . kind !== SyntaxKind . PropertyAssignment && m . kind !== SyntaxKind . ShorthandPropertyAssignment ) {
3357
- // Ignore omitted expressions for missing members in the object literal
3358
- return ;
3365
+ for ( let m of existingMembers ) {
3366
+ // Ignore omitted expressions for missing members
3367
+ if ( m . kind !== SyntaxKind . PropertyAssignment &&
3368
+ m . kind !== SyntaxKind . ShorthandPropertyAssignment &&
3369
+ m . kind !== SyntaxKind . BindingElement ) {
3370
+ continue ;
3359
3371
}
3360
3372
3373
+ // If this is the current item we are editing right now, do not filter it out
3361
3374
if ( m . getStart ( ) <= position && position <= m . getEnd ( ) ) {
3362
- // If this is the current item we are editing right now, do not filter it out
3363
- return ;
3375
+ continue ;
3364
3376
}
3365
3377
3366
- // TODO(jfreeman): Account for computed property name
3367
- existingMemberNames [ ( < Identifier > m . name ) . text ] = true ;
3368
- } ) ;
3378
+ let existingName : string ;
3379
+
3380
+ if ( m . kind === SyntaxKind . BindingElement && ( < BindingElement > m ) . propertyName ) {
3381
+ existingName = ( < BindingElement > m ) . propertyName . text ;
3382
+ }
3383
+ else {
3384
+ // TODO(jfreeman): Account for computed property name
3385
+ // NOTE: if one only performs this step when m.name is an identifier,
3386
+ // things like '__proto__' are not filtered out.
3387
+ existingName = ( < Identifier > m . name ) . text ;
3388
+ }
3389
+
3390
+ existingMemberNames [ existingName ] = true ;
3391
+ }
3369
3392
3370
3393
let filteredMembers : Symbol [ ] = [ ] ;
3371
3394
forEach ( contextualMemberSymbols , s => {
0 commit comments