@@ -2892,33 +2892,36 @@ namespace ts {
28922892 log ( "getCompletionData: Get previous token 2: " + ( new Date ( ) . getTime ( ) - start ) ) ;
28932893 }
28942894
2895- // Check if this is a valid completion location
2896- if ( contextToken && isCompletionListBlocker ( contextToken ) ) {
2897- log ( "Returning an empty list because completion was requested in an invalid position." ) ;
2898- return undefined ;
2899- }
2900-
2901- let options = program . getCompilerOptions ( ) ;
2902- let jsx = options . jsx !== JsxEmit . None ;
2903- let target = options . target ;
2904-
2905- // Find the node where completion is requested on, in the case of a completion after
2906- // a dot, it is the member access expression other wise, it is a request for all
2907- // visible symbols in the scope, and the node is the current location.
2895+ // Find the node where completion is requested on.
2896+ // Also determine whether we are trying to complete with members of that node
2897+ // or attributes of a JSX tag.
29082898 let node = currentToken ;
29092899 let isRightOfDot = false ;
29102900 let isRightOfOpenTag = false ;
29112901
29122902 let location = getTouchingPropertyName ( sourceFile , position ) ;
2913- if ( contextToken ) {
2914- let kind = contextToken . kind ;
2915- if ( kind === SyntaxKind . DotToken && contextToken . parent . kind === SyntaxKind . PropertyAccessExpression ) {
2916- node = ( < PropertyAccessExpression > contextToken . parent ) . expression ;
2917- isRightOfDot = true ;
2903+ if ( contextToken ) {
2904+ // Bail out if this is a known invalid completion location
2905+ if ( isCompletionListBlocker ( contextToken ) ) {
2906+ log ( "Returning an empty list because completion was requested in an invalid position." ) ;
2907+ return undefined ;
29182908 }
2919- else if ( kind === SyntaxKind . DotToken && contextToken . parent . kind === SyntaxKind . QualifiedName ) {
2920- node = ( < QualifiedName > contextToken . parent ) . left ;
2921- isRightOfDot = true ;
2909+
2910+ let { parent, kind } = contextToken ;
2911+ if ( kind === SyntaxKind . DotToken ) {
2912+ if ( parent . kind === SyntaxKind . PropertyAccessExpression ) {
2913+ node = ( < PropertyAccessExpression > contextToken . parent ) . expression ;
2914+ isRightOfDot = true ;
2915+ }
2916+ else if ( parent . kind === SyntaxKind . QualifiedName ) {
2917+ node = ( < QualifiedName > contextToken . parent ) . left ;
2918+ isRightOfDot = true ;
2919+ }
2920+ else {
2921+ // There is nothing that precedes the dot, so this likely just a stray character
2922+ // or leading into a '...' token. Just bail out instead.
2923+ return undefined ;
2924+ }
29222925 }
29232926 else if ( kind === SyntaxKind . LessThanToken && sourceFile . languageVariant === LanguageVariant . JSX ) {
29242927 isRightOfOpenTag = true ;
@@ -3097,11 +3100,11 @@ namespace ts {
30973100 return scope ;
30983101 }
30993102
3100- function isCompletionListBlocker ( previousToken : Node ) : boolean {
3103+ function isCompletionListBlocker ( contextToken : Node ) : boolean {
31013104 let start = new Date ( ) . getTime ( ) ;
3102- let result = isInStringOrRegularExpressionOrTemplateLiteral ( previousToken ) ||
3103- isIdentifierDefinitionLocation ( previousToken ) ||
3104- isRightOfIllegalDot ( previousToken ) ;
3105+ let result = isInStringOrRegularExpressionOrTemplateLiteral ( contextToken ) ||
3106+ isIdentifierDefinitionLocation ( contextToken ) ||
3107+ isDotOfNumericLiteral ( contextToken ) ;
31053108 log ( "getCompletionsAtPosition: isCompletionListBlocker: " + ( new Date ( ) . getTime ( ) - start ) ) ;
31063109 return result ;
31073110 }
@@ -3180,12 +3183,12 @@ namespace ts {
31803183 return false ;
31813184 }
31823185
3183- function isInStringOrRegularExpressionOrTemplateLiteral ( previousToken : Node ) : boolean {
3184- if ( previousToken . kind === SyntaxKind . StringLiteral
3185- || previousToken . kind === SyntaxKind . RegularExpressionLiteral
3186- || isTemplateLiteralKind ( previousToken . kind ) ) {
3187- let start = previousToken . getStart ( ) ;
3188- let end = previousToken . getEnd ( ) ;
3186+ function isInStringOrRegularExpressionOrTemplateLiteral ( contextToken : Node ) : boolean {
3187+ if ( contextToken . kind === SyntaxKind . StringLiteral
3188+ || contextToken . kind === SyntaxKind . RegularExpressionLiteral
3189+ || isTemplateLiteralKind ( contextToken . kind ) ) {
3190+ let start = contextToken . getStart ( ) ;
3191+ let end = contextToken . getEnd ( ) ;
31893192
31903193 // To be "in" one of these literals, the position has to be:
31913194 // 1. entirely within the token text.
@@ -3196,8 +3199,8 @@ namespace ts {
31963199 }
31973200
31983201 if ( position === end ) {
3199- return ! ! ( < LiteralExpression > previousToken ) . isUnterminated ||
3200- previousToken . kind === SyntaxKind . RegularExpressionLiteral ;
3202+ return ! ! ( < LiteralExpression > contextToken ) . isUnterminated
3203+ || contextToken . kind === SyntaxKind . RegularExpressionLiteral ;
32013204 }
32023205 }
32033206
@@ -3351,101 +3354,98 @@ namespace ts {
33513354 return false ;
33523355 }
33533356
3354- function isIdentifierDefinitionLocation ( previousToken : Node ) : boolean {
3355- if ( previousToken ) {
3356- let containingNodeKind = previousToken . parent . kind ;
3357- switch ( previousToken . kind ) {
3358- case SyntaxKind . CommaToken :
3359- return containingNodeKind === SyntaxKind . VariableDeclaration ||
3360- containingNodeKind === SyntaxKind . VariableDeclarationList ||
3361- containingNodeKind === SyntaxKind . VariableStatement ||
3362- containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { foo, |
3363- isFunction ( containingNodeKind ) ||
3364- containingNodeKind === SyntaxKind . ClassDeclaration || // class A<T, |
3365- containingNodeKind === SyntaxKind . FunctionDeclaration || // function A<T, |
3366- containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A<T, |
3367- containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [x, y|
3357+ function isIdentifierDefinitionLocation ( contextToken : Node ) : boolean {
3358+ let containingNodeKind = contextToken . parent . kind ;
3359+ switch ( contextToken . kind ) {
3360+ case SyntaxKind . CommaToken :
3361+ return containingNodeKind === SyntaxKind . VariableDeclaration ||
3362+ containingNodeKind === SyntaxKind . VariableDeclarationList ||
3363+ containingNodeKind === SyntaxKind . VariableStatement ||
3364+ containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { foo, |
3365+ isFunction ( containingNodeKind ) ||
3366+ containingNodeKind === SyntaxKind . ClassDeclaration || // class A<T, |
3367+ containingNodeKind === SyntaxKind . FunctionDeclaration || // function A<T, |
3368+ containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A<T, |
3369+ containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [x, y|
33683370
3369- case SyntaxKind . DotToken :
3370- return containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [.|
3371+ case SyntaxKind . DotToken :
3372+ return containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [.|
33713373
3372- case SyntaxKind . ColonToken :
3373- return containingNodeKind === SyntaxKind . BindingElement ; // var {x :html|
3374+ case SyntaxKind . ColonToken :
3375+ return containingNodeKind === SyntaxKind . BindingElement ; // var {x :html|
33743376
3375- case SyntaxKind . OpenBracketToken :
3376- return containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [x|
3377+ case SyntaxKind . OpenBracketToken :
3378+ return containingNodeKind === SyntaxKind . ArrayBindingPattern ; // var [x|
33773379
3378- case SyntaxKind . OpenParenToken :
3379- return containingNodeKind === SyntaxKind . CatchClause ||
3380- isFunction ( containingNodeKind ) ;
3381-
3382- case SyntaxKind . OpenBraceToken :
3383- return containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { |
3384- containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface a { |
3385- containingNodeKind === SyntaxKind . TypeLiteral ; // let x : { |
3386-
3387- case SyntaxKind . SemicolonToken :
3388- return containingNodeKind === SyntaxKind . PropertySignature &&
3389- previousToken . parent && previousToken . parent . parent &&
3390- ( previousToken . parent . parent . kind === SyntaxKind . InterfaceDeclaration || // interface a { f; |
3391- previousToken . parent . parent . kind === SyntaxKind . TypeLiteral ) ; // let x : { a; |
3392-
3393- case SyntaxKind . LessThanToken :
3394- return containingNodeKind === SyntaxKind . ClassDeclaration || // class A< |
3395- containingNodeKind === SyntaxKind . FunctionDeclaration || // function A< |
3396- containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A< |
3397- isFunction ( containingNodeKind ) ;
3398-
3399- case SyntaxKind . StaticKeyword :
3400- return containingNodeKind === SyntaxKind . PropertyDeclaration ;
3401-
3402- case SyntaxKind . DotDotDotToken :
3403- return containingNodeKind === SyntaxKind . Parameter ||
3404- containingNodeKind === SyntaxKind . Constructor ||
3405- ( previousToken . parent && previousToken . parent . parent &&
3406- previousToken . parent . parent . kind === SyntaxKind . ArrayBindingPattern ) ; // var [...z|
3407-
3408- case SyntaxKind . PublicKeyword :
3409- case SyntaxKind . PrivateKeyword :
3410- case SyntaxKind . ProtectedKeyword :
3411- return containingNodeKind === SyntaxKind . Parameter ;
3412-
3413- case SyntaxKind . ClassKeyword :
3414- case SyntaxKind . EnumKeyword :
3415- case SyntaxKind . InterfaceKeyword :
3416- case SyntaxKind . FunctionKeyword :
3417- case SyntaxKind . VarKeyword :
3418- case SyntaxKind . GetKeyword :
3419- case SyntaxKind . SetKeyword :
3420- case SyntaxKind . ImportKeyword :
3421- case SyntaxKind . LetKeyword :
3422- case SyntaxKind . ConstKeyword :
3423- case SyntaxKind . YieldKeyword :
3424- case SyntaxKind . TypeKeyword : // type htm|
3425- return true ;
3426- }
3380+ case SyntaxKind . OpenParenToken :
3381+ return containingNodeKind === SyntaxKind . CatchClause ||
3382+ isFunction ( containingNodeKind ) ;
3383+
3384+ case SyntaxKind . OpenBraceToken :
3385+ return containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { |
3386+ containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface a { |
3387+ containingNodeKind === SyntaxKind . TypeLiteral ; // let x : { |
3388+
3389+ case SyntaxKind . SemicolonToken :
3390+ return containingNodeKind === SyntaxKind . PropertySignature &&
3391+ contextToken . parent && contextToken . parent . parent &&
3392+ ( contextToken . parent . parent . kind === SyntaxKind . InterfaceDeclaration || // interface a { f; |
3393+ contextToken . parent . parent . kind === SyntaxKind . TypeLiteral ) ; // let x : { a; |
3394+
3395+ case SyntaxKind . LessThanToken :
3396+ return containingNodeKind === SyntaxKind . ClassDeclaration || // class A< |
3397+ containingNodeKind === SyntaxKind . FunctionDeclaration || // function A< |
3398+ containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A< |
3399+ isFunction ( containingNodeKind ) ;
3400+
3401+ case SyntaxKind . StaticKeyword :
3402+ return containingNodeKind === SyntaxKind . PropertyDeclaration ;
3403+
3404+ case SyntaxKind . DotDotDotToken :
3405+ return containingNodeKind === SyntaxKind . Parameter ||
3406+ ( contextToken . parent && contextToken . parent . parent &&
3407+ contextToken . parent . parent . kind === SyntaxKind . ArrayBindingPattern ) ; // var [...z|
3408+
3409+ case SyntaxKind . PublicKeyword :
3410+ case SyntaxKind . PrivateKeyword :
3411+ case SyntaxKind . ProtectedKeyword :
3412+ return containingNodeKind === SyntaxKind . Parameter ;
3413+
3414+ case SyntaxKind . ClassKeyword :
3415+ case SyntaxKind . EnumKeyword :
3416+ case SyntaxKind . InterfaceKeyword :
3417+ case SyntaxKind . FunctionKeyword :
3418+ case SyntaxKind . VarKeyword :
3419+ case SyntaxKind . GetKeyword :
3420+ case SyntaxKind . SetKeyword :
3421+ case SyntaxKind . ImportKeyword :
3422+ case SyntaxKind . LetKeyword :
3423+ case SyntaxKind . ConstKeyword :
3424+ case SyntaxKind . YieldKeyword :
3425+ case SyntaxKind . TypeKeyword : // type htm|
3426+ return true ;
3427+ }
34273428
3428- // Previous token may have been a keyword that was converted to an identifier.
3429- switch ( previousToken . getText ( ) ) {
3430- case "class" :
3431- case "interface" :
3432- case "enum" :
3433- case "function" :
3434- case "var" :
3435- case "static" :
3436- case "let" :
3437- case "const" :
3438- case "yield" :
3439- return true ;
3440- }
3429+ // Previous token may have been a keyword that was converted to an identifier.
3430+ switch ( contextToken . getText ( ) ) {
3431+ case "class" :
3432+ case "interface" :
3433+ case "enum" :
3434+ case "function" :
3435+ case "var" :
3436+ case "static" :
3437+ case "let" :
3438+ case "const" :
3439+ case "yield" :
3440+ return true ;
34413441 }
34423442
34433443 return false ;
34443444 }
34453445
3446- function isRightOfIllegalDot ( previousToken : Node ) : boolean {
3447- if ( previousToken && previousToken . kind === SyntaxKind . NumericLiteral ) {
3448- let text = previousToken . getFullText ( ) ;
3446+ function isDotOfNumericLiteral ( contextToken : Node ) : boolean {
3447+ if ( contextToken . kind === SyntaxKind . NumericLiteral ) {
3448+ let text = contextToken . getFullText ( ) ;
34493449 return text . charAt ( text . length - 1 ) === "." ;
34503450 }
34513451
0 commit comments