@@ -61,7 +61,7 @@ namespace ts.Completions {
6161 }
6262 else {
6363 if ( ( ! symbols || symbols . length === 0 ) && keywordFilters === KeywordCompletionFilters . None ) {
64- return undefined ;
64+ return undefined ;
6565 }
6666
6767 getCompletionEntriesFromSymbols ( symbols , entries , location , /*performCharacterChecks*/ true , typeChecker , compilerOptions . target , log ) ;
@@ -112,7 +112,7 @@ namespace ts.Completions {
112112 // Try to get a valid display name for this symbol, if we could not find one, then ignore it.
113113 // We would like to only show things that can be added after a dot, so for instance numeric properties can
114114 // not be accessed with a dot (a.1 <- invalid)
115- const displayName = getCompletionEntryDisplayNameForSymbol ( typeChecker , symbol , target , performCharacterChecks , location ) ;
115+ const displayName = getCompletionEntryDisplayNameForSymbol ( symbol , target , performCharacterChecks ) ;
116116 if ( ! displayName ) {
117117 return undefined ;
118118 }
@@ -307,7 +307,7 @@ namespace ts.Completions {
307307 // We don't need to perform character checks here because we're only comparing the
308308 // name against 'entryName' (which is known to be good), not building a new
309309 // completion entry.
310- const symbol = forEach ( symbols , s => getCompletionEntryDisplayNameForSymbol ( typeChecker , s , compilerOptions . target , /*performCharacterChecks*/ false , location ) === entryName ? s : undefined ) ;
310+ const symbol = forEach ( symbols , s => getCompletionEntryDisplayNameForSymbol ( s , compilerOptions . target , /*performCharacterChecks*/ false ) === entryName ? s : undefined ) ;
311311
312312 if ( symbol ) {
313313 const { displayParts, documentation, symbolKind, tags } = SymbolDisplay . getSymbolDisplayPartsDocumentationAndSymbolKind ( typeChecker , symbol , sourceFile , location , location , SemanticMeaning . All ) ;
@@ -341,20 +341,14 @@ namespace ts.Completions {
341341 return undefined ;
342342 }
343343
344- export function getCompletionEntrySymbol ( typeChecker : TypeChecker , log : ( message : string ) => void , compilerOptions : CompilerOptions , sourceFile : SourceFile , position : number , entryName : string ) : Symbol {
344+ export function getCompletionEntrySymbol ( typeChecker : TypeChecker , log : ( message : string ) => void , compilerOptions : CompilerOptions , sourceFile : SourceFile , position : number , entryName : string ) : Symbol | undefined {
345345 // Compute all the completion symbols again.
346346 const completionData = getCompletionData ( typeChecker , log , sourceFile , position ) ;
347- if ( completionData ) {
348- const { symbols, location } = completionData ;
349-
350- // Find the symbol with the matching entry name.
351- // We don't need to perform character checks here because we're only comparing the
352- // name against 'entryName' (which is known to be good), not building a new
353- // completion entry.
354- return forEach ( symbols , s => getCompletionEntryDisplayNameForSymbol ( typeChecker , s , compilerOptions . target , /*performCharacterChecks*/ false , location ) === entryName ? s : undefined ) ;
355- }
356-
357- return undefined ;
347+ // Find the symbol with the matching entry name.
348+ // We don't need to perform character checks here because we're only comparing the
349+ // name against 'entryName' (which is known to be good), not building a new
350+ // completion entry.
351+ return completionData && forEach ( completionData . symbols , s => getCompletionEntryDisplayNameForSymbol ( s , compilerOptions . target , /*performCharacterChecks*/ false ) === entryName ? s : undefined ) ;
358352 }
359353
360354 interface CompletionData {
@@ -369,7 +363,7 @@ namespace ts.Completions {
369363 }
370364 type Request = { kind : "JsDocTagName" } | { kind : "JsDocTag" } | { kind : "JsDocParameterName" , tag : JSDocParameterTag } ;
371365
372- function getCompletionData ( typeChecker : TypeChecker , log : ( message : string ) => void , sourceFile : SourceFile , position : number ) : CompletionData {
366+ function getCompletionData ( typeChecker : TypeChecker , log : ( message : string ) => void , sourceFile : SourceFile , position : number ) : CompletionData | undefined {
373367 const isJavaScriptFile = isSourceFileJavaScript ( sourceFile ) ;
374368
375369 let request : Request | undefined ;
@@ -615,7 +609,7 @@ namespace ts.Completions {
615609 // Extract module or enum members
616610 const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
617611 const isValidValueAccess = ( symbol : Symbol ) => typeChecker . isValidPropertyAccess ( < PropertyAccessExpression > ( node . parent ) , symbol . getUnescapedName ( ) ) ;
618- const isValidTypeAccess = ( symbol : Symbol ) => symbolCanbeReferencedAtTypeLocation ( symbol ) ;
612+ const isValidTypeAccess = ( symbol : Symbol ) => symbolCanBeReferencedAtTypeLocation ( symbol ) ;
619613 const isValidAccess = isRhsOfImportDeclaration ?
620614 // Any kind is allowed when dotting off namespace in internal import equals declaration
621615 ( symbol : Symbol ) => isValidTypeAccess ( symbol ) || isValidValueAccess ( symbol ) :
@@ -630,7 +624,7 @@ namespace ts.Completions {
630624
631625 if ( ! isTypeLocation ) {
632626 const type = typeChecker . getTypeAtLocation ( node ) ;
633- addTypeProperties ( type ) ;
627+ if ( type ) addTypeProperties ( type ) ;
634628 }
635629 }
636630
@@ -642,17 +636,17 @@ namespace ts.Completions {
642636 symbols . push ( symbol ) ;
643637 }
644638 }
639+ }
645640
646- if ( isJavaScriptFile && type . flags & TypeFlags . Union ) {
647- // In javascript files, for union types, we don't just get the members that
648- // the individual types have in common, we also include all the members that
649- // each individual type has. This is because we're going to add all identifiers
650- // anyways. So we might as well elevate the members that were at least part
651- // of the individual types to a higher status since we know what they are.
652- const unionType = < UnionType > type ;
653- for ( const elementType of unionType . types ) {
654- addTypeProperties ( elementType ) ;
655- }
641+ if ( isJavaScriptFile && type . flags & TypeFlags . Union ) {
642+ // In javascript files, for union types, we don't just get the members that
643+ // the individual types have in common, we also include all the members that
644+ // each individual type has. This is because we're going to add all identifiers
645+ // anyways. So we might as well elevate the members that were at least part
646+ // of the individual types to a higher status since we know what they are.
647+ const unionType = < UnionType > type ;
648+ for ( const elementType of unionType . types ) {
649+ addTypeProperties ( elementType ) ;
656650 }
657651 }
658652 }
@@ -777,12 +771,12 @@ namespace ts.Completions {
777771 ( ! isContextTokenValueLocation ( contextToken ) &&
778772 ( isPartOfTypeNode ( location ) || isContextTokenTypeLocation ( contextToken ) ) ) ) {
779773 // Its a type, but you can reach it by namespace.type as well
780- return symbolCanbeReferencedAtTypeLocation ( symbol ) ;
774+ return symbolCanBeReferencedAtTypeLocation ( symbol ) ;
781775 }
782776 }
783777
784778 // expressions are value space (which includes the value namespaces)
785- return ! ! ( symbol . flags & SymbolFlags . Value ) ;
779+ return ! ! ( getCombinedLocalAndExportSymbolFlags ( symbol ) & SymbolFlags . Value ) ;
786780 } ) ;
787781 }
788782
@@ -812,7 +806,9 @@ namespace ts.Completions {
812806 }
813807 }
814808
815- function symbolCanbeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
809+ function symbolCanBeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
810+ symbol = symbol . exportSymbol || symbol ;
811+
816812 // This is an alias, follow what it aliases
817813 if ( symbol && symbol . flags & SymbolFlags . Alias ) {
818814 symbol = typeChecker . getAliasedSymbol ( symbol ) ;
@@ -826,7 +822,7 @@ namespace ts.Completions {
826822 const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
827823 // If the exported symbols contains type,
828824 // symbol can be referenced at locations where type is allowed
829- return forEach ( exportedSymbols , symbolCanbeReferencedAtTypeLocation ) ;
825+ return forEach ( exportedSymbols , symbolCanBeReferencedAtTypeLocation ) ;
830826 }
831827 }
832828
@@ -1598,47 +1594,36 @@ namespace ts.Completions {
15981594 /**
15991595 * Get the name to be display in completion from a given symbol.
16001596 *
1601- * @return undefined if the name is of external module otherwise a name with striped of any quote
1597+ * @return undefined if the name is of external module
16021598 */
1603- function getCompletionEntryDisplayNameForSymbol ( typeChecker : TypeChecker , symbol : Symbol , target : ScriptTarget , performCharacterChecks : boolean , location : Node ) : string {
1604- const displayName : string = getDeclaredName ( typeChecker , symbol , location ) ;
1605-
1606- if ( displayName ) {
1607- const firstCharCode = displayName . charCodeAt ( 0 ) ;
1608- // First check of the displayName is not external module; if it is an external module, it is not valid entry
1609- if ( ( symbol . flags & SymbolFlags . Namespace ) && ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) ) {
1599+ function getCompletionEntryDisplayNameForSymbol ( symbol : Symbol , target : ScriptTarget , performCharacterChecks : boolean ) : string | undefined {
1600+ const name = symbol . getUnescapedName ( ) ;
1601+ if ( ! name ) return undefined ;
1602+
1603+ // First check of the displayName is not external module; if it is an external module, it is not valid entry
1604+ if ( symbol . flags & SymbolFlags . Namespace ) {
1605+ const firstCharCode = name . charCodeAt ( 0 ) ;
1606+ if ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) {
16101607 // If the symbol is external module, don't show it in the completion list
16111608 // (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there)
16121609 return undefined ;
16131610 }
16141611 }
16151612
1616- return getCompletionEntryDisplayName ( displayName , target , performCharacterChecks ) ;
1613+ return getCompletionEntryDisplayName ( name , target , performCharacterChecks ) ;
16171614 }
16181615
16191616 /**
16201617 * Get a displayName from a given for completion list, performing any necessary quotes stripping
16211618 * and checking whether the name is valid identifier name.
16221619 */
16231620 function getCompletionEntryDisplayName ( name : string , target : ScriptTarget , performCharacterChecks : boolean ) : string {
1624- if ( ! name ) {
1625- return undefined ;
1626- }
1627-
1628- name = stripQuotes ( name ) ;
1629-
1630- if ( ! name ) {
1631- return undefined ;
1632- }
1633-
16341621 // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
16351622 // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
16361623 // e.g "b a" is valid quoted name but when we strip off the quotes, it is invalid.
16371624 // We, thus, need to check if whatever was inside the quotes is actually a valid identifier name.
1638- if ( performCharacterChecks ) {
1639- if ( ! isIdentifierText ( name , target ) ) {
1640- return undefined ;
1641- }
1625+ if ( performCharacterChecks && ! isIdentifierText ( name , target ) ) {
1626+ return undefined ;
16421627 }
16431628
16441629 return name ;
0 commit comments