Fix find-all-refs for import("mod").Foo where Foo is a typedef (#23881)

* Fix find-all-refs for import("mod").Foo where Foo is a typedef

* Add Debug.assertNever message

* Ensure SemanticMeaning is matched
This commit is contained in:
Andy
2018-05-04 13:32:40 -07:00
committed by GitHub
parent 5133c70e7e
commit df9e2621d2
7 changed files with 85 additions and 14 deletions

View File

@@ -559,7 +559,8 @@ namespace ts.FindAllReferences.Core {
const addRef = state.referenceAdder(exportSymbol);
for (const singleRef of singleReferences) {
// At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename.
if (!(state.options.isForRename && (isExportSpecifier(singleRef.parent) || isImportSpecifier(singleRef.parent)) && singleRef.escapedText === InternalSymbolName.Default)) {
if (hasMatchingMeaning(singleRef, state) &&
!(state.options.isForRename && (isExportSpecifier(singleRef.parent) || isImportSpecifier(singleRef.parent)) && singleRef.escapedText === InternalSymbolName.Default)) {
addRef(singleRef);
}
}
@@ -822,6 +823,10 @@ namespace ts.FindAllReferences.Core {
}
}
function hasMatchingMeaning(referenceLocation: Node, state: State): boolean {
return !!(getMeaningFromLocation(referenceLocation) & state.searchMeaning);
}
function getReferencesAtLocation(sourceFile: SourceFile, position: number, search: Search, state: State, addReferencesHere: boolean): void {
const referenceLocation = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
@@ -840,9 +845,7 @@ namespace ts.FindAllReferences.Core {
return;
}
if (!(getMeaningFromLocation(referenceLocation) & state.searchMeaning)) {
return;
}
if (!hasMatchingMeaning(referenceLocation, state)) return;
const referenceSymbol = state.checker.getSymbolAtLocation(referenceLocation);
if (!referenceSymbol) {

View File

@@ -99,6 +99,9 @@ namespace ts.FindAllReferences {
}
break;
case SyntaxKind.Identifier: // for 'const x = require("y");
break; // TODO: GH#23879
case SyntaxKind.ImportEqualsDeclaration:
handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export));
break;
@@ -130,6 +133,19 @@ namespace ts.FindAllReferences {
directImports.push(direct);
}
break;
case SyntaxKind.ImportType:
if (direct.qualifier) {
// `import("foo").x` named import
directImports.push(direct);
}
else {
// TODO: GH#23879
}
break;
default:
Debug.assertNever(direct, `Unexpected import kind: ${Debug.showSyntaxKind(direct)}`);
}
}
}
@@ -216,6 +232,9 @@ namespace ts.FindAllReferences {
}
if (decl.kind === SyntaxKind.ImportType) {
if (decl.qualifier) { // TODO: GH#23879
singleReferences.push(decl.qualifier.kind === SyntaxKind.Identifier ? decl.qualifier : decl.qualifier.right);
}
return;
}
@@ -313,16 +332,10 @@ namespace ts.FindAllReferences {
const namespaceImportSymbol = checker.getSymbolAtLocation(name);
return forEachPossibleImportOrExportStatement(sourceFileLike, statement => {
if (statement.kind !== SyntaxKind.ExportDeclaration) return;
const { exportClause, moduleSpecifier } = statement as ExportDeclaration;
if (moduleSpecifier || !exportClause) return;
for (const element of exportClause.elements) {
if (checker.getExportSpecifierLocalTargetSymbol(element) === namespaceImportSymbol) {
return true;
}
}
if (!isExportDeclaration(statement)) return;
const { exportClause, moduleSpecifier } = statement;
return !moduleSpecifier && exportClause &&
exportClause.elements.some(element => checker.getExportSpecifierLocalTargetSymbol(element) === namespaceImportSymbol);
});
}
@@ -485,6 +498,9 @@ namespace ts.FindAllReferences {
else if (isBinaryExpression(parent.parent)) {
return getSpecialPropertyExport(parent.parent, /*useLhsSymbol*/ true);
}
else if (isJSDocTypedefTag(parent)) {
return exportInfo(symbol, ExportKind.Named);
}
}
function getExportAssignmentExport(ex: ExportAssignment): ExportedSymbol {

View File

@@ -180,6 +180,8 @@ namespace ts {
switch (node.parent.kind) {
case SyntaxKind.TypeReference:
return true;
case SyntaxKind.ImportType:
return !(node.parent as ImportTypeNode).isTypeOf;
case SyntaxKind.ExpressionWithTypeArguments:
return !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent);
}

View File

@@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////module.exports = 0;
////export type [|{| "isWriteAccess": true, "isDefinition": true |}N|] = number;
// @Filename: /b.js
////type T = import("./a").[|N|];
verify.rangesReferenceEachOther();

View File

@@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
////export = [|T|];
////const x: [|import("./b")|] = 0;
// TODO: GH#23879 should just verify.rangesReferenceEachOther();
const [r0, r1, r2] = test.ranges();
verify.referenceGroups([r0, r1], [{ definition: "type T = number", ranges: [r0, r1] }]);
verify.referenceGroups(r2, undefined);

View File

@@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////module.exports = 0;
/////** @typedef {number} [|{| "isWriteAccess": true, "isDefinition": true |}Foo|] */
////const dummy = 0;
// @Filename: /b.js
/////** @type {import('./a').[|Foo|]} */
////const x = 0;
verify.rangesReferenceEachOther();

View File

@@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
// @Filename: /a.ts
////export type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = 0;
////export const [|{| "isWriteAccess": true, "isDefinition": true |}T|] = 0;
// @Filename: /b.ts
////const x: import("./a").[|T|] = 0;
////const x: typeof import("./a").[|T|] = 0;
const [r0, r1, r2, r3] = test.ranges();
verify.rangesReferenceEachOther([r0, r2]);
verify.rangesReferenceEachOther([r1, r3]);