mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-12 20:25:48 -06:00
Improvements to find-all-references for import types (#23998)
* Improvements to find-all-references for import types * Add JS test
This commit is contained in:
parent
3f39916a56
commit
fd17f77cc9
@ -3252,12 +3252,17 @@ namespace ts {
|
||||
/* @internal */
|
||||
export type AnyImportOrReExport = AnyImportSyntax | ExportDeclaration;
|
||||
|
||||
/* @internal */
|
||||
export interface ValidImportTypeNode extends ImportTypeNode {
|
||||
argument: LiteralTypeNode & { literal: StringLiteral };
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type AnyValidImportOrReExport =
|
||||
| (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral }
|
||||
| ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral } }
|
||||
| RequireOrImportCall
|
||||
| ImportTypeNode & { argument: LiteralType };
|
||||
| ValidImportTypeNode;
|
||||
|
||||
/* @internal */
|
||||
export type RequireOrImportCall = CallExpression & { arguments: [StringLiteralLike] };
|
||||
|
||||
@ -1728,6 +1728,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function importFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport {
|
||||
return tryGetImportFromModuleSpecifier(node) || Debug.fail(Debug.showSyntaxKind(node.parent));
|
||||
}
|
||||
|
||||
export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport | undefined {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
@ -1737,9 +1741,10 @@ namespace ts {
|
||||
case SyntaxKind.CallExpression:
|
||||
return node.parent as AnyValidImportOrReExport;
|
||||
case SyntaxKind.LiteralType:
|
||||
return cast(node.parent.parent, isImportTypeNode) as ImportTypeNode & { argument: LiteralType };
|
||||
Debug.assert(isStringLiteral(node));
|
||||
return tryCast(node.parent.parent, isImportTypeNode) as ValidImportTypeNode | undefined;
|
||||
default:
|
||||
return Debug.fail(Debug.showSyntaxKind(node.parent));
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -236,7 +236,7 @@ namespace ts.FindAllReferences.Core {
|
||||
export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName)): SymbolAndEntries[] | undefined {
|
||||
if (isSourceFile(node)) {
|
||||
const reference = GoToDefinition.getReferenceAtPosition(node, position, program);
|
||||
return reference && getReferencedSymbolsForModule(program, program.getTypeChecker().getMergedSymbol(reference.file.symbol), sourceFiles, sourceFilesSet);
|
||||
return reference && getReferencedSymbolsForModule(program, program.getTypeChecker().getMergedSymbol(reference.file.symbol), /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
|
||||
}
|
||||
|
||||
if (!options.implementations) {
|
||||
@ -247,7 +247,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const symbol = checker.getSymbolAtLocation(node);
|
||||
let symbol = checker.getSymbolAtLocation(node);
|
||||
|
||||
// Could not find a symbol e.g. unknown identifier
|
||||
if (!symbol) {
|
||||
@ -255,37 +255,37 @@ namespace ts.FindAllReferences.Core {
|
||||
return !options.implementations && isStringLiteral(node) ? getReferencesForStringLiteral(node, sourceFiles, cancellationToken) : undefined;
|
||||
}
|
||||
|
||||
if (symbol.flags & SymbolFlags.Module && isModuleReferenceLocation(node)) {
|
||||
return getReferencedSymbolsForModule(program, symbol, sourceFiles, sourceFilesSet);
|
||||
let moduleReferences: SymbolAndEntries[] = emptyArray;
|
||||
const moduleSourceFile = isModuleSymbol(symbol);
|
||||
if (moduleSourceFile) {
|
||||
const exportEquals = symbol.exports.get(InternalSymbolName.ExportEquals);
|
||||
// If !!exportEquals, we're about to add references to `import("mod")` anyway, so don't double-count them.
|
||||
moduleReferences = getReferencedSymbolsForModule(program, symbol, !!exportEquals, sourceFiles, sourceFilesSet);
|
||||
if (!exportEquals || !sourceFilesSet.has(moduleSourceFile.fileName)) return moduleReferences;
|
||||
// Continue to get references to 'export ='.
|
||||
symbol = skipAlias(exportEquals, checker);
|
||||
node = undefined;
|
||||
}
|
||||
|
||||
return getReferencedSymbolsForSymbol(symbol, node, sourceFiles, sourceFilesSet, checker, cancellationToken, options);
|
||||
return concatenate(moduleReferences, getReferencedSymbolsForSymbol(symbol, node, sourceFiles, sourceFilesSet, checker, cancellationToken, options));
|
||||
}
|
||||
|
||||
function isModuleReferenceLocation(node: Node): boolean {
|
||||
if (!isStringLiteralLike(node)) {
|
||||
return false;
|
||||
}
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ExternalModuleReference:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.LiteralType:
|
||||
return isImportTypeNode(node.parent.parent);
|
||||
case SyntaxKind.CallExpression:
|
||||
return isRequireCall(node.parent as CallExpression, /*checkArgumentIsStringLiteralLike*/ false) || isImportCall(node.parent as CallExpression);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
function isModuleSymbol(symbol: Symbol): SourceFile | undefined {
|
||||
return symbol.flags & SymbolFlags.Module && find(symbol.declarations, isSourceFile);
|
||||
}
|
||||
|
||||
function getReferencedSymbolsForModule(program: Program, symbol: Symbol, sourceFiles: ReadonlyArray<SourceFile>, sourceFilesSet: ReadonlyMap<true>): SymbolAndEntries[] {
|
||||
function getReferencedSymbolsForModule(program: Program, symbol: Symbol, excludeImportTypeOfExportEquals: boolean, sourceFiles: ReadonlyArray<SourceFile>, sourceFilesSet: ReadonlyMap<true>): SymbolAndEntries[] {
|
||||
Debug.assert(!!symbol.valueDeclaration);
|
||||
|
||||
const references = findModuleReferences(program, sourceFiles, symbol).map<Entry>(reference => {
|
||||
const references = mapDefined<ModuleReference, Entry>(findModuleReferences(program, sourceFiles, symbol), reference => {
|
||||
if (reference.kind === "import") {
|
||||
const parent = reference.literal.parent;
|
||||
if (isLiteralTypeNode(parent)) {
|
||||
const importType = cast(parent.parent, isImportTypeNode);
|
||||
if (excludeImportTypeOfExportEquals && !importType.qualifier) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
// import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway.
|
||||
return { type: "node", node: reference.literal };
|
||||
}
|
||||
else {
|
||||
@ -308,11 +308,12 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// This may be merged with something.
|
||||
Debug.fail("Expected a module symbol to be declared by a SourceFile or ModuleDeclaration.");
|
||||
}
|
||||
}
|
||||
|
||||
return [{ definition: { type: "symbol", symbol }, references }];
|
||||
return references.length ? [{ definition: { type: "symbol", symbol }, references }] : emptyArray;
|
||||
}
|
||||
|
||||
/** getReferencedSymbols for special node kinds. */
|
||||
@ -345,21 +346,21 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
/** Core find-all-references algorithm for a normal symbol. */
|
||||
function getReferencedSymbolsForSymbol(symbol: Symbol, node: Node, sourceFiles: ReadonlyArray<SourceFile>, sourceFilesSet: ReadonlyMap<true>, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] {
|
||||
symbol = skipPastExportOrImportSpecifierOrUnion(symbol, node, checker) || symbol;
|
||||
function getReferencedSymbolsForSymbol(symbol: Symbol, node: Node | undefined, sourceFiles: ReadonlyArray<SourceFile>, sourceFilesSet: ReadonlyMap<true>, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] {
|
||||
symbol = node && skipPastExportOrImportSpecifierOrUnion(symbol, node, checker) || symbol;
|
||||
|
||||
// Compute the meaning from the location and the symbol it references
|
||||
const searchMeaning = getIntersectingMeaningFromDeclarations(node, symbol);
|
||||
const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All;
|
||||
|
||||
const result: SymbolAndEntries[] = [];
|
||||
const state = new State(sourceFiles, sourceFilesSet, getSpecialSearchKind(node), checker, cancellationToken, searchMeaning, options, result);
|
||||
const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result);
|
||||
|
||||
if (node.kind === SyntaxKind.DefaultKeyword) {
|
||||
if (node && node.kind === SyntaxKind.DefaultKeyword) {
|
||||
addReference(node, symbol, state);
|
||||
searchForImportsOfExport(node, symbol, { exportingModuleSymbol: Debug.assertDefined(symbol.parent, "Expected export symbol to have a parent"), exportKind: ExportKind.Default }, state);
|
||||
}
|
||||
else {
|
||||
const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: populateSearchSymbolSet(symbol, node, checker, options.implementations) });
|
||||
const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, options.implementations) : [symbol] });
|
||||
|
||||
// Try to get the smallest valid scope that we can limit our search to;
|
||||
// otherwise we'll need to search globally (i.e. include each file).
|
||||
@ -499,7 +500,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
/** @param allSearchSymbols set of additinal symbols for use by `includes`. */
|
||||
createSearch(location: Node, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search {
|
||||
createSearch(location: Node | undefined, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search {
|
||||
// Note: if this is an external module symbol, the name doesn't include quotes.
|
||||
// Note: getLocalSymbolForExportDefault handles `export default class C {}`, but not `export default C` or `export { C as default }`.
|
||||
// The other two forms seem to be handled downstream (e.g. in `skipPastExportOrImportSpecifier`), so special-casing the first form
|
||||
@ -509,7 +510,7 @@ namespace ts.FindAllReferences.Core {
|
||||
allSearchSymbols = [symbol],
|
||||
} = searchOptions;
|
||||
const escapedText = escapeLeadingUnderscores(text);
|
||||
const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker);
|
||||
const parents = this.options.implementations && location && getParentSymbolsOfPropertyAccess(location, symbol, this.checker);
|
||||
return { symbol, comingFrom, text, escapedText, parents, allSearchSymbols, includes: sym => contains(allSearchSymbols, sym) };
|
||||
}
|
||||
|
||||
@ -559,11 +560,7 @@ namespace ts.FindAllReferences.Core {
|
||||
if (singleReferences.length) {
|
||||
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 (hasMatchingMeaning(singleRef, state) &&
|
||||
!(state.options.isForRename && (isExportSpecifier(singleRef.parent) || isImportSpecifier(singleRef.parent)) && singleRef.escapedText === InternalSymbolName.Default)) {
|
||||
addRef(singleRef);
|
||||
}
|
||||
if (shouldAddSingleReference(singleRef, state)) addRef(singleRef);
|
||||
}
|
||||
}
|
||||
|
||||
@ -593,6 +590,15 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
}
|
||||
|
||||
function shouldAddSingleReference(singleRef: Identifier | StringLiteral, state: State): boolean {
|
||||
if (!hasMatchingMeaning(singleRef, state)) return false;
|
||||
if (!state.options.isForRename) return true;
|
||||
// Don't rename an import type `import("./module-name")` when renaming `name` in `export = name;`
|
||||
if (!isIdentifier(singleRef)) return false;
|
||||
// At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename.
|
||||
return !((isExportSpecifier(singleRef.parent) || isImportSpecifier(singleRef.parent)) && singleRef.escapedText === InternalSymbolName.Default);
|
||||
}
|
||||
|
||||
// Go to the symbol we imported from and find references for it.
|
||||
function searchForImportedSymbol(symbol: Symbol, state: State): void {
|
||||
for (const declaration of symbol.declarations) {
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
namespace ts.FindAllReferences {
|
||||
export interface ImportsResult {
|
||||
/** For every import of the symbol, the location and local symbol for the import. */
|
||||
importSearches: [Identifier, Symbol][];
|
||||
importSearches: ReadonlyArray<[Identifier, Symbol]>;
|
||||
/** For rename imports/exports `{ foo as bar }`, `foo` is not a local, so it may be added as a reference immediately without further searching. */
|
||||
singleReferences: Identifier[];
|
||||
singleReferences: ReadonlyArray<Identifier | StringLiteral>;
|
||||
/** List of source files that may (or may not) use the symbol via a namespace. (For UMD modules this is every file.) */
|
||||
indirectUsers: ReadonlyArray<SourceFile>;
|
||||
}
|
||||
@ -33,7 +33,7 @@ namespace ts.FindAllReferences {
|
||||
interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; }
|
||||
type SourceFileLike = SourceFile | AmbientModuleDeclaration;
|
||||
// Identifier for the case of `const x = require("y")`.
|
||||
type Importer = AnyImportOrReExport | ImportTypeNode | Identifier;
|
||||
type Importer = AnyImportOrReExport | ValidImportTypeNode | Identifier;
|
||||
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. */
|
||||
@ -135,13 +135,7 @@ namespace ts.FindAllReferences {
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImportType:
|
||||
if (direct.qualifier) {
|
||||
// `import("foo").x` named import
|
||||
directImports.push(direct);
|
||||
}
|
||||
else {
|
||||
// TODO: GH#23879
|
||||
}
|
||||
directImports.push(direct);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -205,7 +199,7 @@ namespace ts.FindAllReferences {
|
||||
*/
|
||||
function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker, isForRename: boolean): Pick<ImportsResult, "importSearches" | "singleReferences"> {
|
||||
const importSearches: [Identifier, Symbol][] = [];
|
||||
const singleReferences: Identifier[] = [];
|
||||
const singleReferences: (Identifier | StringLiteral)[] = [];
|
||||
function addSearch(location: Identifier, symbol: Symbol): void {
|
||||
importSearches.push([location, symbol]);
|
||||
}
|
||||
@ -232,8 +226,13 @@ 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);
|
||||
if (decl.qualifier) {
|
||||
if (isIdentifier(decl.qualifier) && decl.qualifier.escapedText === symbolName(exportSymbol)) {
|
||||
singleReferences.push(decl.qualifier);
|
||||
}
|
||||
}
|
||||
else if (exportKind === ExportKind.ExportEquals) {
|
||||
singleReferences.push(decl.argument.literal);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -36,6 +36,9 @@ namespace ts.Rename {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Can't rename a module name.
|
||||
if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) return undefined;
|
||||
|
||||
const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);
|
||||
const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteral(node) && node.parent.kind === SyntaxKind.ComputedPropertyName)
|
||||
? stripQuotes(getTextOfIdentifierOrLiteral(node))
|
||||
|
||||
@ -107,6 +107,10 @@ namespace ts {
|
||||
Debug.assert(isJSDocTemplateTag(node.parent.parent)); // Else would be handled by isDeclarationName
|
||||
return SemanticMeaning.Type;
|
||||
}
|
||||
else if (isLiteralTypeNode(node.parent)) {
|
||||
// This might be T["name"], which is actually referencing a property and not a type. So allow both meanings.
|
||||
return SemanticMeaning.Type | SemanticMeaning.Value;
|
||||
}
|
||||
else {
|
||||
return SemanticMeaning.Value;
|
||||
}
|
||||
|
||||
16
tests/cases/fourslash/findAllRefsExportEquals.ts
Normal file
16
tests/cases/fourslash/findAllRefsExportEquals.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
|
||||
////export = [|T|];
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import [|{| "isWriteAccess": true, "isDefinition": true |}T|] = require("[|./a|]");
|
||||
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
const mod = { definition: 'module "/a"', ranges: [r3] };
|
||||
const a = { definition: "type T = number", ranges: [r0, r1] };
|
||||
const b = { definition: '(alias) type T = number\nimport T = require("./a")', ranges: [r2] };
|
||||
verify.referenceGroups([r0, r1], [a, b]);
|
||||
verify.referenceGroups(r2, [b, a]);
|
||||
verify.referenceGroups(r3, [mod, a, b]);
|
||||
@ -9,7 +9,4 @@
|
||||
////declare module "[|{| "isWriteAccess": true, "isDefinition": true |}foo|]" {}
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2] = ranges;
|
||||
verify.singleReferenceGroup('module "/node_modules/foo/index"');
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /b.ts
|
||||
////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
|
||||
////export = [|T|];
|
||||
|
||||
// @Filename: /a.ts
|
||||
////const x: import("[|./b|]") = 0;
|
||||
|
||||
// TODO: GH#23879 Should be `verify.singleReferenceGroup("type T = number")
|
||||
const [r0, r1, r2] = test.ranges();
|
||||
verify.referenceGroups([r0, r1], [{ definition: "type T = number", ranges: [r0, r1] }]);
|
||||
verify.referenceGroups(r2, [{ definition: 'module "/b"', ranges: [r2] }]);
|
||||
31
tests/cases/fourslash/findAllRefs_importType_exportEquals.ts
Normal file
31
tests/cases/fourslash/findAllRefs_importType_exportEquals.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
|
||||
////namespace [|{| "isWriteAccess": true, "isDefinition": true |}T|] {
|
||||
//// export type U = string;
|
||||
////}
|
||||
////export = [|T|];
|
||||
|
||||
// @Filename: /b.ts
|
||||
////const x: import("[|./a|]") = 0;
|
||||
////const y: import("[|./a|]").U = "";
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
const [r0, r1, r2, r3, r4] = test.ranges();
|
||||
verify.referenceGroups(r0, [{ definition: "type T = number\nnamespace T", ranges: [r0, r2, r3] }]);
|
||||
verify.referenceGroups(r1, [{ definition: "type T = number\nnamespace T", ranges: [r1, r2] }]);
|
||||
verify.referenceGroups(r2, [{ definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] }]);
|
||||
verify.referenceGroups([r3, r4], [
|
||||
{ definition: 'module "/a"', ranges: [r4] },
|
||||
{ definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] },
|
||||
]);
|
||||
|
||||
verify.renameLocations(r0, [r0, r2]);
|
||||
verify.renameLocations(r1, [r1, r2]);
|
||||
verify.renameLocations(r2, [r0, r1, r2]);
|
||||
for (const range of [r3, r4]) {
|
||||
goTo.rangeStart(range);
|
||||
verify.renameInfoFailed();
|
||||
}
|
||||
37
tests/cases/fourslash/findAllRefs_importType_js.ts
Normal file
37
tests/cases/fourslash/findAllRefs_importType_js.ts
Normal file
@ -0,0 +1,37 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
|
||||
// @Filename: /a.js
|
||||
////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}C|] {};
|
||||
////module.exports.[|{| "isWriteAccess": true, "isDefinition": true |}D|] = class [|{| "isWriteAccess": true, "isDefinition": true |}D|] {};
|
||||
|
||||
// @Filename: /b.js
|
||||
/////** @type {import("[|./a|]")} */
|
||||
////const x = 0;
|
||||
/////** @type {import("[|./a|]").[|D|]} */
|
||||
////const y = 0;
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
// TODO: GH#24025
|
||||
|
||||
const [r0, r1, r2, r3, r4, r5] = test.ranges();
|
||||
verify.referenceGroups(r0, [
|
||||
{ definition: "(local class) C", ranges: [r0] },
|
||||
// TODO: This definition is really ugly
|
||||
{ definition: "(alias) (local class) export=\nimport export=", ranges: [r3] },
|
||||
]);
|
||||
verify.referenceGroups([r1, r5], [
|
||||
{ definition: "class D\n(property) D: typeof D", ranges: [r1, r5, r5] }, // TODO: should only reference r5 once
|
||||
]);
|
||||
verify.referenceGroups(r2, [
|
||||
{ definition: "(local class) D", ranges: [r2] },
|
||||
{ definition: "class D\n(property) D: typeof D", ranges: [r5] },
|
||||
]);
|
||||
verify.referenceGroups([r3, r4], [
|
||||
{ definition: 'module "/a"', ranges: [r4] },
|
||||
{ definition: "(local class) C", ranges: [r0] },
|
||||
{ definition: "(alias) (local class) export=\nimport export=", ranges: [r3] },
|
||||
]);
|
||||
13
tests/cases/fourslash/findAllRefs_importType_named.ts
Normal file
13
tests/cases/fourslash/findAllRefs_importType_named.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
|
||||
////export type [|{| "isWriteAccess": true, "isDefinition": true |}U|] = string;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////const x: import("./a").[|T|] = 0;
|
||||
////const x: import("./a").[|U|] = 0;
|
||||
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
verify.singleReferenceGroup("type T = number", [r0, r2]);
|
||||
verify.singleReferenceGroup("type U = string", [r1, r3]);
|
||||
10
tests/cases/fourslash/findAllRefs_importType_typeofImport.ts
Normal file
10
tests/cases/fourslash/findAllRefs_importType_typeofImport.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export const x = 0;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////const x: typeof import("[|./a|]") = { x: 0 };
|
||||
////const y: typeof import("[|./a|]") = { x: 0 };
|
||||
|
||||
verify.singleReferenceGroup('module "/a"');
|
||||
@ -15,7 +15,7 @@
|
||||
////}
|
||||
|
||||
const [moduleFoo0, f0, moduleBar0, foo0, moduleFoo1, foo1, f1, moduleBar1, foo2] = test.ranges();
|
||||
verify.singleReferenceGroup('module "foo"', [moduleFoo1, moduleFoo0]);
|
||||
verify.singleReferenceGroup('module "bar"', [moduleBar1, moduleBar0]);
|
||||
verify.singleReferenceGroup('module "foo"', [moduleFoo0, moduleFoo1]);
|
||||
verify.singleReferenceGroup('module "bar"', [moduleBar0, moduleBar1]);
|
||||
verify.singleReferenceGroup('(alias) module "foo"\nimport foo = require("foo")', [foo0, foo1, foo2]);
|
||||
verify.singleReferenceGroup("var f: number", [f0, f1]);
|
||||
|
||||
@ -1,16 +1,11 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// Global interface reference.
|
||||
|
||||
// @Filename: referencesForGlobals_1.ts
|
||||
////declare module "[|{| "isWriteAccess": true, "isDefinition": true |}foo|]" {
|
||||
//// var f: number;
|
||||
////}
|
||||
|
||||
|
||||
// @Filename: referencesForGlobals_2.ts
|
||||
////import f = require("[|foo|]");
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
verify.referenceGroups(ranges, [{ definition: 'module "foo"', ranges: [r1, r0] }]);
|
||||
verify.singleReferenceGroup('module "foo"');
|
||||
|
||||
16
tests/cases/fourslash/renameImport.ts
Normal file
16
tests/cases/fourslash/renameImport.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export const x = 0;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import * as a from "[|./a|]";
|
||||
////import a2 = require("[|./a"|]);
|
||||
|
||||
// @Filename: /c.js
|
||||
////const a = require("[|./a|]");
|
||||
|
||||
verify.noErrors();
|
||||
goTo.eachRange(() => { verify.renameInfoFailed(); });
|
||||
Loading…
x
Reference in New Issue
Block a user