Skip to content

Commit 126a46c

Browse files
author
Andy Hanson
committed
getSymbolsInScope() should return local symbols, not exported symbols
1 parent 5a6e240 commit 126a46c

14 files changed

+98
-79
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22226,11 +22226,6 @@ namespace ts {
2222622226
}
2222722227

2222822228
switch (location.kind) {
22229-
case SyntaxKind.SourceFile:
22230-
if (!isExternalOrCommonJsModule(<SourceFile>location)) {
22231-
break;
22232-
}
22233-
// falls through
2223422229
case SyntaxKind.ModuleDeclaration:
2223522230
copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember);
2223622231
break;
@@ -22282,7 +22277,7 @@ namespace ts {
2228222277
* @param meaning meaning of symbol to filter by before adding to symbol table
2228322278
*/
2228422279
function copySymbol(symbol: Symbol, meaning: SymbolFlags): void {
22285-
if (symbol.flags & meaning) {
22280+
if (getCombinedLocalAndExportSymbolFlags(symbol) & meaning) {
2228622281
const id = symbol.name;
2228722282
// We will copy all symbol regardless of its reserved name because
2228822283
// symbolsToArray will check whether the key is a reserved name and

src/compiler/utilities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3549,6 +3549,11 @@ namespace ts {
35493549
}
35503550
return previous[previous.length - 1];
35513551
}
3552+
3553+
/** See comment on `declareModuleMember` in `binder.ts`. */
3554+
export function getCombinedLocalAndExportSymbolFlags(symbol: Symbol): SymbolFlags {
3555+
return symbol.exportSymbol ? symbol.exportSymbol.flags | symbol.flags : symbol.flags;
3556+
}
35523557
}
35533558

35543559
namespace ts {

src/services/completions.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ namespace ts.Completions {
9191

9292
if (!uniqueNames.get(name)) {
9393
uniqueNames.set(name, name);
94-
const displayName = getCompletionEntryDisplayName(unescapeIdentifier(name), target, /*performCharacterChecks*/ true);
94+
const displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks*/ true);
9595
if (displayName) {
9696
const entry = {
9797
name: displayName,
@@ -608,7 +608,7 @@ namespace ts.Completions {
608608
// Extract module or enum members
609609
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
610610
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name);
611-
const isValidTypeAccess = (symbol: Symbol) => symbolCanbeReferencedAtTypeLocation(symbol);
611+
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
612612
const isValidAccess = isRhsOfImportDeclaration ?
613613
// Any kind is allowed when dotting off namespace in internal import equals declaration
614614
(symbol: Symbol) => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
@@ -768,12 +768,12 @@ namespace ts.Completions {
768768
(!isContextTokenValueLocation(contextToken) &&
769769
(isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken)))) {
770770
// Its a type, but you can reach it by namespace.type as well
771-
return symbolCanbeReferencedAtTypeLocation(symbol);
771+
return symbolCanBeReferencedAtTypeLocation(symbol);
772772
}
773773
}
774774

775775
// expressions are value space (which includes the value namespaces)
776-
return !!(symbol.flags & SymbolFlags.Value);
776+
return !!(getCombinedLocalAndExportSymbolFlags(symbol) & SymbolFlags.Value);
777777
});
778778
}
779779

@@ -803,7 +803,9 @@ namespace ts.Completions {
803803
}
804804
}
805805

