Skip to content

Commit 28a3604

Browse files
author
Andy Hanson
committed
Fix #14346
1 parent 2dd23fa commit 28a3604

File tree

4 files changed

+95
-25
lines changed

4 files changed

+95
-25
lines changed

src/services/findAllReferences.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -935,8 +935,6 @@ namespace ts.FindAllReferences.Core {
935935
addReference(referenceLocation, search.symbol, search.location, state);
936936
}
937937

938-
const classSymbol = skipAliases(search.symbol, state.checker);
939-
Debug.assert(isClassLike(classSymbol.valueDeclaration));
940938
const pusher = state.referenceAdder(search.symbol, search.location);
941939

942940
if (isClassLike(referenceLocation.parent)) {
@@ -1687,10 +1685,6 @@ namespace ts.FindAllReferences.Core {
16871685
return false;
16881686
}
16891687

1690-
function skipAliases(symbol: Symbol, checker: TypeChecker): Symbol {
1691-
return symbol.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
1692-
}
1693-
16941688
/**
16951689
* If we are just looking for implementations and this is a property access expression, we need to get the
16961690
* symbol of the local type of the symbol the property is being accessed on. This is because our search

src/services/importTracker.ts

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ namespace ts.FindAllReferences {
3232

3333
interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; }
3434
type SourceFileLike = SourceFile | AmbientModuleDeclaration;
35-
type Importer = AnyImportSyntax | ExportDeclaration;
35+
// Identifier for the case of `const x = require("y")`.
36+
type Importer = AnyImportSyntax | Identifier | ExportDeclaration;
3637
type ImporterOrCallExpression = Importer | CallExpression;
3738

3839
/** Returns import statements that directly reference the exporting module, and a list of files that may access the module through a namespace. */
@@ -55,7 +56,7 @@ namespace ts.FindAllReferences {
5556

5657
// Module augmentations may use this module's exports without importing it.
5758
for (const decl of exportingModuleSymbol.declarations) {
58-
if (ts.isExternalModuleAugmentation(decl)) {
59+
if (isExternalModuleAugmentation(decl)) {
5960
addIndirectUser(decl as SourceFileLike);
6061
}
6162
}
@@ -74,6 +75,15 @@ namespace ts.FindAllReferences {
7475
switch (direct.kind) {
7576
case SyntaxKind.CallExpression:
7677
if (!isAvailableThroughGlobal) {
78+
const parent = direct.parent!;
79+
if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) {
80+
const { name } = parent as ts.VariableDeclaration;
81+
if (name.kind === SyntaxKind.Identifier) {
82+
directImports.push(name);
83+
break;
84+
}
85+
}
86+
7787
// Don't support re-exporting 'require()' calls, so just add a single indirect user.
7888
addIndirectUser(direct.getSourceFile());
7989
}
@@ -179,6 +189,11 @@ namespace ts.FindAllReferences {
179189
return;
180190
}
181191

192+
if (decl.kind === ts.SyntaxKind.Identifier) {
193+
handleNamespaceImportLike(decl);
194+
return;
195+
}
196+
182197
// Ignore if there's a grammar error
183198
if (decl.moduleSpecifier.kind !== SyntaxKind.StringLiteral) {
184199
return;
@@ -192,7 +207,7 @@ namespace ts.FindAllReferences {
192207
const { importClause } = decl;
193208

194209
const { namedBindings } = importClause;
195-
if (namedBindings && namedBindings.kind === ts.SyntaxKind.NamespaceImport) {
210+
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
196211
handleNamespaceImportLike(namedBindings.name);
197212
return;
198213
}
@@ -333,13 +348,13 @@ namespace ts.FindAllReferences {
333348

334349
if (sourceFile.flags & NodeFlags.JavaScriptFile) {
335350
// Find all 'require()' calls.
336-
recur(sourceFile);
337-
function recur(node: Node): void {
351+
sourceFile.forEachChild(function recur(node: Node): void {
338352
if (isRequireCall(node, /*checkArgumentIsStringLiteral*/true)) {
339353
action(node, node.arguments[0] as StringLiteral);
354+
} else {
355+
node.forEachChild(recur);
340356
}
341-
forEachChild(node, recur);
342-
}
357+
});
343358
}
344359
}
345360
}
@@ -379,18 +394,9 @@ namespace ts.FindAllReferences {
379394
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
380395
// When accessing an export of a JS module, there's no alias. The symbol will still be flagged as an export even though we're at the use.
381396
// So check that we are at the declaration.
382-
if (!symbol.declarations.some(d => d === parent)) {
383-
return undefined;
384-
}
385-
386-
switch (getSpecialPropertyAssignmentKind(parent.parent)) {
387-
case SpecialPropertyAssignmentKind.ExportsProperty:
388-
return exportInfo(symbol, ExportKind.Named);
389-
case SpecialPropertyAssignmentKind.ModuleExports:
390-
return exportInfo(symbol, ExportKind.ExportEquals);
391-
default:
392-
return undefined;
393-
}
397+
return symbol.declarations.some(d => d === parent) && parent.parent.kind === ts.SyntaxKind.BinaryExpression
398+
? getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ false)
399+
: undefined;
394400
}
395401
else {
396402
const { exportSymbol } = symbol;
@@ -420,6 +426,29 @@ namespace ts.FindAllReferences {
420426
Debug.assert(!!exportingModuleSymbol);
421427
return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } };
422428
}
429+
else if (parent.kind === ts.SyntaxKind.BinaryExpression) {
430+
return getSpecialPropertyExport(parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
431+
}
432+
else if (parent.parent.kind === SyntaxKind.BinaryExpression) {
433+
return getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
434+
}
435+
}
436+
437+
function getSpecialPropertyExport(node: ts.BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined {
438+
let kind: ExportKind;
439+
switch (getSpecialPropertyAssignmentKind(node)) {
440+
case SpecialPropertyAssignmentKind.ExportsProperty:
441+
kind = ExportKind.Named;
442+
break;
443+
case SpecialPropertyAssignmentKind.ModuleExports:
444+
kind = ExportKind.ExportEquals;
445+
break;
446+
default:
447+
return undefined;
448+
}
449+
450+
const sym = useLhsSymbol ? checker.getSymbolAtLocation((node.left as ts.PropertyAccessExpression).name) : symbol;
451+
return sym && exportInfo(sym, kind);
423452
}
424453
}
425454

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
// @allowJs: true
4+
// @Filename: a.js
5+
////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {}
6+
7+
// @Filename: b.js
8+
////const [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
9+
10+
const [r0, r1] = test.ranges();
11+
verify.referenceGroups(r0, [
12+
{ definition: "(local class) A", ranges: [r0] },
13+
{ definition: "const A: typeof A", ranges: [r1] }
14+
]);
15+
16+
verify.singleReferenceGroup("const A: typeof A", [r1]);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
// @allowJs: true
4+
// @Filename: a.js
5+
////class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {
6+
//// [|constructor|]() { }
7+
////}
8+
////module.exports = [|A|];
9+
10+
// @Filename: b.js
11+
////const [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
12+
////new [|A|];
13+
14+
const [r0, r1, r2, r3, r4] = test.ranges();
15+
verify.referenceGroups([r0, r2], [
16+
{ definition: "class A", ranges: [r0, r2] },
17+
{ definition: "const A: typeof A", ranges: [r3, r4] }
18+
]);
19+
20+
verify.referenceGroups(r1, [
21+
{ definition: "constructor A(): A", ranges: [r1] },
22+
{ definition: "const A: typeof A", ranges: [r4] }
23+
]);
24+
25+
verify.referenceGroups(r3, [
26+
{ definition: "const A: typeof A", ranges: [r3, r4] }
27+
]);
28+
verify.referenceGroups(r4, [
29+
{ definition: "const A: new () => A", ranges: [r3, r4] }
30+
]);
31+

0 commit comments

Comments
 (0)