@@ -61,7 +61,7 @@ namespace ts.Completions {
61
61
}
62
62
else {
63
63
if ( ( ! symbols || symbols . length === 0 ) && keywordFilters === KeywordCompletionFilters . None ) {
64
- return undefined ;
64
+ return undefined ;
65
65
}
66
66
67
67
getCompletionEntriesFromSymbols ( symbols , entries , location , /*performCharacterChecks*/ true , typeChecker , compilerOptions . target , log ) ;
@@ -112,7 +112,7 @@ namespace ts.Completions {
112
112
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
113
113
// We would like to only show things that can be added after a dot, so for instance numeric properties can
114
114
// 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 ) ;
116
116
if ( ! displayName ) {
117
117
return undefined ;
118
118
}
@@ -307,7 +307,7 @@ namespace ts.Completions {
307
307
// We don't need to perform character checks here because we're only comparing the
308
308
// name against 'entryName' (which is known to be good), not building a new
309
309
// 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 ) ;
311
311
312
312
if ( symbol ) {
313
313
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay . getSymbolDisplayPartsDocumentationAndSymbolKind ( typeChecker , symbol , sourceFile , location , location , SemanticMeaning . All ) ;
@@ -341,20 +341,14 @@ namespace ts.Completions {
341
341
return undefined ;
342
342
}
343
343
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 {
345
345
// Compute all the completion symbols again.
346
346
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 ) ;
358
352
}
359
353
360
354
interface CompletionData {
@@ -369,7 +363,7 @@ namespace ts.Completions {
369
363
}
370
364
type Request = { kind : "JsDocTagName" } | { kind : "JsDocTag" } | { kind : "JsDocParameterName" , tag : JSDocParameterTag } ;
371
365
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 {
373
367
const isJavaScriptFile = isSourceFileJavaScript ( sourceFile ) ;
374
368
375
369
let request : Request | undefined ;
@@ -615,7 +609,7 @@ namespace ts.Completions {
615
609
// Extract module or enum members
616
610
const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
617
611
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 ) ;
619
613
const isValidAccess = isRhsOfImportDeclaration ?
620
614
// Any kind is allowed when dotting off namespace in internal import equals declaration
621
615
( symbol : Symbol ) => isValidTypeAccess ( symbol ) || isValidValueAccess ( symbol ) :
@@ -630,7 +624,7 @@ namespace ts.Completions {
630
624
631
625
if ( ! isTypeLocation ) {
632
626
const type = typeChecker . getTypeAtLocation ( node ) ;
633
- addTypeProperties ( type ) ;
627
+ if ( type ) addTypeProperties ( type ) ;
634
628
}
635
629
}
636
630
@@ -642,17 +636,17 @@ namespace ts.Completions {
642
636
symbols . push ( symbol ) ;
643
637
}
644
638
}
639
+ }
645
640
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 ) ;
656
650
}
657
651
}
658
652
}
@@ -777,12 +771,12 @@ namespace ts.Completions {
777
771
( ! isContextTokenValueLocation ( contextToken ) &&
778
772
( isPartOfTypeNode ( location ) || isContextTokenTypeLocation ( contextToken ) ) ) ) {
779
773
// Its a type, but you can reach it by namespace.type as well
780
- return symbolCanbeReferencedAtTypeLocation ( symbol ) ;
774
+ return symbolCanBeReferencedAtTypeLocation ( symbol ) ;
781
775
}
782
776
}
783
777
784
778
// expressions are value space (which includes the value namespaces)
785
- return ! ! ( symbol . flags & SymbolFlags . Value ) ;
779
+ return ! ! ( getCombinedLocalAndExportSymbolFlags ( symbol ) & SymbolFlags . Value ) ;
786
780
} ) ;
787
781
}
788
782
@@ -812,7 +806,9 @@ namespace ts.Completions {
812
806
}
813
807
}
814
808
815
- function symbolCanbeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
809
+ function symbolCanBeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
810
+ symbol = symbol . exportSymbol || symbol ;
811
+
816
812
// This is an alias, follow what it aliases
817
813
if ( symbol && symbol . flags & SymbolFlags . Alias ) {
818
814
symbol = typeChecker . getAliasedSymbol ( symbol ) ;
@@ -826,7 +822,7 @@ namespace ts.Completions {
826
822
const exportedSymbols = typeChecker . getExportsOfModule ( symbol ) ;
827
823
// If the exported symbols contains type,
828
824
// symbol can be referenced at locations where type is allowed
829
- return forEach ( exportedSymbols , symbolCanbeReferencedAtTypeLocation ) ;
825
+ return forEach ( exportedSymbols , symbolCanBeReferencedAtTypeLocation ) ;
830
826
}
831
827
}
832
828
@@ -1598,47 +1594,36 @@ namespace ts.Completions {
1598
1594
/**
1599
1595
* Get the name to be display in completion from a given symbol.
1600
1596
*
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
1602
1598
*/
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 ) {
1610
1607
// If the symbol is external module, don't show it in the completion list
1611
1608
// (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there)
1612
1609
return undefined ;
1613
1610
}
1614
1611
}
1615
1612
1616
- return getCompletionEntryDisplayName ( displayName , target , performCharacterChecks ) ;
1613
+ return getCompletionEntryDisplayName ( name , target , performCharacterChecks ) ;
1617
1614
}
1618
1615
1619
1616
/**
1620
1617
* Get a displayName from a given for completion list, performing any necessary quotes stripping
1621
1618
* and checking whether the name is valid identifier name.
1622
1619
*/
1623
1620
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
-
1634
1621
// If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
1635
1622
// invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
1636
1623
// e.g "b a" is valid quoted name but when we strip off the quotes, it is invalid.
1637
1624
// 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 ;
1642
1627
}
1643
1628
1644
1629
return name ;
0 commit comments