@@ -578,6 +578,9 @@ namespace ts.Completions {
578
578
isMemberCompletion = true ;
579
579
isNewIdentifierLocation = false ;
580
580
581
+ // Since this is qualified name check its a type node location
582
+ const isTypeLocation = isPartOfTypeNode ( node . parent ) ;
583
+ const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration ( node ) ;
581
584
if ( node . kind === SyntaxKind . Identifier || node . kind === SyntaxKind . QualifiedName || node . kind === SyntaxKind . PropertyAccessExpression ) {
582
585
let symbol = typeChecker . getSymbolAtLocation ( node ) ;
583
586
@@ -589,16 +592,24 @@ namespace ts.Completions {
589
592
if ( symbol && symbol . flags & SymbolFlags . HasExports ) {
590
593
// Extract module or enum members
591
594
const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
595
+ const isValidValueAccess = ( symbol : Symbol ) => typeChecker . isValidPropertyAccess ( < PropertyAccessExpression > ( node . parent ) , symbol . name ) ;
596
+ const isValidTypeAccess = ( symbol : Symbol ) => symbolCanbeReferencedAtTypeLocation ( symbol ) ;
597
+ const isValidAccess = isRhsOfImportDeclaration ?
598
+ // Any kind is allowed when dotting off namespace in internal import equals declaration
599
+ ( symbol : Symbol ) => isValidTypeAccess ( symbol ) || isValidValueAccess ( symbol ) :
600
+ isTypeLocation ? isValidTypeAccess : isValidValueAccess ;
592
601
forEach ( exportedSymbols , symbol => {
593
- if ( typeChecker . isValidPropertyAccess ( < PropertyAccessExpression > ( node . parent ) , symbol . name ) ) {
602
+ if ( isValidAccess ( symbol ) ) {
594
603
symbols . push ( symbol ) ;
595
604
}
596
605
} ) ;
597
606
}
598
607
}
599
608
600
- const type = typeChecker . getTypeAtLocation ( node ) ;
601
- addTypeProperties ( type ) ;
609
+ if ( ! isTypeLocation ) {
610
+ const type = typeChecker . getTypeAtLocation ( node ) ;
611
+ addTypeProperties ( type ) ;
612
+ }
602
613
}
603
614
604
615
function addTypeProperties ( type : Type ) {
@@ -706,13 +717,88 @@ namespace ts.Completions {
706
717
isStatement ( scopeNode ) ;
707
718
}
708
719
709
- /// TODO filter meaning based on the current context
710
720
const symbolMeanings = SymbolFlags . Type | SymbolFlags . Value | SymbolFlags . Namespace | SymbolFlags . Alias ;
711
- symbols = typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ;
721
+ symbols = filterGlobalCompletion ( typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ) ;
712
722
713
723
return true ;
714
724
}
715
725
726
+ function filterGlobalCompletion ( symbols : Symbol [ ] ) {
727
+ return filter ( symbols , symbol => {
728
+ if ( ! isSourceFile ( location ) ) {
729
+ // export = /**/ here we want to get all meanings, so any symbol is ok
730
+ if ( isExportAssignment ( location . parent ) ) {
731
+ return true ;
732
+ }
733
+
734
+ // This is an alias, follow what it aliases
735
+ if ( symbol && symbol . flags & SymbolFlags . Alias ) {
736
+ symbol = typeChecker . getAliasedSymbol ( symbol ) ;
737
+ }
738
+
739
+ // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
740
+ if ( isInRightSideOfInternalImportEqualsDeclaration ( location ) ) {
741
+ return ! ! ( symbol . flags & SymbolFlags . Namespace ) ;
742
+ }
743
+
744
+ if ( ! isContextTokenValueLocation ( contextToken ) &&
745
+ ( isPartOfTypeNode ( location ) || isContextTokenTypeLocation ( contextToken ) ) ) {
746
+ // Its a type, but you can reach it by namespace.type as well
747
+ return symbolCanbeReferencedAtTypeLocation ( symbol ) ;
748
+ }
749
+ }
750
+
751
+ // expressions are value space (which includes the value namespaces)
752
+ return ! ! ( symbol . flags & SymbolFlags . Value ) ;
753
+ } ) ;
754
+ }
755
+
756
+ function isContextTokenValueLocation ( contextToken : Node ) {
757
+ if ( contextToken ) {
758
+ const parentKind = contextToken . parent . kind ;
759
+ switch ( contextToken . kind ) {
760
+ case SyntaxKind . TypeOfKeyword :
761
+ return parentKind === SyntaxKind . TypeQuery ;
762
+ }
763
+ }
764
+ }
765
+
766
+ function isContextTokenTypeLocation ( contextToken : Node ) {
767
+ if ( contextToken ) {
768
+ const parentKind = contextToken . parent . kind ;
769
+ switch ( contextToken . kind ) {
770
+ case SyntaxKind . ColonToken :
771
+ return parentKind === SyntaxKind . PropertyDeclaration ||
772
+ parentKind === SyntaxKind . PropertySignature ||
773
+ parentKind === SyntaxKind . Parameter ||
774
+ parentKind === SyntaxKind . VariableDeclaration ||
775
+ isFunctionLikeKind ( parentKind ) ;
776
+
777
+ case SyntaxKind . EqualsToken :
778
+ return parentKind === SyntaxKind . TypeAliasDeclaration ;
779
+
780
+ case SyntaxKind . AsKeyword :
781
+ return parentKind === SyntaxKind . AsExpression ;
782
+ }
783
+ }
784
+ }
785
+
786
+ function symbolCanbeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
787
+ // This is an alias, follow what it aliases
788
+ if ( symbol && symbol . flags & SymbolFlags . Alias ) {
789
+ symbol = typeChecker . getAliasedSymbol ( symbol ) ;
790
+ }
791
+
792
+ if ( symbol . flags & ( SymbolFlags . ValueModule | SymbolFlags . NamespaceModule ) ) {
793
+ const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
794
+ // If the exported symbols contains type,
795
+ // symbol can be referenced at locations where type is allowed
796
+ return forEach ( exportedSymbols , symbolCanbeReferencedAtTypeLocation ) ;
797
+ }
798
+
799
+ return ! ! ( symbol . flags & ( SymbolFlags . NamespaceModule | SymbolFlags . Type ) ) ;
800
+ }
801
+
716
802
/**
717
803
* Finds the first node that "embraces" the position, so that one may
718
804
* accurately aggregate locals from the closest containing scope.
@@ -1140,21 +1226,6 @@ namespace ts.Completions {
1140
1226
return undefined ;
1141
1227
}
1142
1228
1143
- function isFunction ( kind : SyntaxKind ) : boolean {
1144
- if ( ! isFunctionLikeKind ( kind ) ) {
1145
- return false ;
1146
- }
1147
-
1148
- switch ( kind ) {
1149
- case SyntaxKind . Constructor :
1150
- case SyntaxKind . ConstructorType :
1151
- case SyntaxKind . FunctionType :
1152
- return false ;
1153
- default :
1154
- return true ;
1155
- }
1156
- }
1157
-
1158
1229
/**
1159
1230
* @returns true if we are certain that the currently edited location must define a new location; false otherwise.
1160
1231
*/
@@ -1166,7 +1237,7 @@ namespace ts.Completions {
1166
1237
containingNodeKind === SyntaxKind . VariableDeclarationList ||
1167
1238
containingNodeKind === SyntaxKind . VariableStatement ||
1168
1239
containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { foo, |
1169
- isFunction ( containingNodeKind ) ||
1240
+ isFunctionLikeButNotConstructor ( containingNodeKind ) ||
1170
1241
containingNodeKind === SyntaxKind . ClassDeclaration || // class A<T, |
1171
1242
containingNodeKind === SyntaxKind . ClassExpression || // var C = class D<T, |
1172
1243
containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A<T, |
@@ -1184,7 +1255,7 @@ namespace ts.Completions {
1184
1255
1185
1256
case SyntaxKind . OpenParenToken :
1186
1257
return containingNodeKind === SyntaxKind . CatchClause ||
1187
- isFunction ( containingNodeKind ) ;
1258
+ isFunctionLikeButNotConstructor ( containingNodeKind ) ;
1188
1259
1189
1260
case SyntaxKind . OpenBraceToken :
1190
1261
return containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { |
@@ -1202,7 +1273,7 @@ namespace ts.Completions {
1202
1273
containingNodeKind === SyntaxKind . ClassExpression || // var C = class D< |
1203
1274
containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A< |
1204
1275
containingNodeKind === SyntaxKind . TypeAliasDeclaration || // type List< |
1205
- isFunction ( containingNodeKind ) ;
1276
+ isFunctionLikeKind ( containingNodeKind ) ;
1206
1277
1207
1278
case SyntaxKind . StaticKeyword :
1208
1279
return containingNodeKind === SyntaxKind . PropertyDeclaration && ! isClassLike ( contextToken . parent . parent ) ;
@@ -1271,6 +1342,10 @@ namespace ts.Completions {
1271
1342
return false ;
1272
1343
}
1273
1344
1345
+ function isFunctionLikeButNotConstructor ( kind : SyntaxKind ) {
1346
+ return isFunctionLikeKind ( kind ) && kind !== SyntaxKind . Constructor ;
1347
+ }
1348
+
1274
1349
function isDotOfNumericLiteral ( contextToken : Node ) : boolean {
1275
1350
if ( contextToken . kind === SyntaxKind . NumericLiteral ) {
1276
1351
const text = contextToken . getFullText ( ) ;
0 commit comments