mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 00:55:32 -05:00
findAllReferences: Make definition info independent of search location (#21748)
This commit is contained in:
@@ -8,7 +8,7 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export type Definition =
|
||||
| { type: "symbol"; symbol: Symbol; node: Node }
|
||||
| { type: "symbol"; symbol: Symbol }
|
||||
| { type: "label"; node: Identifier }
|
||||
| { type: "keyword"; node: ts.Node }
|
||||
| { type: "this"; node: ts.Node }
|
||||
@@ -42,11 +42,12 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined {
|
||||
const referencedSymbols = findAllReferencedSymbols(program, cancellationToken, sourceFiles, sourceFile, position);
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, /*options*/ {});
|
||||
const checker = program.getTypeChecker();
|
||||
return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined<SymbolAndEntries, ReferencedSymbol>(referencedSymbols, ({ definition, references }) =>
|
||||
// Only include referenced symbols that have a valid definition.
|
||||
definition && { definition: definitionToReferencedSymbolDefinitionInfo(definition, checker), references: references.map(toReferenceEntry) });
|
||||
definition && { definition: definitionToReferencedSymbolDefinitionInfo(definition, checker, node), references: references.map(toReferenceEntry) });
|
||||
}
|
||||
|
||||
export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ImplementationLocation[] {
|
||||
@@ -83,31 +84,26 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function findReferencedEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number, options?: Options): ReferenceEntry[] | undefined {
|
||||
const x = flattenEntries(findAllReferencedSymbols(program, cancellationToken, sourceFiles, sourceFile, position, options));
|
||||
return map(x, toReferenceEntry);
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), toReferenceEntry);
|
||||
}
|
||||
|
||||
export function getReferenceEntriesForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}): Entry[] | undefined {
|
||||
return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options));
|
||||
}
|
||||
|
||||
function findAllReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number, options?: Options): SymbolAndEntries[] | undefined {
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
return Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options);
|
||||
}
|
||||
|
||||
function flattenEntries(referenceSymbols: SymbolAndEntries[]): Entry[] {
|
||||
return referenceSymbols && flatMap(referenceSymbols, r => r.references);
|
||||
}
|
||||
|
||||
function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker): ReferencedSymbolDefinitionInfo | undefined {
|
||||
function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker, originalNode: Node): ReferencedSymbolDefinitionInfo | undefined {
|
||||
const info = (() => {
|
||||
switch (def.type) {
|
||||
case "symbol": {
|
||||
const { symbol, node } = def;
|
||||
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, node, checker);
|
||||
const { symbol } = def;
|
||||
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, checker, originalNode);
|
||||
const name = displayParts.map(p => p.text).join("");
|
||||
return { node, name, kind, displayParts };
|
||||
return { node: symbol.declarations ? getNameOfDeclaration(first(symbol.declarations)) || first(symbol.declarations) : originalNode, name, kind, displayParts };
|
||||
}
|
||||
case "label": {
|
||||
const { node } = def;
|
||||
@@ -129,13 +125,11 @@ namespace ts.FindAllReferences {
|
||||
const { node } = def;
|
||||
return { node, name: node.text, kind: ScriptElementKind.variableElement, displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)] };
|
||||
}
|
||||
default:
|
||||
return Debug.assertNever(def);
|
||||
}
|
||||
})();
|
||||
|
||||
if (!info) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { node, name, kind, displayParts } = info;
|
||||
const sourceFile = node.getSourceFile();
|
||||
return {
|
||||
@@ -149,9 +143,11 @@ namespace ts.FindAllReferences {
|
||||
};
|
||||
}
|
||||
|
||||
function getDefinitionKindAndDisplayParts(symbol: Symbol, node: Node, checker: TypeChecker): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
|
||||
function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
|
||||
const meaning = Core.getIntersectingMeaningFromDeclarations(node, symbol);
|
||||
const enclosingDeclaration = firstOrUndefined(symbol.declarations) || node;
|
||||
const { displayParts, symbolKind } =
|
||||
SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, node.getSourceFile(), getContainerNode(node), node);
|
||||
SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, enclosingDeclaration.getSourceFile(), enclosingDeclaration, enclosingDeclaration, meaning);
|
||||
return { displayParts, kind: symbolKind };
|
||||
}
|
||||
|
||||
@@ -186,7 +182,7 @@ namespace ts.FindAllReferences {
|
||||
function implementationKindDisplayParts(node: ts.Node, checker: ts.TypeChecker): { kind: ScriptElementKind, displayParts: SymbolDisplayPart[] } {
|
||||
const symbol = checker.getSymbolAtLocation(isDeclaration(node) && node.name ? node.name : node);
|
||||
if (symbol) {
|
||||
return getDefinitionKindAndDisplayParts(symbol, node, checker);
|
||||
return getDefinitionKindAndDisplayParts(symbol, checker, node);
|
||||
}
|
||||
else if (node.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return {
|
||||
@@ -317,10 +313,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
}
|
||||
|
||||
return [{
|
||||
definition: { type: "symbol", symbol, node: symbol.valueDeclaration },
|
||||
references
|
||||
}];
|
||||
return [{ definition: { type: "symbol", symbol }, references }];
|
||||
}
|
||||
|
||||
/** getReferencedSymbols for special node kinds. */
|
||||
@@ -357,13 +350,13 @@ namespace ts.FindAllReferences.Core {
|
||||
symbol = skipPastExportOrImportSpecifierOrUnion(symbol, node, checker) || symbol;
|
||||
|
||||
// Compute the meaning from the location and the symbol it references
|
||||
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), symbol.declarations);
|
||||
const searchMeaning = getIntersectingMeaningFromDeclarations(node, symbol);
|
||||
|
||||
const result: SymbolAndEntries[] = [];
|
||||
const state = new State(sourceFiles, getSpecialSearchKind(node), checker, cancellationToken, searchMeaning, options, result);
|
||||
|
||||
if (node.kind === SyntaxKind.DefaultKeyword) {
|
||||
addReference(node, symbol, node, state);
|
||||
addReference(node, symbol, state);
|
||||
searchForImportsOfExport(node, symbol, { exportingModuleSymbol: Debug.assertDefined(symbol.parent, "Expected export symbol to have a parent"), exportKind: ExportKind.Default }, state);
|
||||
}
|
||||
else {
|
||||
@@ -434,7 +427,6 @@ namespace ts.FindAllReferences.Core {
|
||||
/** If coming from an export, we will not recursively search for the imported symbol (since that's where we came from). */
|
||||
readonly comingFrom?: ImportExport;
|
||||
|
||||
readonly location: Node;
|
||||
readonly symbol: Symbol;
|
||||
readonly text: string;
|
||||
readonly escapedText: __String;
|
||||
@@ -514,7 +506,7 @@ namespace ts.FindAllReferences.Core {
|
||||
const escapedText = escapeLeadingUnderscores(text);
|
||||
const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker);
|
||||
return {
|
||||
location, symbol, comingFrom, text, escapedText, parents,
|
||||
symbol, comingFrom, text, escapedText, parents,
|
||||
includes: referenceSymbol => allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol,
|
||||
};
|
||||
}
|
||||
@@ -524,12 +516,12 @@ namespace ts.FindAllReferences.Core {
|
||||
* Callback to add references for a particular searched symbol.
|
||||
* This initializes a reference group, so only call this if you will add at least one reference.
|
||||
*/
|
||||
referenceAdder(searchSymbol: Symbol, searchLocation: Node): (node: Node) => void {
|
||||
referenceAdder(searchSymbol: Symbol): (node: Node) => void {
|
||||
const symbolId = getSymbolId(searchSymbol);
|
||||
let references = this.symbolIdToReferences[symbolId];
|
||||
if (!references) {
|
||||
references = this.symbolIdToReferences[symbolId] = [];
|
||||
this.result.push({ definition: { type: "symbol", symbol: searchSymbol, node: searchLocation }, references });
|
||||
this.result.push({ definition: { type: "symbol", symbol: searchSymbol }, references });
|
||||
}
|
||||
return node => references.push(nodeEntry(node));
|
||||
}
|
||||
@@ -559,7 +551,7 @@ namespace ts.FindAllReferences.Core {
|
||||
|
||||
// For `import { foo as bar }` just add the reference to `foo`, and don't otherwise search in the file.
|
||||
if (singleReferences.length) {
|
||||
const addRef = state.referenceAdder(exportSymbol, exportLocation);
|
||||
const addRef = state.referenceAdder(exportSymbol);
|
||||
for (const singleRef of singleReferences) {
|
||||
addRef(singleRef);
|
||||
}
|
||||
@@ -862,7 +854,7 @@ namespace ts.FindAllReferences.Core {
|
||||
|
||||
switch (state.specialSearchKind) {
|
||||
case SpecialSearchKind.None:
|
||||
addReference(referenceLocation, relatedSymbol, search.location, state);
|
||||
addReference(referenceLocation, relatedSymbol, state);
|
||||
break;
|
||||
case SpecialSearchKind.Constructor:
|
||||
addConstructorReferences(referenceLocation, sourceFile, search, state);
|
||||
@@ -896,7 +888,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
if (!state.options.isForRename && state.markSeenReExportRHS(name)) {
|
||||
addReference(name, referenceSymbol, name, state);
|
||||
addReference(name, referenceSymbol, state);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -920,7 +912,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
function addRef() {
|
||||
addReference(referenceLocation, localSymbol, search.location, state);
|
||||
addReference(referenceLocation, localSymbol, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -969,12 +961,12 @@ namespace ts.FindAllReferences.Core {
|
||||
* position of property accessing, the referenceEntry of such position will be handled in the first case.
|
||||
*/
|
||||
if (!(flags & SymbolFlags.Transient) && search.includes(shorthandValueSymbol)) {
|
||||
addReference(getNameOfDeclaration(valueDeclaration), shorthandValueSymbol, search.location, state);
|
||||
addReference(getNameOfDeclaration(valueDeclaration), shorthandValueSymbol, state);
|
||||
}
|
||||
}
|
||||
|
||||
function addReference(referenceLocation: Node, relatedSymbol: Symbol, searchLocation: Node, state: State): void {
|
||||
const addRef = state.referenceAdder(relatedSymbol, searchLocation);
|
||||
function addReference(referenceLocation: Node, relatedSymbol: Symbol, state: State): void {
|
||||
const addRef = state.referenceAdder(relatedSymbol);
|
||||
if (state.options.implementations) {
|
||||
addImplementationReferences(referenceLocation, addRef, state);
|
||||
}
|
||||
@@ -986,10 +978,10 @@ namespace ts.FindAllReferences.Core {
|
||||
/** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
|
||||
function addConstructorReferences(referenceLocation: Node, sourceFile: SourceFile, search: Search, state: State): void {
|
||||
if (isNewExpressionTarget(referenceLocation)) {
|
||||
addReference(referenceLocation, search.symbol, search.location, state);
|
||||
addReference(referenceLocation, search.symbol, state);
|
||||
}
|
||||
|
||||
const pusher = () => state.referenceAdder(search.symbol, search.location);
|
||||
const pusher = () => state.referenceAdder(search.symbol);
|
||||
|
||||
if (isClassLike(referenceLocation.parent)) {
|
||||
Debug.assert(referenceLocation.kind === SyntaxKind.DefaultKeyword || referenceLocation.parent.name === referenceLocation);
|
||||
@@ -1006,11 +998,11 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
function addClassStaticThisReferences(referenceLocation: Node, search: Search, state: State): void {
|
||||
addReference(referenceLocation, search.symbol, search.location, state);
|
||||
addReference(referenceLocation, search.symbol, state);
|
||||
if (isClassLike(referenceLocation.parent)) {
|
||||
Debug.assert(referenceLocation.parent.name === referenceLocation);
|
||||
// This is the class declaration.
|
||||
addStaticThisReferences(referenceLocation.parent, state.referenceAdder(search.symbol, search.location));
|
||||
addStaticThisReferences(referenceLocation.parent, state.referenceAdder(search.symbol));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1300,7 +1292,7 @@ namespace ts.FindAllReferences.Core {
|
||||
return container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
|
||||
});
|
||||
|
||||
return [{ definition: { type: "symbol", symbol: searchSpaceNode.symbol, node: superKeyword }, references }];
|
||||
return [{ definition: { type: "symbol", symbol: searchSpaceNode.symbol }, references }];
|
||||
}
|
||||
|
||||
function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] {
|
||||
@@ -1645,7 +1637,9 @@ namespace ts.FindAllReferences.Core {
|
||||
* module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module)
|
||||
* do not intersect in any of the three spaces.
|
||||
*/
|
||||
function getIntersectingMeaningFromDeclarations(meaning: SemanticMeaning, declarations: Declaration[]): SemanticMeaning {
|
||||
export function getIntersectingMeaningFromDeclarations(node: Node, symbol: Symbol): SemanticMeaning {
|
||||
let meaning = getMeaningFromLocation(node);
|
||||
const { declarations } = symbol;
|
||||
if (declarations) {
|
||||
let lastIterationMeaning: SemanticMeaning;
|
||||
do {
|
||||
|
||||
Reference in New Issue
Block a user