Skip to content

Commit c5dd17f

Browse files
committed
Merge pull request #6376 from Microsoft/fixFindReferencesOnExports
Fix find all refs in shorthand properties for imports and exports
2 parents 36e9e9e + 31d8515 commit c5dd17f

8 files changed

+95
-8
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ namespace ts {
8383
getSymbolsInScope,
8484
getSymbolAtLocation,
8585
getShorthandAssignmentValueSymbol,
86+
getExportSpecifierLocalTargetSymbol,
8687
getTypeAtLocation: getTypeOfNode,
8788
typeToString,
8889
getSymbolDisplayBuilder,
@@ -15062,11 +15063,18 @@ namespace ts {
1506215063
// This is necessary as an identifier in short-hand property assignment can contains two meaning:
1506315064
// property name and property value.
1506415065
if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) {
15065-
return resolveEntityName((<ShorthandPropertyAssignment>location).name, SymbolFlags.Value);
15066+
return resolveEntityName((<ShorthandPropertyAssignment>location).name, SymbolFlags.Value | SymbolFlags.Alias);
1506615067
}
1506715068
return undefined;
1506815069
}
1506915070

15071+
/** Returns the target of an export specifier without following aliases */
15072+
function getExportSpecifierLocalTargetSymbol(node: ExportSpecifier): Symbol {
15073+
return (<ExportDeclaration>node.parent.parent).moduleSpecifier ?
15074+
getExternalModuleMember(<ExportDeclaration>node.parent.parent, node) :
15075+
resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias);
15076+
}
15077+
1507015078
function getTypeOfNode(node: Node): Type {
1507115079
if (isInsideWithStatementBody(node)) {
1507215080
// We cannot answer semantic questions within a with block, do not proceed any further

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,7 @@ namespace ts {
17251725
getSymbolAtLocation(node: Node): Symbol;
17261726
getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[];
17271727
getShorthandAssignmentValueSymbol(location: Node): Symbol;
1728+
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol;
17281729
getTypeAtLocation(node: Node): Type;
17291730
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
17301731
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;

src/services/services.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5517,10 +5517,8 @@ namespace ts {
55175517
};
55185518
}
55195519

5520-
function isImportOrExportSpecifierImportSymbol(symbol: Symbol) {
5521-
return (symbol.flags & SymbolFlags.Alias) && forEach(symbol.declarations, declaration => {
5522-
return declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ExportSpecifier;
5523-
});
5520+
function isImportSpecifierSymbol(symbol: Symbol) {
5521+
return (symbol.flags & SymbolFlags.Alias) && !!getDeclarationOfKind(symbol, SyntaxKind.ImportSpecifier);
55245522
}
55255523

55265524
function getInternedName(symbol: Symbol, location: Node, declarations: Declaration[]): string {
@@ -5964,8 +5962,17 @@ namespace ts {
59645962
let result = [symbol];
59655963

59665964
// If the symbol is an alias, add what it alaises to the list
5967-
if (isImportOrExportSpecifierImportSymbol(symbol)) {
5968-
result.push(typeChecker.getAliasedSymbol(symbol));
5965+
if (isImportSpecifierSymbol(symbol)) {
5966+
result.push(typeChecker.getAliasedSymbol(symbol));
5967+
}
5968+
5969+
// For export specifiers, the exported name can be refering to a local symbol, e.g.:
5970+
// import {a} from "mod";
5971+
// export {a as somethingElse}
5972+
// We want the *local* declaration of 'a' as declared in the import,
5973+
// *not* as declared within "mod" (or farther)
5974+
if (location.parent.kind === SyntaxKind.ExportSpecifier) {
5975+
result.push(typeChecker.getExportSpecifierLocalTargetSymbol(<ExportSpecifier>location.parent));
59695976
}
59705977

59715978
// If the location is in a context sensitive location (i.e. in an object literal) try
@@ -6055,13 +6062,24 @@ namespace ts {
60556062

60566063
// If the reference symbol is an alias, check if what it is aliasing is one of the search
60576064
// symbols.
6058-
if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) {
6065+
if (isImportSpecifierSymbol(referenceSymbol)) {
60596066
const aliasedSymbol = typeChecker.getAliasedSymbol(referenceSymbol);
60606067
if (searchSymbols.indexOf(aliasedSymbol) >= 0) {
60616068
return aliasedSymbol;
60626069
}
60636070
}
60646071

6072+
// For export specifiers, it can be a local symbol, e.g.
6073+
// import {a} from "mod";
6074+
// export {a as somethingElse}
6075+
// We want the local target of the export (i.e. the import symbol) and not the final target (i.e. "mod".a)
6076+
if (referenceLocation.parent.kind === SyntaxKind.ExportSpecifier) {
6077+
const aliasedSymbol = typeChecker.getExportSpecifierLocalTargetSymbol(<ExportSpecifier>referenceLocation.parent);
6078+
if (searchSymbols.indexOf(aliasedSymbol) >= 0) {
6079+
return aliasedSymbol;
6080+
}
6081+
}
6082+
60656083
// If the reference location is in an object literal, try to get the contextual type for the
60666084
// object literal, lookup the property symbol in the contextual type, and use this symbol to
60676085
// compare to our searchSymbol
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////import [|a|] from "module";
4+
////export { [|a|] };
5+
6+
let ranges = test.ranges()
7+
for (let range of ranges) {
8+
goTo.position(range.start);
9+
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////import [|foo|] from 'bar';
4+
////const bar = { [|foo|] };
5+
6+
let ranges = test.ranges()
7+
for (let range of ranges) {
8+
goTo.position(range.start);
9+
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////import * as [|foo|] from 'bar';
4+
////const bar = { [|foo|] };
5+
6+
let ranges = test.ranges()
7+
for (let range of ranges) {
8+
goTo.position(range.start);
9+
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////declare namespace N {
4+
//// export var x: number;
5+
////}
6+
////declare module "mod" {
7+
//// export = N;
8+
////}
9+
////declare module "test" {
10+
//// import * as [|N|] from "mod";
11+
//// export { [|N|] }; // Renaming N here would rename
12+
////}
13+
14+
let ranges = test.ranges()
15+
for (let range of ranges) {
16+
goTo.position(range.start);
17+
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
18+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////import [|e|] = require("mod4");
4+
////[|e|];
5+
////a = { [|e|] };
6+
////export { [|e|] };
7+
8+
let ranges = test.ranges()
9+
for (let range of ranges) {
10+
goTo.position(range.start);
11+
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
12+
}

0 commit comments

Comments
 (0)