@@ -559,6 +559,9 @@ namespace ts.Completions {
559559 isMemberCompletion = true ;
560560 isNewIdentifierLocation = false ;
561561
562+ // Since this is qualified name check its a type node location
563+ const isTypeLocation = isPartOfTypeNode ( node . parent ) ;
564+ const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration ( node ) ;
562565 if ( node . kind === SyntaxKind . Identifier || node . kind === SyntaxKind . QualifiedName || node . kind === SyntaxKind . PropertyAccessExpression ) {
563566 let symbol = typeChecker . getSymbolAtLocation ( node ) ;
564567
@@ -570,16 +573,24 @@ namespace ts.Completions {
570573 if ( symbol && symbol . flags & SymbolFlags . HasExports ) {
571574 // Extract module or enum members
572575 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 ;
573582 forEach ( exportedSymbols , symbol => {
574- if ( typeChecker . isValidPropertyAccess ( < PropertyAccessExpression > ( node . parent ) , symbol . name ) ) {
583+ if ( isValidAccess ( symbol ) ) {
575584 symbols . push ( symbol ) ;
576585 }
577586 } ) ;
578587 }
579588 }
580589
581- const type = typeChecker . getTypeAtLocation ( node ) ;
582- addTypeProperties ( type ) ;
590+ if ( ! isTypeLocation ) {
591+ const type = typeChecker . getTypeAtLocation ( node ) ;
592+ addTypeProperties ( type ) ;
593+ }
583594 }
584595
585596 function addTypeProperties ( type : Type ) {
@@ -687,13 +698,88 @@ namespace ts.Completions {
687698 isStatement ( scopeNode ) ;
688699 }
689700
690- /// TODO filter meaning based on the current context
691701 const symbolMeanings = SymbolFlags . Type | SymbolFlags . Value | SymbolFlags . Namespace | SymbolFlags . Alias ;
692- symbols = typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ;
702+ symbols = filterGlobalCompletion ( typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ) ;
693703
694704 return true ;
695705 }
696706
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+
697783 /**
698784 * Finds the first node that "embraces" the position, so that one may
699785 * accurately aggregate locals from the closest containing scope.
@@ -1126,21 +1212,6 @@ namespace ts.Completions {
11261212 return undefined ;
11271213 }
11281214
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-
11441215 /**
11451216 * @returns true if we are certain that the currently edited location must define a new location; false otherwise.
11461217 */
@@ -1152,7 +1223,7 @@ namespace ts.Completions {
11521223 containingNodeKind === SyntaxKind . VariableDeclarationList ||
11531224 containingNodeKind === SyntaxKind . VariableStatement ||
11541225 containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { foo, |
1155- isFunction ( containingNodeKind ) ||
1226+ isFunctionLikeButNotConstructor ( containingNodeKind ) ||
11561227 containingNodeKind === SyntaxKind . ClassDeclaration || // class A<T, |
11571228 containingNodeKind === SyntaxKind . ClassExpression || // var C = class D<T, |
11581229 containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A<T, |
@@ -1170,7 +1241,7 @@ namespace ts.Completions {
11701241
11711242 case SyntaxKind . OpenParenToken :
11721243 return containingNodeKind === SyntaxKind . CatchClause ||
1173- isFunction ( containingNodeKind ) ;
1244+ isFunctionLikeButNotConstructor ( containingNodeKind ) ;
11741245
11751246 case SyntaxKind . OpenBraceToken :
11761247 return containingNodeKind === SyntaxKind . EnumDeclaration || // enum a { |
@@ -1188,7 +1259,7 @@ namespace ts.Completions {
11881259 containingNodeKind === SyntaxKind . ClassExpression || // var C = class D< |
11891260 containingNodeKind === SyntaxKind . InterfaceDeclaration || // interface A< |
11901261 containingNodeKind === SyntaxKind . TypeAliasDeclaration || // type List< |
1191- isFunction ( containingNodeKind ) ;
1262+ isFunctionLikeKind ( containingNodeKind ) ;
11921263
11931264 case SyntaxKind . StaticKeyword :
11941265 return containingNodeKind === SyntaxKind . PropertyDeclaration && ! isClassLike ( contextToken . parent . parent ) ;
@@ -1257,6 +1328,10 @@ namespace ts.Completions {
12571328 return false ;
12581329 }
12591330
1331+ function isFunctionLikeButNotConstructor ( kind : SyntaxKind ) {
1332+ return isFunctionLikeKind ( kind ) && kind !== SyntaxKind . Constructor ;
1333+ }
1334+
12601335 function isDotOfNumericLiteral ( contextToken : Node ) : boolean {
12611336 if ( contextToken . kind === SyntaxKind . NumericLiteral ) {
12621337 const text = contextToken . getFullText ( ) ;
0 commit comments