806-
function symbolCanbeReferencedAtTypeLocation(symbol: Symbol): boolean {
806+
function symbolCanBeReferencedAtTypeLocation(symbol: Symbol): boolean {
807+
symbol = symbol.exportSymbol || symbol;
808+
807809
// This is an alias, follow what it aliases
808810
if (symbol && symbol.flags & SymbolFlags.Alias) {
809811
symbol = typeChecker.getAliasedSymbol(symbol);
@@ -817,7 +819,7 @@ namespace ts.Completions {
817819
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
818820
// If the exported symbols contains type,
819821
// symbol can be referenced at locations where type is allowed
820-
return forEach(exportedSymbols, symbolCanbeReferencedAtTypeLocation);
822+
return forEach(exportedSymbols, symbolCanBeReferencedAtTypeLocation);
821823
}
822824
}
823825

@@ -1588,21 +1590,23 @@ namespace ts.Completions {
15881590
/**
15891591
* Get the name to be display in completion from a given symbol.
15901592
*
1591-
* @return undefined if the name is of external module otherwise a name with striped of any quote
1593+
* @return undefined if the name is of external module
15921594
*/
1593-
function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string {
1594-
const displayName = symbol.name;
1595-
if (!displayName) return undefined;
1595+
function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string | undefined {
1596+
const name = symbol.name;
1597+
if (!name) return undefined;
15961598

1597-
const firstCharCode = displayName.charCodeAt(0);
15981599
// First check of the displayName is not external module; if it is an external module, it is not valid entry
1599-
if ((symbol.flags & SymbolFlags.Namespace) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
1600-
// If the symbol is external module, don't show it in the completion list
1601-
// (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there)
1602-
return undefined;
1600+
if (symbol.flags & SymbolFlags.Namespace) {
1601+
const firstCharCode = name.charCodeAt(0);
1602+
if (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote) {
1603+
// If the symbol is external module, don't show it in the completion list
1604+
// (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there)
1605+
return undefined;
1606+
}
16031607
}
16041608

1605-
return getCompletionEntryDisplayName(displayName, target, performCharacterChecks);
1609+
return getCompletionEntryDisplayName(name, target, performCharacterChecks);
16061610
}
16071611

16081612
/**
@@ -1618,7 +1622,7 @@ namespace ts.Completions {
16181622
return undefined;
16191623
}
16201624

1621-
return name;
1625+
return unescapeIdentifier(name);
16221626
}
16231627

16241628
// A cache of completion entries for keywords, these do not change between sessions

src/services/symbolDisplay.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
namespace ts.SymbolDisplay {
33
// TODO(drosen): use contextual SemanticMeaning.
44
export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind {
5-
const { flags } = symbol;
5+
const flags = getCombinedLocalAndExportSymbolFlags(symbol);
66

77
if (flags & SymbolFlags.Class) {
88
return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ?
@@ -34,7 +34,7 @@ namespace ts.SymbolDisplay {
3434
if (location.kind === SyntaxKind.ThisKeyword && isExpression(location)) {
3535
return ScriptElementKind.parameterElement;
3636
}
37-
const { flags } = symbol;
37+
const flags = getCombinedLocalAndExportSymbolFlags(symbol);
3838
if (flags & SymbolFlags.Variable) {
3939
if (isFirstDeclarationOfSymbolParameter(symbol)) {
4040
return ScriptElementKind.parameterElement;
@@ -96,7 +96,7 @@ namespace ts.SymbolDisplay {
9696
const displayParts: SymbolDisplayPart[] = [];
9797
let documentation: SymbolDisplayPart[];
9898
let tags: JSDocTagInfo[];
99-
const symbolFlags = symbol.flags;
99+
const symbolFlags = ts.getCombinedLocalAndExportSymbolFlags(symbol);
100100
let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location);
101101
let hasAddedSymbolInfo: boolean;
102102
const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isExpression(location);
@@ -110,7 +110,7 @@ namespace ts.SymbolDisplay {
110110
}
111111

112112
let signature: Signature;
113-
type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol, location);
113+
type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol.exportSymbol || symbol, location);
114114
if (type) {
115115
if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) {
116116
const right = (<PropertyAccessExpression>location.parent).name;
@@ -198,7 +198,7 @@ namespace ts.SymbolDisplay {
198198
hasAddedSymbolInfo = true;
199199
}
200200
}
201-
else if ((isNameOfFunctionDeclaration(location) && !(symbol.flags & SymbolFlags.Accessor)) || // name of function declaration
201+
else if ((isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) || // name of function declaration
202202
(location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration
203203
// get the signature from the declaration and write it
204204
const functionDeclaration = <FunctionLikeDeclaration>location.parent;
@@ -429,7 +429,7 @@ namespace ts.SymbolDisplay {
429429
if (!documentation) {
430430
documentation = symbol.getDocumentationComment();
431431
tags = symbol.getJsDocTags();
432-
if (documentation.length === 0 && symbol.flags & SymbolFlags.Property) {
432+
if (documentation.length === 0 && symbolFlags & SymbolFlags.Property) {
433433
// For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo`
434434
// there documentation comments might be attached to the right hand side symbol of their declarations.
435435
// The pattern of such special property access is that the parent symbol is the symbol of the file.

tests/cases/fourslash/commentsExternalModules.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ goTo.file("commentsExternalModules_file0.ts");
3535
verify.quickInfoAt("1", "namespace m1", "Namespace comment");
3636

3737
goTo.marker('2');
38-
verify.completionListContains("b", "var m1.b: number", "b's comment");
38+
verify.completionListContains("b", "var b: number", "b's comment");
3939
verify.completionListContains("foo", "function foo(): number", "foo's comment");
4040

4141
goTo.marker('3');

tests/cases/fourslash/commentsModules.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
verify.quickInfoAt("1", "namespace m1", "Namespace comment");
100100

101101
goTo.marker('2');
102-
verify.completionListContains("b", "var m1.b: number", "b's comment");
102+
verify.completionListContains("b", "var b: number", "b's comment");
103103
verify.completionListContains("foo", "function foo(): number", "foo's comment");
104104

105105
goTo.marker('3');

tests/cases/fourslash/completionListForUnicodeEscapeName.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ verify.completionListContains("B");
2222
verify.completionListContains("\u0042");
2323
verify.completionListContains("A");
2424
verify.completionListContains("\u0041");
25-
verify.not.completionListContains("C");
26-
verify.not.completionListContains("\u0043");
25+
verify.completionListContains("C");
26+
verify.completionListContains("\u0043");
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /a.ts
4+
////import * as self from "./a";
5+
////
6+
////declare module "a" {
7+
//// export const a: number;
8+
////}
9+
////
10+
/////**/
11+
12+
goTo.marker();
13+
verify.not.completionListContains("a");

tests/cases/fourslash/completionListOnAliases2.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,16 @@ function getVerify(isTypeLocation?: boolean) {
4141
verifyValueOrType: verify
4242
};
4343
}
44-
function typeLocationVerify(valueMarker: string, verify: (typeMarker: string) => void) {
45-
verify(valueMarker + "Type");
46-
return valueMarker;
47-
}
4844

4945
function verifyModuleM(marker: string) {
50-
const isTypeLocation = marker.indexOf("Type") !== -1;
51-
const { verifyValue, verifyType, verifyValueOrType } = getVerify(isTypeLocation);
52-
if (!isTypeLocation) {
53-
marker = typeLocationVerify(marker, verifyModuleM);
54-
}
46+
verifyModuleMWorker(marker, /*isTypeLocation*/ false);
47+
verifyModuleMWorker(`${marker}Type`, /*isTypeLocation*/ true);
48+
}
49+
50+
function verifyModuleMWorker(marker: string, isTypeLocation: boolean): void {
5551
goTo.marker(marker);
5652

53+
const { verifyValue, verifyType, verifyValueOrType } = getVerify(isTypeLocation);
5754
verifyType.completionListContains("I");
5855
verifyValueOrType.completionListContains("C");
5956
verifyValueOrType.completionListContains("E");
@@ -63,8 +60,9 @@ function verifyModuleM(marker: string) {
6360
verifyValueOrType.completionListContains("A");
6461
}
6562

66-
6763
// Module m
64+
goTo.marker("1");
65+
verify.completionListContains("A");
6866
verifyModuleM("1");
6967

7068
// Class C

0 commit comments

Comments
 (0)