Skip to content

Commit e8c3d54

Browse files
author
Andy Hanson
committed
Fix tests
1 parent 0ca4cb2 commit e8c3d54

7 files changed

+104
-54
lines changed

src/services/documentHighlights.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace ts.DocumentHighlights {
1717
}
1818

1919
function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
20-
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/false, /*findInComments*/false, /*implementations*/false);
20+
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch);
2121
return referencedSymbols && convertReferencedSymbols(referencedSymbols);
2222
}
2323

src/services/findAllReferences.ts

+67-42
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/* @internal */
22
namespace ts.FindAllReferences {
3-
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] | undefined {
3+
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] | undefined {
44
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
5-
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false);
5+
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, isForRename);
66
}
77

8-
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] | undefined {
8+
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings?: boolean, findInComments?: boolean, isForRename?: boolean, implementations?: boolean): ReferencedSymbol[] | undefined {
99
if (!implementations) {
1010
const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken);
1111
if (special) {
@@ -33,11 +33,16 @@ namespace ts.FindAllReferences {
3333
return undefined;
3434
}
3535

36-
const aliasedSymbol = followAliasIfNecessary(symbol, node, typeChecker);
37-
const isShorthandModule = ts.isShorthandAmbientModuleSymbol(aliasedSymbol);
38-
// Don't follow alias for shorthand modules because we lose information that way.
39-
if (!isShorthandModule) {
40-
symbol = aliasedSymbol;
36+
const { symbol: aliasedSymbol, shorthandModuleSymbol } = followAliases(symbol, node, typeChecker, isForRename);
37+
symbol = aliasedSymbol;
38+
39+
// Build the set of symbols to search for, initially it has only the current symbol
40+
const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations);
41+
if (shorthandModuleSymbol) {
42+
searchSymbols.push(shorthandModuleSymbol);
43+
}
44+
function isSearchedFor(symbol: Symbol): boolean {
45+
return contains(searchSymbols, symbol);
4146
}
4247

4348
// Compute the meaning from the location and the symbol it references
@@ -48,12 +53,6 @@ namespace ts.FindAllReferences {
4853
const symbolToIndex: number[] = [];
4954
const inheritsFromCache: Map<boolean> = createMap<boolean>();
5055

51-
// Build the set of symbols to search for, initially it has only the current symbol
52-
const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations, isShorthandModule ? aliasedSymbol : undefined);
53-
function isSearchedFor(symbol: Symbol): boolean {
54-
return contains(searchSymbols, symbol);
55-
}
56-
5756
// Get the text to search for.
5857
// Note: if this is an external module symbol, the name doesn't include quotes.
5958
const declaredName = stripQuotes(getDeclaredName(typeChecker, symbol, node));
@@ -116,6 +115,31 @@ namespace ts.FindAllReferences {
116115
return undefined;
117116
}
118117

118+
/**
119+
* Follows aliases to get to the original declaration of a symbol.
120+
* For a shorthand ambient module, we don't follow the alias to it, but we will need to add it to the set of search symbols.
121+
*/
122+
function followAliases(symbol: Symbol, node: Node, typeChecker: TypeChecker, isForRename: boolean): { symbol: Symbol, shorthandModuleSymbol?: Symbol } {
123+
while (true) {
124+
// When renaming a default import, only rename in the current file
125+
if (isForRename && isImportDefaultSymbol(symbol)) {
126+
return { symbol };
127+
}
128+
129+
const aliasedSymbol = getAliasSymbolForPropertyNameSymbol(symbol, node, typeChecker);
130+
// Don't follow alias if it goes to unknown symbol. This can happen if it points to an untyped module.
131+
if (!aliasedSymbol || !aliasedSymbol.declarations) {
132+
return { symbol };
133+
}
134+
135+
if (ts.isShorthandAmbientModuleSymbol(aliasedSymbol)) {
136+
return { symbol, shorthandModuleSymbol: aliasedSymbol };
137+
}
138+
139+
symbol = aliasedSymbol;
140+
}
141+
}
142+
119143
function sourceFileHasName(sourceFile: SourceFile, name: string): boolean {
120144
return getNameTable(sourceFile).get(name) !== undefined;
121145
}
@@ -157,29 +181,30 @@ namespace ts.FindAllReferences {
157181
}
158182

159183
function getAliasSymbolForPropertyNameSymbol(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol | undefined {
160-
if (symbol.flags & SymbolFlags.Alias) {
161-
// Default import get alias
162-
const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
163-
if (defaultImport) {
164-
return typeChecker.getAliasedSymbol(symbol);
165-
}
184+
if (!(symbol.flags & SymbolFlags.Alias)) {
185+
return undefined;
186+
}
166187

167-
const importOrExportSpecifier = <ImportOrExportSpecifier>forEach(symbol.declarations,
168-
declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
169-
declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
170-
if (importOrExportSpecifier &&
171-
// export { a }
172-
(!importOrExportSpecifier.propertyName ||
173-
// export {a as class } where a is location
174-
importOrExportSpecifier.propertyName === location)) {
175-
// If Import specifier -> get alias
176-
// else Export specifier -> get local target
177-
return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
178-
typeChecker.getAliasedSymbol(symbol) :
179-
typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
180-
}
188+
// Default import get alias
189+
const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
190+
if (defaultImport) {
191+
return typeChecker.getAliasedSymbol(symbol);
192+
}
193+
194+
const importOrExportSpecifier = <ImportOrExportSpecifier>forEach(symbol.declarations,
195+
declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
196+
declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
197+
if (importOrExportSpecifier &&
198+
// export { a }
199+
(!importOrExportSpecifier.propertyName ||
200+
// export {a as class } where a is location
201+
importOrExportSpecifier.propertyName === location)) {
202+
// If Import specifier -> get alias
203+
// else Export specifier -> get local target
204+
return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
205+
typeChecker.getAliasedSymbol(symbol) :
206+
typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
181207
}
182-
return undefined;
183208
}
184209

185210
function followAliasIfNecessary(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol {
@@ -1022,9 +1047,9 @@ namespace ts.FindAllReferences {
10221047
}
10231048
}
10241049

1025-
function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean, aliasSymbol?: Symbol): Symbol[] {
1050+
function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean): Symbol[] {
10261051
// The search set contains at least the current symbol
1027-
let result = [symbol];
1052+
const result = [symbol];
10281053

10291054
// If the location is name of property symbol from object literal destructuring pattern
10301055
// Search the property symbol
@@ -1037,10 +1062,6 @@ namespace ts.FindAllReferences {
10371062
}
10381063
}
10391064

1040-
if (aliasSymbol) {
1041-
result = result.concat(populateSearchSymbolSet(aliasSymbol, location, typeChecker, implementations));
1042-
}
1043-
10441065
// If the location is in a context sensitive location (i.e. in an object literal) try
10451066
// to get a contextual type for it, and add the property symbol from the contextual
10461067
// type to the search set
@@ -1072,7 +1093,7 @@ namespace ts.FindAllReferences {
10721093
// Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members
10731094
if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter &&
10741095
isParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration)) {
1075-
result = result.concat(typeChecker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
1096+
addRange(result, typeChecker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
10761097
}
10771098

10781099
// If this is symbol of binding element without propertyName declaration in Object binding pattern
@@ -1447,4 +1468,8 @@ namespace ts.FindAllReferences {
14471468

14481469
return false;
14491470
}
1471+
1472+
function isImportDefaultSymbol(symbol: Symbol): boolean {
1473+
return symbol.declarations[0].kind === SyntaxKind.ImportClause;
1474+
}
14501475
}

src/services/goToImplementation.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace ts.GoToImplementation {
1717
else {
1818
// Perform "Find all References" and retrieve only those that are implementations
1919
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken,
20-
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*implementations*/true);
20+
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*isForRename*/false, /*implementations*/true);
2121
const result = flatMap(referencedSymbols, symbol =>
2222
map(symbol.references, ({ textSpan, fileName }) => ({ textSpan, fileName })));
2323

src/services/services.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1406,25 +1406,25 @@ namespace ts {
14061406
}
14071407

14081408
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
1409-
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments);
1409+
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/true);
14101410
return FindAllReferences.convertReferences(referencedSymbols);
14111411
}
14121412

14131413
function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
1414-
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
1414+
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
14151415
return FindAllReferences.convertReferences(referencedSymbols);
14161416
}
14171417

14181418
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
1419-
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
1419+
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
14201420

14211421
// Only include referenced symbols that have a valid definition.
14221422
return filter(referencedSymbols, rs => !!rs.definition);
14231423
}
14241424

1425-
function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
1425+
function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] {
14261426
synchronizeHostData();
1427-
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments);
1427+
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments, isForRename);
14281428
}
14291429

