@@ -2398,42 +2398,51 @@ module ts {
23982398 }
23992399
24002400 /// Completion
2401- function getValidCompletionEntryDisplayName ( symbol : Symbol , target : ScriptTarget ) : string {
2401+ function getCompletionEntryDisplayName ( symbol : Symbol , target : ScriptTarget , performCharacterChecks : boolean ) : string {
24022402 let displayName = symbol . getName ( ) ;
2403- if ( displayName && displayName . length > 0 ) {
2404- let firstCharCode = displayName . charCodeAt ( 0 ) ;
2405- // First check of the displayName is not external module; if it is an external module, it is not valid entry
2406- if ( ( symbol . flags & SymbolFlags . Namespace ) && ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) ) {
2407- // If the symbol is external module, don't show it in the completion list
2408- // (i.e declare module "http" { let x; } | // <= request completion here, "http" should not be there)
2409- return undefined ;
2410- }
2403+ if ( ! displayName ) {
2404+ return undefined ;
2405+ }
24112406
2412- if ( displayName && displayName . length >= 2 && firstCharCode === displayName . charCodeAt ( displayName . length - 1 ) &&
2413- ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) ) {
2414- // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
2415- // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
2416- displayName = displayName . substring ( 1 , displayName . length - 1 ) ;
2417- }
2407+ let firstCharCode = displayName . charCodeAt ( 0 ) ;
2408+ // First check of the displayName is not external module; if it is an external module, it is not valid entry
2409+ if ( ( symbol . flags & SymbolFlags . Namespace ) && ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) ) {
2410+ // If the symbol is external module, don't show it in the completion list
2411+ // (i.e declare module "http" { let x; } | // <= request completion here, "http" should not be there)
2412+ return undefined ;
2413+ }
24182414
2419- let isValid = isIdentifierStart ( displayName . charCodeAt ( 0 ) , target ) ;
2420- for ( let i = 1 , n = displayName . length ; isValid && i < n ; i ++ ) {
2421- isValid = isIdentifierPart ( displayName . charCodeAt ( i ) , target ) ;
2415+ if ( displayName && displayName . length >= 2 && firstCharCode === displayName . charCodeAt ( displayName . length - 1 ) &&
2416+ ( firstCharCode === CharacterCodes . singleQuote || firstCharCode === CharacterCodes . doubleQuote ) ) {
2417+ // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
2418+ // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
2419+ displayName = displayName . substring ( 1 , displayName . length - 1 ) ;
2420+ }
2421+
2422+ if ( ! displayName ) {
2423+ return undefined ;
2424+ }
2425+
2426+ if ( performCharacterChecks ) {
2427+ if ( ! isIdentifierStart ( displayName . charCodeAt ( 0 ) , target ) ) {
2428+ return undefined ;
24222429 }
24232430
2424- if ( isValid ) {
2425- return unescapeIdentifier ( displayName ) ;
2431+ for ( let i = 1 , n = displayName . length ; i < n ; i ++ ) {
2432+ if ( ! isIdentifierPart ( displayName . charCodeAt ( i ) , target ) ) {
2433+ return undefined ;
2434+ }
24262435 }
24272436 }
24282437
2429- return undefined ;
2438+ return unescapeIdentifier ( displayName ) ;
24302439 }
24312440
24322441 function createCompletionEntry ( symbol : Symbol , typeChecker : TypeChecker , location : Node ) : CompletionEntry {
24332442 // Try to get a valid display name for this symbol, if we could not find one, then ignore it.
24342443 // We would like to only show things that can be added after a dot, so for instance numeric properties can
24352444 // not be accessed with a dot (a.1 <- invalid)
2436- let displayName = getValidCompletionEntryDisplayName ( symbol , program . getCompilerOptions ( ) . target ) ;
2445+ let displayName = getCompletionEntryDisplayName ( symbol , program . getCompilerOptions ( ) . target , /*performCharacterChecks:*/ true ) ;
24372446 if ( ! displayName ) {
24382447 return undefined ;
24392448 }
@@ -2449,26 +2458,7 @@ module ts {
24492458 } ;
24502459 }
24512460
2452- // If symbolName is undefined, all symbols at the specified are returned. If symbolName
2453- // is not undefined, then the first symbol with that name at the specified position
2454- // will be returned. Calling without symbolName is useful when you want the entire
2455- // list of symbols (like for getCompletionsAtPosition). Calling with a symbolName is
2456- // useful when you want information about a single symbol (like for getCompletionEntryDetails).
2457- function getCompletionData ( fileName : string , position : number , symbolName ?: string ) {
2458- let result = getCompletionDataWorker ( fileName , position , symbolName ) ;
2459- if ( ! result ) {
2460- return undefined ;
2461- }
2462-
2463- if ( result . symbols && symbolName ) {
2464- var target = program . getCompilerOptions ( ) . target ;
2465- result . symbols = filter ( result . symbols , s => getValidCompletionEntryDisplayName ( s , target ) === symbolName ) ;
2466- }
2467-
2468- return result ;
2469- }
2470-
2471- function getCompletionDataWorker ( fileName : string , position : number , symbolName : string ) {
2461+ function getCompletionData ( fileName : string , position : number ) {
24722462 let syntacticStart = new Date ( ) . getTime ( ) ;
24732463 let sourceFile = getValidSourceFile ( fileName ) ;
24742464
@@ -2600,11 +2590,7 @@ module ts {
26002590 let scopeNode = getScopeNode ( previousToken , position , sourceFile ) ;
26012591 let symbolMeanings = SymbolFlags . Type | SymbolFlags . Value | SymbolFlags . Namespace | SymbolFlags . Alias ;
26022592
2603- // Filter down to the symbol that matches the symbolName if we were given one.
2604- let predicate = symbolName !== undefined
2605- ? ( s : Symbol ) => getValidCompletionEntryDisplayName ( s , target ) === symbolName
2606- : undefined ;
2607- symbols = typeInfoResolver . getSymbolsInScope ( scopeNode , symbolMeanings , predicate ) ;
2593+ symbols = typeInfoResolver . getSymbolsInScope ( scopeNode , symbolMeanings ) ;
26082594 }
26092595 }
26102596
@@ -2955,12 +2941,16 @@ module ts {
29552941 function getCompletionEntryDetails ( fileName : string , position : number , entryName : string ) : CompletionEntryDetails {
29562942 synchronizeHostData ( ) ;
29572943
2958- // Look up a completion symbol with this name .
2959- let completionData = getCompletionData ( fileName , position , entryName ) ;
2944+ // Compute all the completion symbols again .
2945+ let completionData = getCompletionData ( fileName , position ) ;
29602946 if ( completionData ) {
29612947 let { symbols, location } = completionData ;
2962- if ( symbols && symbols . length > 0 ) {
2963- let symbol = symbols [ 0 ] ;
2948+
2949+ // Find the symbol with the matching entry name.
2950+ let target = program . getCompilerOptions ( ) . target ;
2951+ let symbol = forEach ( symbols , s => getCompletionEntryDisplayName ( s , target , /*performCharacterChecks:*/ false ) === entryName ? s : undefined ) ;
2952+
2953+ if ( symbol ) {
29642954 let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind ( symbol , getValidSourceFile ( fileName ) , location , typeInfoResolver , location , SemanticMeaning . All ) ;
29652955 return {
29662956 name : entryName ,
0 commit comments