Fix #14346
This commit is contained in:
parent
2dd23fa0a8
commit
28a3604714
4 changed files with 95 additions and 25 deletions
|
@ -935,8 +935,6 @@ namespace ts.FindAllReferences.Core {
|
|||
addReference(referenceLocation, search.symbol, search.location, state);
|
||||
}
|
||||
|
||||
const classSymbol = skipAliases(search.symbol, state.checker);
|
||||
Debug.assert(isClassLike(classSymbol.valueDeclaration));
|
||||
const pusher = state.referenceAdder(search.symbol, search.location);
|
||||
|
||||
if (isClassLike(referenceLocation.parent)) {
|
||||
|
@ -1687,10 +1685,6 @@ namespace ts.FindAllReferences.Core {
|
|||
return false;
|
||||
}
|
||||
|
||||
function skipAliases(symbol: Symbol, checker: TypeChecker): Symbol {
|
||||
return symbol.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are just looking for implementations and this is a property access expression, we need to get the
|
||||
* symbol of the local type of the symbol the property is being accessed on. This is because our search
|
||||
|
|
|
@ -32,7 +32,8 @@ namespace ts.FindAllReferences {
|
|||
|
||||
interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; }
|
||||
type SourceFileLike = SourceFile | AmbientModuleDeclaration;
|
||||
type Importer = AnyImportSyntax | ExportDeclaration;
|
||||
// Identifier for the case of `const x = require("y")`.
|
||||
type Importer = AnyImportSyntax | Identifier | ExportDeclaration;
|
||||
type ImporterOrCallExpression = Importer | CallExpression;
|
||||
|
||||
/** 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 {
|
|||
|
||||
// Module augmentations may use this module's exports without importing it.
|
||||
for (const decl of exportingModuleSymbol.declarations) {
|
||||
if (ts.isExternalModuleAugmentation(decl)) {
|
||||
if (isExternalModuleAugmentation(decl)) {
|
||||
addIndirectUser(decl as SourceFileLike);
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +75,15 @@ namespace ts.FindAllReferences {
|
|||
switch (direct.kind) {
|
||||
case SyntaxKind.CallExpression:
|
||||
if (!isAvailableThroughGlobal) {
|
||||
const parent = direct.parent!;
|
||||
if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) {
|
||||
const { name } = parent as ts.VariableDeclaration;
|
||||
if (name.kind === SyntaxKind.Identifier) {
|
||||
directImports.push(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't support re-exporting 'require()' calls, so just add a single indirect user.
|
||||
addIndirectUser(direct.getSourceFile());
|
||||
}
|
||||
|
@ -179,6 +189,11 @@ namespace ts.FindAllReferences {
|
|||
return;
|
||||
}
|
||||
|
||||
if (decl.kind === ts.SyntaxKind.Identifier) {
|
||||
handleNamespaceImportLike(decl);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore if there's a grammar error
|
||||
if (decl.moduleSpecifier.kind !== SyntaxKind.StringLiteral) {
|
||||
return;
|
||||
|
@ -192,7 +207,7 @@ namespace ts.FindAllReferences {
|
|||
const { importClause } = decl;
|
||||
|
||||
const { namedBindings } = importClause;
|
||||
if (namedBindings && namedBindings.kind === ts.SyntaxKind.NamespaceImport) {
|
||||
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
|
||||
handleNamespaceImportLike(namedBindings.name);
|
||||
return;
|
||||
}
|
||||
|
@ -333,13 +348,13 @@ namespace ts.FindAllReferences {
|
|||
|
||||
if (sourceFile.flags & NodeFlags.JavaScriptFile) {
|
||||
// Find all 'require()' calls.
|
||||
recur(sourceFile);
|
||||
function recur(node: Node): void {
|
||||
sourceFile.forEachChild(function recur(node: Node): void {
|
||||
if (isRequireCall(node, /*checkArgumentIsStringLiteral*/true)) {
|
||||
action(node, node.arguments[0] as StringLiteral);
|
||||
} else {
|
||||
node.forEachChild(recur);
|
||||
}
|
||||
forEachChild(node, recur);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -379,18 +394,9 @@ namespace ts.FindAllReferences {
|
|||
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
// 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.
|
||||
// So check that we are at the declaration.
|
||||
if (!symbol.declarations.some(d => d === parent)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (getSpecialPropertyAssignmentKind(parent.parent)) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
return exportInfo(symbol, ExportKind.Named);
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
return exportInfo(symbol, ExportKind.ExportEquals);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
return symbol.declarations.some(d => d === parent) && parent.parent.kind === ts.SyntaxKind.BinaryExpression
|
||||
? getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ false)
|
||||
: undefined;
|
||||
}
|
||||
else {
|
||||
const { exportSymbol } = symbol;
|
||||
|
@ -420,6 +426,29 @@ namespace ts.FindAllReferences {
|
|||
Debug.assert(!!exportingModuleSymbol);
|
||||
return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } };
|
||||
}
|
||||
else if (parent.kind === ts.SyntaxKind.BinaryExpression) {
|
||||
return getSpecialPropertyExport(parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
|
||||
}
|
||||
else if (parent.parent.kind === SyntaxKind.BinaryExpression) {
|
||||
return getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
function getSpecialPropertyExport(node: ts.BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined {
|
||||
let kind: ExportKind;
|
||||
switch (getSpecialPropertyAssignmentKind(node)) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
kind = ExportKind.Named;
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
kind = ExportKind.ExportEquals;
|
||||
break;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const sym = useLhsSymbol ? checker.getSymbolAtLocation((node.left as ts.PropertyAccessExpression).name) : symbol;
|
||||
return sym && exportInfo(sym, kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
16
tests/cases/fourslash/renameJsExports02.ts
Normal file
16
tests/cases/fourslash/renameJsExports02.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {}
|
||||
|
||||
// @Filename: b.js
|
||||
////const [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
|
||||
|
||||
const [r0, r1] = test.ranges();
|
||||
verify.referenceGroups(r0, [
|
||||
{ definition: "(local class) A", ranges: [r0] },
|
||||
{ definition: "const A: typeof A", ranges: [r1] }
|
||||
]);
|
||||
|
||||
verify.singleReferenceGroup("const A: typeof A", [r1]);
|
31
tests/cases/fourslash/renameJsExports03.ts
Normal file
31
tests/cases/fourslash/renameJsExports03.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
////class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {
|
||||
//// [|constructor|]() { }
|
||||
////}
|
||||
////module.exports = [|A|];
|
||||
|
||||
// @Filename: b.js
|
||||
////const [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
|
||||
////new [|A|];
|
||||
|
||||
const [r0, r1, r2, r3, r4] = test.ranges();
|
||||
verify.referenceGroups([r0, r2], [
|
||||
{ definition: "class A", ranges: [r0, r2] },
|
||||
{ definition: "const A: typeof A", ranges: [r3, r4] }
|
||||
]);
|
||||
|
||||
verify.referenceGroups(r1, [
|
||||
{ definition: "constructor A(): A", ranges: [r1] },
|
||||
{ definition: "const A: typeof A", ranges: [r4] }
|
||||
]);
|
||||
|
||||
verify.referenceGroups(r3, [
|
||||
{ definition: "const A: typeof A", ranges: [r3, r4] }
|
||||
]);
|
||||
verify.referenceGroups(r4, [
|
||||
{ definition: "const A: new () => A", ranges: [r3, r4] }
|
||||
]);
|
||||
|
Loading…
Reference in a new issue