@@ -559,6 +559,9 @@ namespace ts.Completions {
559
559
isMemberCompletion = true ;
560
560
isNewIdentifierLocation = false ;
561
561
562
+ // Since this is qualified name check its a type node location
563
+ const isTypeLocation = isPartOfTypeNode ( node . parent ) ;
564
+ const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration ( node ) ;
562
565
if ( node . kind === SyntaxKind . Identifier || node . kind === SyntaxKind . QualifiedName || node . kind === SyntaxKind . PropertyAccessExpression ) {
563
566
let symbol = typeChecker . getSymbolAtLocation ( node ) ;
564
567
@@ -570,16 +573,24 @@ namespace ts.Completions {
570
573
if ( symbol && symbol . flags & SymbolFlags . HasExports ) {
571
574
// Extract module or enum members
572
575
const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
576
+ const isValidValueAccess = ( symbol : Symbol ) => typeChecker . isValidPropertyAccess ( < PropertyAccessExpression > ( node . parent ) , symbol . name ) ;
577
+ const isValidTypeAccess = ( symbol : Symbol ) => symbolCanbeReferencedAtTypeLocation ( symbol ) ;
578
+ const isValidAccess = isRhsOfImportDeclaration ?
579
+ // Any kind is allowed when dotting off namespace in internal import equals declaration
580
+ ( symbol : Symbol ) => isValidTypeAccess ( symbol ) || isValidValueAccess ( symbol ) :
581
+ isTypeLocation ? isValidTypeAccess : isValidValueAccess ;
573
582
forEach ( exportedSymbols , symbol => {
574
- if ( typeChecker . isValidPropertyAccess ( < PropertyAccessExpression > ( node . parent ) , symbol . name ) ) {
583
+ if ( isValidAccess ( symbol ) ) {
575
584
symbols . push ( symbol ) ;
576
585
}
577
586
} ) ;
578
587
}
579
588
}
580
589
581
- const type = typeChecker . getTypeAtLocation ( node ) ;
582
- addTypeProperties ( type ) ;
590
+ if ( ! isTypeLocation ) {
591
+ const type = typeChecker . getTypeAtLocation ( node ) ;
592
+ addTypeProperties ( type ) ;
593
+ }
583
594
}
584
595
585
596
function addTypeProperties ( type : Type ) {
@@ -687,13 +698,88 @@ namespace ts.Completions {
687
698
isStatement ( scopeNode ) ;
688
699
}
689
700
690
- /// TODO filter meaning based on the current context
691
701
const symbolMeanings = SymbolFlags . Type | SymbolFlags . Value | SymbolFlags . Namespace | SymbolFlags . Alias ;
692
- symbols = typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ;
702
+ symbols = filterGlobalCompletion ( typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ) ;
693
703
694
704
return true ;
695
705
}
696
706
707
+ function filterGlobalCompletion ( symbols : Symbol [ ] ) {
708
+ return filter ( symbols , symbol => {
709
+ if ( ! isSourceFile ( location ) ) {
710
+ // export = /**/ here we want to get all meanings, so any symbol is ok
711
+ if ( isExportAssignment ( location . parent ) ) {
712
+ return true ;
713
+ }
714
+
715
+ // This is an alias, follow what it aliases
716
+ if ( symbol && symbol . flags & SymbolFlags . Alias ) {
717
+ symbol = typeChecker . getAliasedSymbol ( symbol ) ;
718
+ }
719
+
720
+ // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
721
+ if ( isInRightSideOfInternalImportEqualsDeclaration ( location ) ) {
722
+ return ! ! ( symbol . flags & SymbolFlags . Namespace ) ;
723
+ }
724
+
725
+ if ( ! isContextTokenValueLocation ( contextToken ) &&
726
+ ( isPartOfTypeNode ( location ) || isContextTokenTypeLocation ( contextToken ) ) ) {
727
+ // Its a type, but you can reach it by namespace.type as well
728
+ return symbolCanbeReferencedAtTypeLocation ( symbol ) ;
729
+ }
730
+ }
731
+
732
+ // expressions are value space (which includes the value namespaces)
733
+ return ! ! ( symbol . flags & SymbolFlags . Value ) ;
734
+ } ) ;
735
+ }
736
+
737
+ function isContextTokenValueLocation ( contextToken : Node ) {
738
+ if ( contextToken ) {
739
+ const parentKind = contextToken . parent . kind ;
740
+ switch ( contextToken . kind ) {
741
+ case SyntaxKind . TypeOfKeyword :
742
+ return parentKind === SyntaxKind . TypeQuery ;
743
+ }
744
+ }
745
+ }
746
+
747
+ function isContextTokenTypeLocation ( contextToken : Node ) {
748
+ if ( contextToken ) {
749
+ const parentKind = contextToken . parent . kind ;
750
+ switch ( contextToken . kind ) {
751
+ case SyntaxKind . ColonToken :
752
+ return parentKind === SyntaxKind . PropertyDeclaration ||
753
+ parentKind === SyntaxKind . PropertySignature ||
754
+ parentKind === SyntaxKind . Parameter ||
755
+ parentKind === SyntaxKind . VariableDeclaration ||
756
+ isFunctionLikeKind ( parentKind ) ;
757
+
758
+ case SyntaxKind . EqualsToken :
759
+ return parentKind === SyntaxKind . TypeAliasDeclaration ;
760
+
761
+ case SyntaxKind . AsKeyword :
762
+ return parentKind === SyntaxKind . AsExpression ;
763
+ }
764
+ }
765
+ }
766
+
767
+ function symbolCanbeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
768
+ // This is an alias, follow what it aliases
769
+ if ( symbol && symbol . flags & SymbolFlags . Alias ) {
770
+ symbol = typeChecker . getAliasedSymbol ( symbol ) ;
771
+ }
772
+
773
+ if ( symbol . flags & ( SymbolFlags . ValueModule | SymbolFlags . NamespaceModule ) ) {
774
+ const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
775
+ // If the exported symbols contains type,
776
+ // symbol can be referenced at locations where type is allowed
777
+ return forEach ( exportedSymbols , symbolCanbeReferencedAtTypeLocation ) ;
778
+ }
779
+
780
+ return ! ! ( symbol . flags & ( SymbolFlags . NamespaceModule | SymbolFlags . Type ) ) ;
781
+ }
782
+
697
783
/**
698
784
* Finds the first node that "embraces" the position, so that one may
699
785
* accurately aggregate locals from the closest containing scope.
@@ -1126,21 +1212,6 @@ namespace ts.Completions {
1126
1212
return undefined ;
1127
1213
}
1128
1214
1129
- function isFunction ( kind : SyntaxKind ) : boolean {
1130
- if ( ! isFunctionLikeKind ( kind ) ) {
1131
- return false ;
1132
- }
1133
-
1134
- switch ( kind ) {
1135
- case SyntaxKind . Constructor :
1136
- case SyntaxKind . ConstructorType :
1137
- case SyntaxKind . FunctionType :
1138
- return false ;
1139
- default :
1140
- return true ;
1141
- }
1142
- }
1143
-
1144
1215
/**
1145
1216
* @returns true if we are certain that the currently edited location must define a new location; false otherwise.
1146
1217
*/
@@ -1152,7 +1223,7 @@ namespace ts.Completions {
1152
1223
containingNodeKind === SyntaxKind . VariableDeclarationList ||
1153
1224
containingNodeKind === SyntaxKind . VariableStatement ||
1154
1225
containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { foo, |
1155
- isFunction ( containingNodeKind ) ||
1226
+ isFunctionLikeButNotConstructor ( containingNodeKind ) ||
1156
1227
containingNodeKind === SyntaxKind . ClassDeclaration || // class A<T, |
1157
1228
containingNodeKind === SyntaxKind . ClassExpression || // var C = class D<T, |
1158
1229
containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A<T, |
@@ -1170,7 +1241,7 @@ namespace ts.Completions {
1170
1241
1171
1242
case SyntaxKind . OpenParenToken :
1172
1243
return containingNodeKind === SyntaxKind . CatchClause ||
1173
- isFunction ( containingNodeKind ) ;
1244
+ isFunctionLikeButNotConstructor ( containingNodeKind ) ;
1174
1245
1175
1246
case SyntaxKind . OpenBraceToken :
1176
1247
return containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { |
@@ -1188,7 +1259,7 @@ namespace ts.Completions {
1188
1259
containingNodeKind === SyntaxKind . ClassExpression || // var C = class D< |
1189
1260
containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A< |
1190
1261
containingNodeKind === SyntaxKind . TypeAliasDeclaration || // type List< |
1191
- isFunction ( containingNodeKind ) ;
1262
+ isFunctionLikeKind ( containingNodeKind ) ;
1192
1263
1193
1264
case SyntaxKind . StaticKeyword :
1194
1265
return containingNodeKind === SyntaxKind . PropertyDeclaration && ! isClassLike ( contextToken . parent . parent ) ;
@@ -1257,6 +1328,10 @@ namespace ts.Completions {
1257
1328
return false ;
1258
1329
}
1259
1330
1331
+ function isFunctionLikeButNotConstructor ( kind : SyntaxKind ) {
1332
+ return isFunctionLikeKind ( kind ) && kind !== SyntaxKind . Constructor ;
1333
+ }
1334
+
1260
1335
function isDotOfNumericLiteral ( contextToken : Node ) : boolean {
1261
1336
if ( contextToken . kind === SyntaxKind . NumericLiteral ) {
1262
1337
const text = contextToken . getFullText ( ) ;
0 commit comments