14301430
/// NavigateTo
+15-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// <reference path='fourslash.ts' />
22

33
// @Filename: B.ts
4-
////export default class [|B|] {
4+
////export default class /*1*/[|B|] {
55
//// test() {
66
//// }
77
////}
@@ -11,4 +11,17 @@
1111
////let b = new [|B|]();
1212
////b.test();
1313

14-
verify.rangesAreRenameLocations();
14+
goTo.marker("1");
15+
verify.occurrencesAtPositionCount(1);
16+
17+
const [C, B0, B1] = test.ranges();
18+
verify.rangesReferenceEachOther();
19+
20+
goTo.rangeStart(C);
21+
verify.renameLocations(false, false, [C, B0, B1]);
22+
23+
const rangesInB = [B0, B1];
24+
for (const r of rangesInB) {
25+
goTo.rangeStart(r);
26+
verify.renameLocations(false, false, rangesInB);
27+
}

tests/cases/fourslash/renameDefaultImportDifferentName.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// <reference path='fourslash.ts' />
22

33
// @Filename: B.ts
4-
////export default class /*1*/C {
4+
////export default class /*1*/[|C|] {
55
//// test() {
66
//// }
77
////}
@@ -14,4 +14,14 @@
1414
goTo.marker("1");
1515
verify.occurrencesAtPositionCount(1);
1616

17-
verify.rangesAreRenameLocations();
17+
const [C, B0, B1] = test.ranges();
18+
verify.rangesReferenceEachOther();
19+
20+
goTo.rangeStart(C);
21+
verify.renameLocations(false, false, [C, B0, B1]);
22+
23+
const rangesInB = [B0, B1];
24+
for (const r of rangesInB) {
25+
goTo.rangeStart(r);
26+
verify.renameLocations(false, false, rangesInB);
27+
}

tests/cases/fourslash/renameImportAndExport.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
////import [|a|] from "module";
44
////export { [|a|] };
55

6-
verify.rangesAreRenameLocations();
6+
const [r0, r1] = test.ranges();
7+
verify.referencesOf(r1, [r0, r1]);
8+
//verify.rangesAreRenameLocations();

0 commit comments

Comments
 (0)