• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import {
2    __String, addToSeen, append, AssignmentDeclarationKind, BinaryExpression, BindingElement, Block, CallExpression,
3    CancellationToken, cast, CheckFlags, ClassLikeDeclaration, climbPastPropertyAccess, compareValues,
4    ConstructorDeclaration, contains, createQueue, createTextSpan, createTextSpanFromBounds, createTextSpanFromRange,
5    Debug, Declaration, displayPart, DocumentSpan, emptyArray, emptyOptions, escapeLeadingUnderscores, ESMap,
6    ExportSpecifier, Expression, FileIncludeReason, FileReference, filter, find, findAncestor, findChildOfKind,
7    findIndex, first, firstDefined, firstOrUndefined, flatMap, forEachChild, forEachReturnStatement, ForInOrOfStatement,
8    FunctionDeclaration, FunctionExpression, FunctionLikeDeclaration, GetAccessorDeclaration,
9    getAdjustedReferenceLocation, getAdjustedRenameLocation, getAllSuperTypeNodes, getAncestor,
10    getAssignmentDeclarationKind, getCheckFlags, getContainerNode, getContainingObjectLiteralElement,
11    getContextualTypeFromParentOrAncestorTypeNode, getDeclarationFromName, getDeclarationOfKind,
12    getEffectiveModifierFlags, getLocalSymbolForExportDefault, getMeaningFromDeclaration, getMeaningFromLocation,
13    getModeForUsageLocation, getNameOfDeclaration, getNameTable, getNextJSDocCommentLocation, getNodeId, getNodeKind,
14    getPropertySymbolFromBindingElement, getPropertySymbolsFromContextualType, getReferencedFileLocation,
15    getSuperContainer, getSymbolId, getSyntacticModifierFlags, getTargetLabel, getTextOfNode, getThisContainer,
16    getTouchingPropertyName, GoToDefinition, hasEffectiveModifier, hasInitializer, hasSyntacticModifier, hasType,
17    HighlightSpan, HighlightSpanKind, Identifier, ImplementationLocation, InterfaceDeclaration, InternalSymbolName,
18    isAccessExpression, isArrayLiteralOrObjectLiteralDestructuringPattern, isAssertionExpression, isBinaryExpression,
19    isBindableObjectDefinePropertyCall, isBindingElement, isBreakOrContinueStatement, isCallExpression,
20    isCallExpressionTarget, isCatchClause, isClassLike, isClassStaticBlockDeclaration, isComputedPropertyName,
21    isConstructorDeclaration, isDeclaration, isDeclarationName, isExportAssignment, isExportSpecifier,
22    isExpressionOfExternalModuleImportEqualsDeclaration, isExpressionStatement, isExpressionWithTypeArguments,
23    isExternalModule, isExternalModuleSymbol, isExternalOrCommonJsModule, isForInOrOfStatement, isFunctionExpression,
24    isFunctionLike, isFunctionLikeDeclaration, isIdentifier, isIdentifierPart, isImportMeta, isImportOrExportSpecifier,
25    isImportSpecifier, isImportTypeNode, isInJSFile, isInNonReferenceComment, isInString, isInterfaceDeclaration,
26    isJSDocMemberName, isJSDocTag, isJsxClosingElement, isJsxOpeningElement, isJsxSelfClosingElement,
27    isJumpStatementTarget, isLabeledStatement, isLabelOfLabeledStatement, isLiteralComputedPropertyDeclarationName,
28    isLiteralNameOfPropertyDeclarationOrIndexAccess, isLiteralTypeNode, isMethodOrAccessor, isModuleDeclaration,
29    isModuleExportsAccessExpression, isModuleOrEnumDeclaration, isModuleSpecifierLike, isNameOfModuleDeclaration,
30    isNamespaceExportDeclaration, isNewExpressionTarget, isNoSubstitutionTemplateLiteral,
31    isObjectBindingElementWithoutPropertyName, isObjectLiteralExpression, isObjectLiteralMethod, isParameter,
32    isParameterPropertyDeclaration, isPrivateIdentifierClassElementDeclaration, isPropertyAccessExpression,
33    isQualifiedName, isReferencedFile, isReferenceFileLocation, isRightSideOfPropertyAccess,
34    isShorthandPropertyAssignment, isSourceFile, isStatement, isStatic, isStaticModifier, isStringLiteralLike,
35    isSuperProperty, isThis, isTypeAliasDeclaration, isTypeElement, isTypeKeyword, isTypeLiteralNode, isTypeNode,
36    isTypeOperatorNode, isUnionTypeNode, isVariableDeclarationInitializedToBareOrAccessedRequire,
37    isVariableDeclarationList, isVariableLike, isVariableStatement, isVoidExpression, isWriteAccess, JSDocTag, map, Map,
38    mapDefined, MethodDeclaration, ModifierFlags, ModuleDeclaration, MultiMap, NamedDeclaration, Node, NodeFlags,
39    nodeSeenTracker, NumericLiteral, ParameterDeclaration, ParenthesizedExpression, Path, PrivateIdentifier, Program,
40    PropertyAccessExpression, PropertyAssignment, PropertyDeclaration, punctuationPart, Push, rangeIsOnSingleLine,
41    ReadonlySet, ReferencedSymbol, ReferencedSymbolDefinitionInfo, ReferencedSymbolEntry, ReferenceEntry,
42    RenameLocation, ScriptElementKind, ScriptTarget, SemanticMeaning, Set, SetAccessorDeclaration, SignatureDeclaration,
43    skipAlias, some, SourceFile, Statement, StringLiteral, StringLiteralLike, stripQuotes, Symbol, SymbolDisplay,
44    SymbolDisplayPart, SymbolDisplayPartKind, SymbolFlags, SymbolId, symbolName, SyntaxKind, textPart, TextSpan,
45    tokenToString, tryAddToSet, tryCast, tryGetClassExtendingExpressionWithTypeArguments,
46    tryGetImportFromModuleSpecifier, TypeChecker, VariableDeclaration,
47} from "./_namespaces/ts";
48import {
49    createImportTracker, ExportInfo, ExportKind, findModuleReferences, getExportInfo, getImportOrExportSymbol,
50    ImportExport, ImportsResult, ImportTracker, ModuleReference,
51} from "./_namespaces/ts.FindAllReferences";
52
53/** @internal */
54export interface SymbolAndEntries {
55    readonly definition: Definition | undefined;
56    readonly references: readonly Entry[];
57}
58
59/** @internal */
60export const enum DefinitionKind { Symbol, Label, Keyword, This, String, TripleSlashReference }
61/** @internal */
62export type Definition =
63    | { readonly type: DefinitionKind.Symbol; readonly symbol: Symbol }
64    | { readonly type: DefinitionKind.Label; readonly node: Identifier }
65    | { readonly type: DefinitionKind.Keyword; readonly node: Node }
66    | { readonly type: DefinitionKind.This; readonly node: Node }
67    | { readonly type: DefinitionKind.String; readonly node: StringLiteralLike }
68    | { readonly type: DefinitionKind.TripleSlashReference; readonly reference: FileReference, readonly file: SourceFile };
69
70/** @internal */
71export const enum EntryKind { Span, Node, StringLiteral, SearchedLocalFoundProperty, SearchedPropertyFoundLocal }
72/** @internal */
73export type NodeEntryKind = EntryKind.Node | EntryKind.StringLiteral | EntryKind.SearchedLocalFoundProperty | EntryKind.SearchedPropertyFoundLocal;
74/** @internal */
75export type Entry = NodeEntry | SpanEntry;
76/** @internal */
77export interface ContextWithStartAndEndNode {
78    start: Node;
79    end: Node;
80}
81/** @internal */
82export type ContextNode = Node | ContextWithStartAndEndNode;
83/** @internal */
84export interface NodeEntry {
85    readonly kind: NodeEntryKind;
86    readonly node: Node;
87    readonly context?: ContextNode;
88}
89/** @internal */
90export interface SpanEntry {
91    readonly kind: EntryKind.Span;
92    readonly fileName: string;
93    readonly textSpan: TextSpan;
94}
95/** @internal */
96export function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): NodeEntry {
97    return {
98        kind,
99        node: (node as NamedDeclaration).name || node,
100        context: getContextNodeForNodeEntry(node)
101    };
102}
103
104/** @internal */
105export function isContextWithStartAndEndNode(node: ContextNode): node is ContextWithStartAndEndNode {
106    return node && (node as Node).kind === undefined;
107}
108
109function getContextNodeForNodeEntry(node: Node): ContextNode | undefined {
110    if (isDeclaration(node)) {
111        return getContextNode(node);
112    }
113
114    if (!node.parent) return undefined;
115
116    if (!isDeclaration(node.parent) && !isExportAssignment(node.parent)) {
117        // Special property assignment in javascript
118        if (isInJSFile(node)) {
119            const binaryExpression = isBinaryExpression(node.parent) ?
120                node.parent :
121                isAccessExpression(node.parent) &&
122                    isBinaryExpression(node.parent.parent) &&
123                    node.parent.parent.left === node.parent ?
124                    node.parent.parent :
125                    undefined;
126            if (binaryExpression && getAssignmentDeclarationKind(binaryExpression) !== AssignmentDeclarationKind.None) {
127                return getContextNode(binaryExpression);
128            }
129        }
130
131        // Jsx Tags
132        if (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) {
133            return node.parent.parent;
134        }
135        else if (isJsxSelfClosingElement(node.parent) ||
136            isLabeledStatement(node.parent) ||
137            isBreakOrContinueStatement(node.parent)) {
138            return node.parent;
139        }
140        else if (isStringLiteralLike(node)) {
141            const validImport = tryGetImportFromModuleSpecifier(node);
142            if (validImport) {
143                const declOrStatement = findAncestor(validImport, node =>
144                    isDeclaration(node) ||
145                    isStatement(node) ||
146                    isJSDocTag(node)
147                )! as NamedDeclaration | Statement | JSDocTag;
148                return isDeclaration(declOrStatement) ?
149                    getContextNode(declOrStatement) :
150                    declOrStatement;
151            }
152        }
153
154        // Handle computed property name
155        const propertyName = findAncestor(node, isComputedPropertyName);
156        return propertyName ?
157            getContextNode(propertyName.parent) :
158            undefined;
159    }
160
161    if (node.parent.name === node || // node is name of declaration, use parent
162        isConstructorDeclaration(node.parent) ||
163        isExportAssignment(node.parent) ||
164        // Property name of the import export specifier or binding pattern, use parent
165        ((isImportOrExportSpecifier(node.parent) || isBindingElement(node.parent))
166            && node.parent.propertyName === node) ||
167        // Is default export
168        (node.kind === SyntaxKind.DefaultKeyword && hasSyntacticModifier(node.parent, ModifierFlags.ExportDefault))) {
169        return getContextNode(node.parent);
170    }
171
172    return undefined;
173}
174
175/** @internal */
176export function getContextNode(node: NamedDeclaration | BinaryExpression | ForInOrOfStatement | undefined): ContextNode | undefined {
177    if (!node) return undefined;
178    switch (node.kind) {
179        case SyntaxKind.VariableDeclaration:
180            return !isVariableDeclarationList(node.parent) || node.parent.declarations.length !== 1 ?
181                node :
182                isVariableStatement(node.parent.parent) ?
183                    node.parent.parent :
184                    isForInOrOfStatement(node.parent.parent) ?
185                        getContextNode(node.parent.parent) :
186                        node.parent;
187
188        case SyntaxKind.BindingElement:
189            return getContextNode(node.parent.parent as NamedDeclaration);
190
191        case SyntaxKind.ImportSpecifier:
192            return node.parent.parent.parent;
193
194        case SyntaxKind.ExportSpecifier:
195        case SyntaxKind.NamespaceImport:
196            return node.parent.parent;
197
198        case SyntaxKind.ImportClause:
199        case SyntaxKind.NamespaceExport:
200            return node.parent;
201
202        case SyntaxKind.BinaryExpression:
203            return isExpressionStatement(node.parent) ?
204                node.parent :
205                node;
206
207        case SyntaxKind.ForOfStatement:
208        case SyntaxKind.ForInStatement:
209            return {
210                start: (node as ForInOrOfStatement).initializer,
211                end: (node as ForInOrOfStatement).expression
212            };
213
214        case SyntaxKind.PropertyAssignment:
215        case SyntaxKind.ShorthandPropertyAssignment:
216            return isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) ?
217                getContextNode(
218                    findAncestor(node.parent, node =>
219                        isBinaryExpression(node) || isForInOrOfStatement(node)
220                    ) as BinaryExpression | ForInOrOfStatement
221                ) :
222                node;
223
224        default:
225            return node;
226    }
227}
228
229/** @internal */
230export function toContextSpan(textSpan: TextSpan, sourceFile: SourceFile, context?: ContextNode): { contextSpan: TextSpan } | undefined {
231    if (!context) return undefined;
232    const contextSpan = isContextWithStartAndEndNode(context) ?
233        getTextSpan(context.start, sourceFile, context.end) :
234        getTextSpan(context, sourceFile);
235    return contextSpan.start !== textSpan.start || contextSpan.length !== textSpan.length ?
236        { contextSpan } :
237        undefined;
238}
239
240/** @internal */
241export const enum FindReferencesUse {
242    /**
243     * When searching for references to a symbol, the location will not be adjusted (this is the default behavior when not specified).
244     */
245    Other,
246    /**
247     * When searching for references to a symbol, the location will be adjusted if the cursor was on a keyword.
248     */
249    References,
250    /**
251     * When searching for references to a symbol, the location will be adjusted if the cursor was on a keyword.
252     * Unlike `References`, the location will only be adjusted keyword belonged to a declaration with a valid name.
253     * If set, we will find fewer references -- if it is referenced by several different names, we still only find references for the original name.
254     */
255    Rename,
256}
257
258/** @internal */
259export interface Options {
260    readonly findInStrings?: boolean;
261    readonly findInComments?: boolean;
262    readonly use?: FindReferencesUse;
263    /** True if we are searching for implementations. We will have a different method of adding references if so. */
264    readonly implementations?: boolean;
265    /**
266     * True to opt in for enhanced renaming of shorthand properties and import/export specifiers.
267     * The options controls the behavior for the whole rename operation; it cannot be changed on a per-file basis.
268     * Default is false for backwards compatibility.
269     */
270    readonly providePrefixAndSuffixTextForRename?: boolean;
271}
272
273/** @internal */
274export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined {
275    const node = getTouchingPropertyName(sourceFile, position);
276    const options = { use: FindReferencesUse.References };
277    const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options);
278    const checker = program.getTypeChecker();
279    // Unless the starting node is a declaration (vs e.g. JSDoc), don't attempt to compute isDefinition
280    const adjustedNode = Core.getAdjustedNode(node, options);
281    const symbol = isDefinitionForReference(adjustedNode) ? checker.getSymbolAtLocation(adjustedNode) : undefined;
282    return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined<SymbolAndEntries, ReferencedSymbol>(referencedSymbols, ({ definition, references }) =>
283        // Only include referenced symbols that have a valid definition.
284        definition && {
285            definition: checker.runWithCancellationToken(cancellationToken, checker => definitionToReferencedSymbolDefinitionInfo(definition, checker, node)),
286            references: references.map(r => toReferencedSymbolEntry(r, symbol))
287        });
288}
289
290function isDefinitionForReference(node: Node): boolean {
291    return node.kind === SyntaxKind.DefaultKeyword
292        || !!getDeclarationFromName(node)
293        || isLiteralComputedPropertyDeclarationName(node)
294        || (node.kind === SyntaxKind.ConstructorKeyword && isConstructorDeclaration(node.parent));
295}
296
297/** @internal */
298export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ImplementationLocation[] | undefined {
299    const node = getTouchingPropertyName(sourceFile, position);
300    let referenceEntries: Entry[] | undefined;
301    const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node, position);
302
303    if (
304        node.parent.kind === SyntaxKind.PropertyAccessExpression
305        || node.parent.kind === SyntaxKind.BindingElement
306        || node.parent.kind === SyntaxKind.ElementAccessExpression
307        || node.kind === SyntaxKind.SuperKeyword
308    ) {
309        referenceEntries = entries && [...entries];
310    }
311    else if (entries) {
312        const queue = createQueue(entries);
313        const seenNodes = new Map<number, true>();
314        while (!queue.isEmpty()) {
315            const entry = queue.dequeue() as NodeEntry;
316            if (!addToSeen(seenNodes, getNodeId(entry.node))) {
317                continue;
318            }
319            referenceEntries = append(referenceEntries, entry);
320            const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, entry.node, entry.node.pos);
321            if (entries) {
322                queue.enqueue(...entries);
323            }
324        }
325    }
326    const checker = program.getTypeChecker();
327    return map(referenceEntries, entry => toImplementationLocation(entry, checker));
328}
329
330function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], node: Node, position: number): readonly Entry[] | undefined {
331    if (node.kind === SyntaxKind.SourceFile) {
332        return undefined;
333    }
334
335    const checker = program.getTypeChecker();
336    // If invoked directly on a shorthand property assignment, then return
337    // the declaration of the symbol being assigned (not the symbol being assigned to).
338    if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
339        const result: NodeEntry[] = [];
340        Core.getReferenceEntriesForShorthandPropertyAssignment(node, checker, node => result.push(nodeEntry(node)));
341        return result;
342    }
343    else if (node.kind === SyntaxKind.SuperKeyword || isSuperProperty(node.parent)) {
344        // References to and accesses on the super keyword only have one possible implementation, so no
345        // need to "Find all References"
346        const symbol = checker.getSymbolAtLocation(node)!;
347        return symbol.valueDeclaration && [nodeEntry(symbol.valueDeclaration)];
348    }
349    else {
350        // Perform "Find all References" and retrieve only those that are implementations
351        return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { implementations: true, use: FindReferencesUse.References });
352    }
353}
354
355/** @internal */
356export function findReferenceOrRenameEntries<T>(
357    program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], node: Node, position: number, options: Options | undefined,
358    convertEntry: ToReferenceOrRenameEntry<T>,
359): T[] | undefined {
360    return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), entry => convertEntry(entry, node, program.getTypeChecker()));
361}
362
363/** @internal */
364export type ToReferenceOrRenameEntry<T> = (entry: Entry, originalNode: Node, checker: TypeChecker) => T;
365
366/** @internal */
367export function getReferenceEntriesForNode(
368    position: number,
369    node: Node,
370    program: Program,
371    sourceFiles: readonly SourceFile[],
372    cancellationToken: CancellationToken,
373    options: Options = {},
374    sourceFilesSet: ReadonlySet<string> = new Set(sourceFiles.map(f => f.fileName)),
375): readonly Entry[] | undefined {
376    return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options, sourceFilesSet));
377}
378
379function flattenEntries(referenceSymbols: readonly SymbolAndEntries[] | undefined): readonly Entry[] | undefined {
380    return referenceSymbols && flatMap(referenceSymbols, r => r.references);
381}
382
383function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker, originalNode: Node): ReferencedSymbolDefinitionInfo {
384    const info = ((): { sourceFile: SourceFile, textSpan: TextSpan, name: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], context?: Node | ContextWithStartAndEndNode } => {
385        switch (def.type) {
386            case DefinitionKind.Symbol: {
387                const { symbol } = def;
388                const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, checker, originalNode);
389                const name = displayParts.map(p => p.text).join("");
390                const declaration = symbol.declarations && firstOrUndefined(symbol.declarations);
391                const node = declaration ? (getNameOfDeclaration(declaration) || declaration) : originalNode;
392                return {
393                    ...getFileAndTextSpanFromNode(node),
394                    name,
395                    kind,
396                    displayParts,
397                    context: getContextNode(declaration)
398                };
399            }
400            case DefinitionKind.Label: {
401                const { node } = def;
402                return { ...getFileAndTextSpanFromNode(node), name: node.text, kind: ScriptElementKind.label, displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)] };
403            }
404            case DefinitionKind.Keyword: {
405                const { node } = def;
406                const name = tokenToString(node.kind)!;
407                return { ...getFileAndTextSpanFromNode(node), name, kind: ScriptElementKind.keyword, displayParts: [{ text: name, kind: ScriptElementKind.keyword }] };
408            }
409            case DefinitionKind.This: {
410                const { node } = def;
411                const symbol = checker.getSymbolAtLocation(node);
412                const displayParts = symbol && SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(
413                    checker, symbol, node.getSourceFile(), getContainerNode(node), node).displayParts || [textPart("this")];
414                return { ...getFileAndTextSpanFromNode(node), name: "this", kind: ScriptElementKind.variableElement, displayParts };
415            }
416            case DefinitionKind.String: {
417                const { node } = def;
418                return {
419                    ...getFileAndTextSpanFromNode(node),
420                    name: node.text,
421                    kind: ScriptElementKind.variableElement,
422                    displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)]
423                };
424            }
425            case DefinitionKind.TripleSlashReference: {
426                return {
427                    textSpan: createTextSpanFromRange(def.reference),
428                    sourceFile: def.file,
429                    name: def.reference.fileName,
430                    kind: ScriptElementKind.string,
431                    displayParts: [displayPart(`"${def.reference.fileName}"`, SymbolDisplayPartKind.stringLiteral)]
432                };
433            }
434            default:
435                return Debug.assertNever(def);
436        }
437    })();
438
439    const { sourceFile, textSpan, name, kind, displayParts, context } = info;
440    return {
441        containerKind: ScriptElementKind.unknown,
442        containerName: "",
443        fileName: sourceFile.fileName,
444        kind,
445        name,
446        textSpan,
447        displayParts,
448        ...toContextSpan(textSpan, sourceFile, context)
449    };
450}
451
452function getFileAndTextSpanFromNode(node: Node) {
453    const sourceFile = node.getSourceFile();
454    return {
455        sourceFile,
456        textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile)
457    };
458}
459
460function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
461    const meaning = Core.getIntersectingMeaningFromDeclarations(node, symbol);
462    const enclosingDeclaration = symbol.declarations && firstOrUndefined(symbol.declarations) || node;
463    const { displayParts, symbolKind } =
464        SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, enclosingDeclaration.getSourceFile(), enclosingDeclaration, enclosingDeclaration, meaning);
465    return { displayParts, kind: symbolKind };
466}
467
468/** @internal */
469export function toRenameLocation(entry: Entry, originalNode: Node, checker: TypeChecker, providePrefixAndSuffixText: boolean): RenameLocation {
470    return { ...entryToDocumentSpan(entry), ...(providePrefixAndSuffixText && getPrefixAndSuffixText(entry, originalNode, checker)) };
471}
472
473function toReferencedSymbolEntry(entry: Entry, symbol: Symbol | undefined): ReferencedSymbolEntry {
474    const referenceEntry = toReferenceEntry(entry);
475    if (!symbol) return referenceEntry;
476    return {
477        ...referenceEntry,
478        isDefinition: entry.kind !== EntryKind.Span && isDeclarationOfSymbol(entry.node, symbol)
479    };
480}
481
482/** @internal */
483export function toReferenceEntry(entry: Entry): ReferenceEntry {
484    const documentSpan = entryToDocumentSpan(entry);
485    if (entry.kind === EntryKind.Span) {
486        return { ...documentSpan, isWriteAccess: false };
487    }
488    const { kind, node } = entry;
489    return {
490        ...documentSpan,
491        isWriteAccess: isWriteAccessForReference(node),
492        isInString: kind === EntryKind.StringLiteral ? true : undefined,
493    };
494}
495
496function entryToDocumentSpan(entry: Entry): DocumentSpan {
497    if (entry.kind === EntryKind.Span) {
498        return { textSpan: entry.textSpan, fileName: entry.fileName };
499    }
500    else {
501        const sourceFile = entry.node.getSourceFile();
502        const textSpan = getTextSpan(entry.node, sourceFile);
503        return {
504            textSpan,
505            fileName: sourceFile.fileName,
506            ...toContextSpan(textSpan, sourceFile, entry.context)
507        };
508    }
509}
510
511interface PrefixAndSuffix { readonly prefixText?: string; readonly suffixText?: string; }
512function getPrefixAndSuffixText(entry: Entry, originalNode: Node, checker: TypeChecker): PrefixAndSuffix {
513    if (entry.kind !== EntryKind.Span && isIdentifier(originalNode)) {
514        const { node, kind } = entry;
515        const parent = node.parent;
516        const name = originalNode.text;
517        const isShorthandAssignment = isShorthandPropertyAssignment(parent);
518        if (isShorthandAssignment || (isObjectBindingElementWithoutPropertyName(parent) && parent.name === node && parent.dotDotDotToken === undefined)) {
519            const prefixColon: PrefixAndSuffix = { prefixText: name + ": " };
520            const suffixColon: PrefixAndSuffix = { suffixText: ": " + name };
521            if (kind === EntryKind.SearchedLocalFoundProperty) {
522                return prefixColon;
523            }
524            if (kind === EntryKind.SearchedPropertyFoundLocal) {
525                return suffixColon;
526            }
527
528            // In `const o = { x }; o.x`, symbolAtLocation at `x` in `{ x }` is the property symbol.
529            // For a binding element `const { x } = o;`, symbolAtLocation at `x` is the property symbol.
530            if (isShorthandAssignment) {
531                const grandParent = parent.parent;
532                if (isObjectLiteralExpression(grandParent) &&
533                    isBinaryExpression(grandParent.parent) &&
534                    isModuleExportsAccessExpression(grandParent.parent.left)) {
535                    return prefixColon;
536                }
537                return suffixColon;
538            }
539            else {
540                return prefixColon;
541            }
542        }
543        else if (isImportSpecifier(parent) && !parent.propertyName) {
544            // If the original symbol was using this alias, just rename the alias.
545            const originalSymbol = isExportSpecifier(originalNode.parent) ? checker.getExportSpecifierLocalTargetSymbol(originalNode.parent) : checker.getSymbolAtLocation(originalNode);
546            return contains(originalSymbol!.declarations, parent) ? { prefixText: name + " as " } : emptyOptions;
547        }
548        else if (isExportSpecifier(parent) && !parent.propertyName) {
549            // If the symbol for the node is same as declared node symbol use prefix text
550            return originalNode === entry.node || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) ?
551                { prefixText: name + " as " } :
552                { suffixText: " as " + name };
553        }
554    }
555
556    return emptyOptions;
557}
558
559function toImplementationLocation(entry: Entry, checker: TypeChecker): ImplementationLocation {
560    const documentSpan = entryToDocumentSpan(entry);
561    if (entry.kind !== EntryKind.Span) {
562        const { node } = entry;
563        return {
564            ...documentSpan,
565            ...implementationKindDisplayParts(node, checker)
566        };
567    }
568    else {
569        return { ...documentSpan, kind: ScriptElementKind.unknown, displayParts: [] };
570    }
571}
572
573function implementationKindDisplayParts(node: Node, checker: TypeChecker): { kind: ScriptElementKind, displayParts: SymbolDisplayPart[] } {
574    const symbol = checker.getSymbolAtLocation(isDeclaration(node) && node.name ? node.name : node);
575    if (symbol) {
576        return getDefinitionKindAndDisplayParts(symbol, checker, node);
577    }
578    else if (node.kind === SyntaxKind.ObjectLiteralExpression) {
579        return {
580            kind: ScriptElementKind.interfaceElement,
581            displayParts: [punctuationPart(SyntaxKind.OpenParenToken), textPart("object literal"), punctuationPart(SyntaxKind.CloseParenToken)]
582        };
583    }
584    else if (node.kind === SyntaxKind.ClassExpression) {
585        return {
586            kind: ScriptElementKind.localClassElement,
587            displayParts: [punctuationPart(SyntaxKind.OpenParenToken), textPart("anonymous local class"), punctuationPart(SyntaxKind.CloseParenToken)]
588        };
589    }
590    else {
591        return { kind: getNodeKind(node), displayParts: [] };
592    }
593}
594
595/** @internal */
596export function toHighlightSpan(entry: Entry): { fileName: string, span: HighlightSpan } {
597    const documentSpan = entryToDocumentSpan(entry);
598    if (entry.kind === EntryKind.Span) {
599        return {
600            fileName: documentSpan.fileName,
601            span: {
602                textSpan: documentSpan.textSpan,
603                kind: HighlightSpanKind.reference
604            }
605        };
606    }
607
608    const writeAccess = isWriteAccessForReference(entry.node);
609    const span: HighlightSpan = {
610        textSpan: documentSpan.textSpan,
611        kind: writeAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference,
612        isInString: entry.kind === EntryKind.StringLiteral ? true : undefined,
613        ...documentSpan.contextSpan && { contextSpan: documentSpan.contextSpan }
614    };
615    return { fileName: documentSpan.fileName, span };
616}
617
618function getTextSpan(node: Node, sourceFile: SourceFile, endNode?: Node): TextSpan {
619    let start = node.getStart(sourceFile);
620    let end = (endNode || node).getEnd();
621    if (isStringLiteralLike(node) && (end - start) > 2) {
622        Debug.assert(endNode === undefined);
623        start += 1;
624        end -= 1;
625    }
626    return createTextSpanFromBounds(start, end);
627}
628
629/** @internal */
630export function getTextSpanOfEntry(entry: Entry) {
631    return entry.kind === EntryKind.Span ? entry.textSpan :
632        getTextSpan(entry.node, entry.node.getSourceFile());
633}
634
635/** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */
636function isWriteAccessForReference(node: Node): boolean {
637    const decl = getDeclarationFromName(node);
638    return !!decl && declarationIsWriteAccess(decl) || node.kind === SyntaxKind.DefaultKeyword || isWriteAccess(node);
639}
640
641/**
642 * Whether a reference, `node`, is a definition of the `target` symbol
643 *
644 * @internal
645 */
646export function isDeclarationOfSymbol(node: Node, target: Symbol | undefined): boolean {
647    if (!target) return false;
648    const source = getDeclarationFromName(node) ||
649        (node.kind === SyntaxKind.DefaultKeyword ? node.parent
650        : isLiteralComputedPropertyDeclarationName(node) ? node.parent.parent
651        : node.kind === SyntaxKind.ConstructorKeyword && isConstructorDeclaration(node.parent) ? node.parent.parent
652        : undefined);
653    const commonjsSource = source && isBinaryExpression(source) ? source.left as unknown as Declaration : undefined;
654    return !!(source && target.declarations?.some(d => d === source || d === commonjsSource));
655}
656
657/**
658 * True if 'decl' provides a value, as in `function f() {}`;
659 * false if 'decl' is just a location for a future write, as in 'let x;'
660 */
661function declarationIsWriteAccess(decl: Declaration): boolean {
662    // Consider anything in an ambient declaration to be a write access since it may be coming from JS.
663    if (!!(decl.flags & NodeFlags.Ambient)) return true;
664
665    switch (decl.kind) {
666        case SyntaxKind.BinaryExpression:
667        case SyntaxKind.BindingElement:
668        case SyntaxKind.ClassDeclaration:
669        case SyntaxKind.ClassExpression:
670        case SyntaxKind.StructDeclaration:
671        case SyntaxKind.DefaultKeyword:
672        case SyntaxKind.EnumDeclaration:
673        case SyntaxKind.EnumMember:
674        case SyntaxKind.ExportSpecifier:
675        case SyntaxKind.ImportClause: // default import
676        case SyntaxKind.ImportEqualsDeclaration:
677        case SyntaxKind.ImportSpecifier:
678        case SyntaxKind.InterfaceDeclaration:
679        case SyntaxKind.JSDocCallbackTag:
680        case SyntaxKind.JSDocTypedefTag:
681        case SyntaxKind.JsxAttribute:
682        case SyntaxKind.ModuleDeclaration:
683        case SyntaxKind.NamespaceExportDeclaration:
684        case SyntaxKind.NamespaceImport:
685        case SyntaxKind.NamespaceExport:
686        case SyntaxKind.Parameter:
687        case SyntaxKind.ShorthandPropertyAssignment:
688        case SyntaxKind.TypeAliasDeclaration:
689        case SyntaxKind.TypeParameter:
690            return true;
691
692        case SyntaxKind.PropertyAssignment:
693            // In `({ x: y } = 0);`, `x` is not a write access. (Won't call this function for `y`.)
694            return !isArrayLiteralOrObjectLiteralDestructuringPattern((decl as PropertyAssignment).parent);
695
696        case SyntaxKind.FunctionDeclaration:
697        case SyntaxKind.FunctionExpression:
698        case SyntaxKind.Constructor:
699        case SyntaxKind.MethodDeclaration:
700        case SyntaxKind.GetAccessor:
701        case SyntaxKind.SetAccessor:
702            return !!(decl as FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration).body;
703
704        case SyntaxKind.VariableDeclaration:
705        case SyntaxKind.PropertyDeclaration:
706            return !!(decl as VariableDeclaration | PropertyDeclaration).initializer || isCatchClause(decl.parent);
707
708        case SyntaxKind.MethodSignature:
709        case SyntaxKind.PropertySignature:
710        case SyntaxKind.JSDocPropertyTag:
711        case SyntaxKind.JSDocParameterTag:
712            return false;
713
714        default:
715            return Debug.failBadSyntaxKind(decl);
716    }
717}
718
719/**
720 * @internal
721 * Encapsulates the core find-all-references algorithm.
722 */
723export namespace Core {
724    /** Core find-all-references algorithm. Handles special cases before delegating to `getReferencedSymbolsForSymbol`. */
725    export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlySet<string> = new Set(sourceFiles.map(f => f.fileName))): readonly SymbolAndEntries[] | undefined {
726        node = getAdjustedNode(node, options);
727        if (isSourceFile(node)) {
728            const resolvedRef = GoToDefinition.getReferenceAtPosition(node, position, program);
729            if (!resolvedRef?.file) {
730                return undefined;
731            }
732            const moduleSymbol = program.getTypeChecker().getMergedSymbol(resolvedRef.file.symbol);
733            if (moduleSymbol) {
734                return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
735            }
736            const fileIncludeReasons = program.getFileIncludeReasons();
737            if (!fileIncludeReasons) {
738                return undefined;
739            }
740            return [{
741                definition: { type: DefinitionKind.TripleSlashReference, reference: resolvedRef.reference, file: node },
742                references: getReferencesForNonModule(resolvedRef.file, fileIncludeReasons, program) || emptyArray
743            }];
744        }
745
746        if (!options.implementations) {
747            const special = getReferencedSymbolsSpecial(node, sourceFiles, cancellationToken);
748            if (special) {
749                return special;
750            }
751        }
752
753        const checker = program.getTypeChecker();
754        // constructors should use the class symbol, detected by name, if present
755        const symbol = checker.getSymbolAtLocation(isConstructorDeclaration(node) && node.parent.name || node);
756
757        // Could not find a symbol e.g. unknown identifier
758        if (!symbol) {
759            // String literal might be a property (and thus have a symbol), so do this here rather than in getReferencedSymbolsSpecial.
760            if (!options.implementations && isStringLiteralLike(node)) {
761                if (isModuleSpecifierLike(node)) {
762                    const fileIncludeReasons = program.getFileIncludeReasons();
763                    const referencedFileName = node.getSourceFile().resolvedModules?.get(node.text, getModeForUsageLocation(node.getSourceFile(), node))?.resolvedFileName;
764                    const referencedFile = referencedFileName ? program.getSourceFile(referencedFileName) : undefined;
765                    if (referencedFile) {
766                        return [{ definition: { type: DefinitionKind.String, node }, references: getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray }];
767                    }
768                    // Fall through to string literal references. This is not very likely to return
769                    // anything useful, but I guess it's better than nothing, and there's an existing
770                    // test that expects this to happen (fourslash/cases/untypedModuleImport.ts).
771                }
772                return getReferencesForStringLiteral(node, sourceFiles, checker, cancellationToken);
773            }
774            return undefined;
775        }
776
777        if (symbol.escapedName === InternalSymbolName.ExportEquals) {
778            return getReferencedSymbolsForModule(program, symbol.parent!, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
779        }
780
781        const moduleReferences = getReferencedSymbolsForModuleIfDeclaredBySourceFile(symbol, program, sourceFiles, cancellationToken, options, sourceFilesSet);
782        if (moduleReferences && !(symbol.flags & SymbolFlags.Transient)) {
783            return moduleReferences;
784        }
785
786        const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration(node, symbol, checker);
787        const moduleReferencesOfExportTarget = aliasedSymbol &&
788            getReferencedSymbolsForModuleIfDeclaredBySourceFile(aliasedSymbol, program, sourceFiles, cancellationToken, options, sourceFilesSet);
789
790        const references = getReferencedSymbolsForSymbol(symbol, node, sourceFiles, sourceFilesSet, checker, cancellationToken, options);
791        return mergeReferences(program, moduleReferences, references, moduleReferencesOfExportTarget);
792    }
793
794    export function getAdjustedNode(node: Node, options: Options) {
795        if (options.use === FindReferencesUse.References) {
796            node = getAdjustedReferenceLocation(node);
797        }
798        else if (options.use === FindReferencesUse.Rename) {
799            node = getAdjustedRenameLocation(node);
800        }
801        return node;
802    }
803
804    export function getReferencesForFileName(fileName: string, program: Program, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet<string> = new Set(sourceFiles.map(f => f.fileName))): readonly Entry[] {
805        const moduleSymbol = program.getSourceFile(fileName)?.symbol;
806        if (moduleSymbol) {
807            return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet)[0]?.references || emptyArray;
808        }
809        const fileIncludeReasons = program.getFileIncludeReasons();
810        const referencedFile = program.getSourceFile(fileName);
811        return referencedFile && fileIncludeReasons && getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray;
812    }
813
814    function getReferencesForNonModule(referencedFile: SourceFile, refFileMap: MultiMap<Path, FileIncludeReason>, program: Program): readonly SpanEntry[] | undefined {
815        let entries: SpanEntry[] | undefined;
816        const references = refFileMap.get(referencedFile.path) || emptyArray;
817        for (const ref of references) {
818            if (isReferencedFile(ref)) {
819                const referencingFile = program.getSourceFileByPath(ref.file)!;
820                const location = getReferencedFileLocation(program.getSourceFileByPath, ref);
821                if (isReferenceFileLocation(location)) {
822                    entries = append(entries, {
823                        kind: EntryKind.Span,
824                        fileName: referencingFile.fileName,
825                        textSpan: createTextSpanFromRange(location)
826                    });
827                }
828            }
829        }
830        return entries;
831    }
832
833    function getMergedAliasedSymbolOfNamespaceExportDeclaration(node: Node, symbol: Symbol, checker: TypeChecker) {
834        if (node.parent && isNamespaceExportDeclaration(node.parent)) {
835            const aliasedSymbol = checker.getAliasedSymbol(symbol);
836            const targetSymbol = checker.getMergedSymbol(aliasedSymbol);
837            if (aliasedSymbol !== targetSymbol) {
838                return targetSymbol;
839            }
840        }
841        return undefined;
842    }
843
844    function getReferencedSymbolsForModuleIfDeclaredBySourceFile(symbol: Symbol, program: Program, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken, options: Options, sourceFilesSet: ReadonlySet<string>) {
845        const moduleSourceFile = (symbol.flags & SymbolFlags.Module) && symbol.declarations && find(symbol.declarations, isSourceFile);
846        if (!moduleSourceFile) return undefined;
847        const exportEquals = symbol.exports!.get(InternalSymbolName.ExportEquals);
848        // If !!exportEquals, we're about to add references to `import("mod")` anyway, so don't double-count them.
849        const moduleReferences = getReferencedSymbolsForModule(program, symbol, !!exportEquals, sourceFiles, sourceFilesSet);
850        if (!exportEquals || !sourceFilesSet.has(moduleSourceFile.fileName)) return moduleReferences;
851        // Continue to get references to 'export ='.
852        const checker = program.getTypeChecker();
853        symbol = skipAlias(exportEquals, checker);
854        return mergeReferences(program, moduleReferences, getReferencedSymbolsForSymbol(symbol, /*node*/ undefined, sourceFiles, sourceFilesSet, checker, cancellationToken, options));
855    }
856
857    /**
858     * Merges the references by sorting them (by file index in sourceFiles and their location in it) that point to same definition symbol
859     */
860    function mergeReferences(program: Program, ...referencesToMerge: (SymbolAndEntries[] | undefined)[]): SymbolAndEntries[] | undefined {
861        let result: SymbolAndEntries[] | undefined;
862        for (const references of referencesToMerge) {
863            if (!references || !references.length) continue;
864            if (!result) {
865                result = references;
866                continue;
867            }
868            for (const entry of references) {
869                if (!entry.definition || entry.definition.type !== DefinitionKind.Symbol) {
870                    result.push(entry);
871                    continue;
872                }
873                const symbol = entry.definition.symbol;
874                const refIndex = findIndex(result, ref => !!ref.definition &&
875                    ref.definition.type === DefinitionKind.Symbol &&
876                    ref.definition.symbol === symbol);
877                if (refIndex === -1) {
878                    result.push(entry);
879                    continue;
880                }
881
882                const reference = result[refIndex];
883                result[refIndex] = {
884                    definition: reference.definition,
885                    references: reference.references.concat(entry.references).sort((entry1, entry2) => {
886                        const entry1File = getSourceFileIndexOfEntry(program, entry1);
887                        const entry2File = getSourceFileIndexOfEntry(program, entry2);
888                        if (entry1File !== entry2File) {
889                            return compareValues(entry1File, entry2File);
890                        }
891
892                        const entry1Span = getTextSpanOfEntry(entry1);
893                        const entry2Span = getTextSpanOfEntry(entry2);
894                        return entry1Span.start !== entry2Span.start ?
895                            compareValues(entry1Span.start, entry2Span.start) :
896                            compareValues(entry1Span.length, entry2Span.length);
897                    })
898                };
899            }
900        }
901        return result;
902    }
903
904    function getSourceFileIndexOfEntry(program: Program, entry: Entry) {
905        const sourceFile = entry.kind === EntryKind.Span ?
906            program.getSourceFile(entry.fileName)! :
907            entry.node.getSourceFile();
908        return program.getSourceFiles().indexOf(sourceFile);
909    }
910
911    function getReferencedSymbolsForModule(program: Program, symbol: Symbol, excludeImportTypeOfExportEquals: boolean, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet<string>): SymbolAndEntries[] {
912        Debug.assert(!!symbol.valueDeclaration);
913
914        const references = mapDefined<ModuleReference, Entry>(findModuleReferences(program, sourceFiles, symbol), reference => {
915            if (reference.kind === "import") {
916                const parent = reference.literal.parent;
917                if (isLiteralTypeNode(parent)) {
918                    const importType = cast(parent.parent, isImportTypeNode);
919                    if (excludeImportTypeOfExportEquals && !importType.qualifier) {
920                        return undefined;
921                    }
922                }
923                // import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway.
924                return nodeEntry(reference.literal);
925            }
926            else {
927                return {
928                    kind: EntryKind.Span,
929                    fileName: reference.referencingFile.fileName,
930                    textSpan: createTextSpanFromRange(reference.ref),
931                };
932            }
933        });
934
935        if (symbol.declarations) {
936            for (const decl of symbol.declarations) {
937                switch (decl.kind) {
938                    case SyntaxKind.SourceFile:
939                        // Don't include the source file itself. (This may not be ideal behavior, but awkward to include an entire file as a reference.)
940                        break;
941                    case SyntaxKind.ModuleDeclaration:
942                        if (sourceFilesSet.has(decl.getSourceFile().fileName)) {
943                            references.push(nodeEntry((decl as ModuleDeclaration).name));
944                        }
945                        break;
946                    default:
947                        // This may be merged with something.
948                        Debug.assert(!!(symbol.flags & SymbolFlags.Transient), "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration.");
949                }
950            }
951        }
952
953        const exported = symbol.exports!.get(InternalSymbolName.ExportEquals);
954        if (exported?.declarations) {
955            for (const decl of exported.declarations) {
956                const sourceFile = decl.getSourceFile();
957                if (sourceFilesSet.has(sourceFile.fileName)) {
958                    // At `module.exports = ...`, reference node is `module`
959                    const node = isBinaryExpression(decl) && isPropertyAccessExpression(decl.left) ? decl.left.expression :
960                        isExportAssignment(decl) ? Debug.checkDefined(findChildOfKind(decl, SyntaxKind.ExportKeyword, sourceFile)) :
961                        getNameOfDeclaration(decl) || decl;
962                    references.push(nodeEntry(node));
963                }
964            }
965        }
966
967        return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] : emptyArray;
968    }
969
970    /** As in a `readonly prop: any` or `constructor(readonly prop: any)`, not a `readonly any[]`. */
971    function isReadonlyTypeOperator(node: Node): boolean {
972        return node.kind === SyntaxKind.ReadonlyKeyword
973            && isTypeOperatorNode(node.parent)
974            && node.parent.operator === SyntaxKind.ReadonlyKeyword;
975    }
976
977    /** getReferencedSymbols for special node kinds. */
978    function getReferencedSymbolsSpecial(node: Node, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
979        if (isTypeKeyword(node.kind)) {
980            // A void expression (i.e., `void foo()`) is not special, but the `void` type is.
981            if (node.kind === SyntaxKind.VoidKeyword && isVoidExpression(node.parent)) {
982                return undefined;
983            }
984
985            // A modifier readonly (like on a property declaration) is not special;
986            // a readonly type keyword (like `readonly string[]`) is.
987            if (node.kind === SyntaxKind.ReadonlyKeyword && !isReadonlyTypeOperator(node)) {
988                return undefined;
989            }
990            // Likewise, when we *are* looking for a special keyword, make sure we
991            // *don’t* include readonly member modifiers.
992            return getAllReferencesForKeyword(
993                sourceFiles,
994                node.kind,
995                cancellationToken,
996                node.kind === SyntaxKind.ReadonlyKeyword ? isReadonlyTypeOperator : undefined);
997        }
998
999        if (isImportMeta(node.parent) && node.parent.name === node) {
1000            return getAllReferencesForImportMeta(sourceFiles, cancellationToken);
1001        }
1002
1003        if (isStaticModifier(node) && isClassStaticBlockDeclaration(node.parent)) {
1004            return [{ definition: { type: DefinitionKind.Keyword, node }, references: [nodeEntry(node)] }];
1005        }
1006
1007        // Labels
1008        if (isJumpStatementTarget(node)) {
1009            const labelDefinition = getTargetLabel(node.parent, node.text);
1010            // if we have a label definition, look within its statement for references, if not, then
1011            // the label is undefined and we have no results..
1012            return labelDefinition && getLabelReferencesInNode(labelDefinition.parent, labelDefinition);
1013        }
1014        else if (isLabelOfLabeledStatement(node)) {
1015            // it is a label definition and not a target, search within the parent labeledStatement
1016            return getLabelReferencesInNode(node.parent, node);
1017        }
1018
1019        if (isThis(node)) {
1020            return getReferencesForThisKeyword(node, sourceFiles, cancellationToken);
1021        }
1022
1023        if (node.kind === SyntaxKind.SuperKeyword) {
1024            return getReferencesForSuperKeyword(node);
1025        }
1026
1027        return undefined;
1028    }
1029
1030    /** Core find-all-references algorithm for a normal symbol. */
1031    function getReferencedSymbolsForSymbol(originalSymbol: Symbol, node: Node | undefined, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet<string>, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] {
1032        const symbol = node && skipPastExportOrImportSpecifierOrUnion(originalSymbol, node, checker, /*useLocalSymbolForExportSpecifier*/ !isForRenameWithPrefixAndSuffixText(options)) || originalSymbol;
1033
1034        // Compute the meaning from the location and the symbol it references
1035        const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All;
1036        const result: SymbolAndEntries[] = [];
1037        const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result);
1038
1039        const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) || !symbol.declarations ? undefined : find(symbol.declarations, isExportSpecifier);
1040        if (exportSpecifier) {
1041            // When renaming at an export specifier, rename the export and not the thing being exported.
1042            getReferencesAtExportSpecifier(exportSpecifier.name, symbol, exportSpecifier, state.createSearch(node, originalSymbol, /*comingFrom*/ undefined), state, /*addReferencesHere*/ true, /*alwaysGetReferences*/ true);
1043        }
1044        else if (node && node.kind === SyntaxKind.DefaultKeyword && symbol.escapedName === InternalSymbolName.Default && symbol.parent) {
1045            addReference(node, symbol, state);
1046            searchForImportsOfExport(node, symbol, { exportingModuleSymbol: symbol.parent, exportKind: ExportKind.Default }, state);
1047        }
1048        else {
1049            const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, options.use === FindReferencesUse.Rename, !!options.providePrefixAndSuffixTextForRename, !!options.implementations) : [symbol] });
1050            getReferencesInContainerOrFiles(symbol, state, search);
1051        }
1052
1053        return result;
1054    }
1055
1056    function getReferencesInContainerOrFiles(symbol: Symbol, state: State, search: Search): void {
1057        // Try to get the smallest valid scope that we can limit our search to;
1058        // otherwise we'll need to search globally (i.e. include each file).
1059        const scope = getSymbolScope(symbol);
1060        if (scope) {
1061            getReferencesInContainer(scope, scope.getSourceFile(), search, state, /*addReferencesHere*/ !(isSourceFile(scope) && !contains(state.sourceFiles, scope)));
1062        }
1063        else {
1064            // Global search
1065            for (const sourceFile of state.sourceFiles) {
1066                state.cancellationToken.throwIfCancellationRequested();
1067                searchForName(sourceFile, search, state);
1068            }
1069        }
1070    }
1071
1072    function getSpecialSearchKind(node: Node): SpecialSearchKind {
1073        switch (node.kind) {
1074            case SyntaxKind.Constructor:
1075            case SyntaxKind.ConstructorKeyword:
1076                return SpecialSearchKind.Constructor;
1077            case SyntaxKind.Identifier:
1078                if (isClassLike(node.parent)) {
1079                    Debug.assert(node.parent.name === node);
1080                    return SpecialSearchKind.Class;
1081                }
1082                // falls through
1083            default:
1084                return SpecialSearchKind.None;
1085        }
1086    }
1087
1088    /** Handle a few special cases relating to export/import specifiers. */
1089    function skipPastExportOrImportSpecifierOrUnion(symbol: Symbol, node: Node, checker: TypeChecker, useLocalSymbolForExportSpecifier: boolean): Symbol | undefined {
1090        const { parent } = node;
1091        if (isExportSpecifier(parent) && useLocalSymbolForExportSpecifier) {
1092            return getLocalSymbolForExportSpecifier(node as Identifier, symbol, parent, checker);
1093        }
1094        // If the symbol is declared as part of a declaration like `{ type: "a" } | { type: "b" }`, use the property on the union type to get more references.
1095        return firstDefined(symbol.declarations, decl => {
1096            if (!decl.parent) {
1097                // Ignore UMD module and global merge
1098                if (symbol.flags & SymbolFlags.Transient) return undefined;
1099                // Assertions for GH#21814. We should be handling SourceFile symbols in `getReferencedSymbolsForModule` instead of getting here.
1100                Debug.fail(`Unexpected symbol at ${Debug.formatSyntaxKind(node.kind)}: ${Debug.formatSymbol(symbol)}`);
1101            }
1102            return isTypeLiteralNode(decl.parent) && isUnionTypeNode(decl.parent.parent)
1103                ? checker.getPropertyOfType(checker.getTypeFromTypeNode(decl.parent.parent), symbol.name)
1104                : undefined;
1105        });
1106    }
1107
1108    /**
1109     * Symbol that is currently being searched for.
1110     * This will be replaced if we find an alias for the symbol.
1111     */
1112    interface Search {
1113        /** If coming from an export, we will not recursively search for the imported symbol (since that's where we came from). */
1114        readonly comingFrom?: ImportExport;
1115
1116        readonly symbol: Symbol;
1117        readonly text: string;
1118        readonly escapedText: __String;
1119        /** Only set if `options.implementations` is true. These are the symbols checked to get the implementations of a property access. */
1120        readonly parents: readonly Symbol[] | undefined;
1121        readonly allSearchSymbols: readonly Symbol[];
1122
1123        /**
1124         * Whether a symbol is in the search set.
1125         * Do not compare directly to `symbol` because there may be related symbols to search for. See `populateSearchSymbolSet`.
1126         */
1127        includes(symbol: Symbol): boolean;
1128    }
1129
1130    const enum SpecialSearchKind {
1131        None,
1132        Constructor,
1133        Class,
1134    }
1135
1136    function getNonModuleSymbolOfMergedModuleSymbol(symbol: Symbol) {
1137        if (!(symbol.flags & (SymbolFlags.Module | SymbolFlags.Transient))) return undefined;
1138        const decl = symbol.declarations && find(symbol.declarations, d => !isSourceFile(d) && !isModuleDeclaration(d));
1139        return decl && decl.symbol;
1140    }
1141
1142    /**
1143     * Holds all state needed for the finding references.
1144     * Unlike `Search`, there is only one `State`.
1145     */
1146    class State {
1147        /** Cache for `explicitlyinheritsFrom`. */
1148        readonly inheritsFromCache = new Map<string, boolean>();
1149
1150        /**
1151         * Type nodes can contain multiple references to the same type. For example:
1152         *      let x: Foo & (Foo & Bar) = ...
1153         * Because we are returning the implementation locations and not the identifier locations,
1154         * duplicate entries would be returned here as each of the type references is part of
1155         * the same implementation. For that reason, check before we add a new entry.
1156         */
1157        readonly markSeenContainingTypeReference = nodeSeenTracker();
1158
1159        /**
1160         * It's possible that we will encounter the right side of `export { foo as bar } from "x";` more than once.
1161         * For example:
1162         *     // b.ts
1163         *     export { foo as bar } from "./a";
1164         *     import { bar } from "./b";
1165         *
1166         * Normally at `foo as bar` we directly add `foo` and do not locally search for it (since it doesn't declare a local).
1167         * But another reference to it may appear in the same source file.
1168         * See `tests/cases/fourslash/transitiveExportImports3.ts`.
1169         */
1170        readonly markSeenReExportRHS = nodeSeenTracker();
1171
1172        constructor(
1173            readonly sourceFiles: readonly SourceFile[],
1174            readonly sourceFilesSet: ReadonlySet<string>,
1175            readonly specialSearchKind: SpecialSearchKind,
1176            readonly checker: TypeChecker,
1177            readonly cancellationToken: CancellationToken,
1178            readonly searchMeaning: SemanticMeaning,
1179            readonly options: Options,
1180            private readonly result: Push<SymbolAndEntries>) {
1181        }
1182
1183        includesSourceFile(sourceFile: SourceFile): boolean {
1184            return this.sourceFilesSet.has(sourceFile.fileName);
1185        }
1186
1187        private importTracker: ImportTracker | undefined;
1188        /** Gets every place to look for references of an exported symbols. See `ImportsResult` in `importTracker.ts` for more documentation. */
1189        getImportSearches(exportSymbol: Symbol, exportInfo: ExportInfo): ImportsResult {
1190            if (!this.importTracker) this.importTracker = createImportTracker(this.sourceFiles, this.sourceFilesSet, this.checker, this.cancellationToken);
1191            return this.importTracker(exportSymbol, exportInfo, this.options.use === FindReferencesUse.Rename);
1192        }
1193
1194        /** @param allSearchSymbols set of additional symbols for use by `includes`. */
1195        createSearch(location: Node | undefined, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search {
1196            // Note: if this is an external module symbol, the name doesn't include quotes.
1197            // Note: getLocalSymbolForExportDefault handles `export default class C {}`, but not `export default C` or `export { C as default }`.
1198            // The other two forms seem to be handled downstream (e.g. in `skipPastExportOrImportSpecifier`), so special-casing the first form
1199            // here appears to be intentional).
1200            const {
1201                text = stripQuotes(symbolName(getLocalSymbolForExportDefault(symbol) || getNonModuleSymbolOfMergedModuleSymbol(symbol) || symbol)),
1202                allSearchSymbols = [symbol],
1203            } = searchOptions;
1204            const escapedText = escapeLeadingUnderscores(text);
1205            const parents = this.options.implementations && location ? getParentSymbolsOfPropertyAccess(location, symbol, this.checker) : undefined;
1206            return { symbol, comingFrom, text, escapedText, parents, allSearchSymbols, includes: sym => contains(allSearchSymbols, sym) };
1207        }
1208
1209        private readonly symbolIdToReferences: Entry[][] = [];
1210        /**
1211         * Callback to add references for a particular searched symbol.
1212         * This initializes a reference group, so only call this if you will add at least one reference.
1213         */
1214        referenceAdder(searchSymbol: Symbol): (node: Node, kind?: NodeEntryKind) => void {
1215            const symbolId = getSymbolId(searchSymbol);
1216            let references = this.symbolIdToReferences[symbolId];
1217            if (!references) {
1218                references = this.symbolIdToReferences[symbolId] = [];
1219                this.result.push({ definition: { type: DefinitionKind.Symbol, symbol: searchSymbol }, references });
1220            }
1221            return (node, kind) => references.push(nodeEntry(node, kind));
1222        }
1223
1224        /** Add a reference with no associated definition. */
1225        addStringOrCommentReference(fileName: string, textSpan: TextSpan): void {
1226            this.result.push({
1227                definition: undefined,
1228                references: [{ kind: EntryKind.Span, fileName, textSpan }]
1229            });
1230        }
1231
1232        // Source file ID → symbol ID → Whether the symbol has been searched for in the source file.
1233        private readonly sourceFileToSeenSymbols: Set<number>[] = [];
1234        /** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */
1235        markSearchedSymbols(sourceFile: SourceFile, symbols: readonly Symbol[]): boolean {
1236            const sourceId = getNodeId(sourceFile);
1237            const seenSymbols = this.sourceFileToSeenSymbols[sourceId] || (this.sourceFileToSeenSymbols[sourceId] = new Set<number>());
1238
1239            let anyNewSymbols = false;
1240            for (const sym of symbols) {
1241                anyNewSymbols = tryAddToSet(seenSymbols, getSymbolId(sym)) || anyNewSymbols;
1242            }
1243            return anyNewSymbols;
1244        }
1245    }
1246
1247    /** Search for all imports of a given exported symbol using `State.getImportSearches`. */
1248    function searchForImportsOfExport(exportLocation: Node, exportSymbol: Symbol, exportInfo: ExportInfo, state: State): void {
1249        const { importSearches, singleReferences, indirectUsers } = state.getImportSearches(exportSymbol, exportInfo);
1250
1251        // For `import { foo as bar }` just add the reference to `foo`, and don't otherwise search in the file.
1252        if (singleReferences.length) {
1253            const addRef = state.referenceAdder(exportSymbol);
1254            for (const singleRef of singleReferences) {
1255                if (shouldAddSingleReference(singleRef, state)) addRef(singleRef);
1256            }
1257        }
1258
1259        // For each import, find all references to that import in its source file.
1260        for (const [importLocation, importSymbol] of importSearches) {
1261            getReferencesInSourceFile(importLocation.getSourceFile(), state.createSearch(importLocation, importSymbol, ImportExport.Export), state);
1262        }
1263
1264        if (indirectUsers.length) {
1265            let indirectSearch: Search | undefined;
1266            switch (exportInfo.exportKind) {
1267                case ExportKind.Named:
1268                    indirectSearch = state.createSearch(exportLocation, exportSymbol, ImportExport.Export);
1269                    break;
1270                case ExportKind.Default:
1271                    // Search for a property access to '.default'. This can't be renamed.
1272                    indirectSearch = state.options.use === FindReferencesUse.Rename ? undefined : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" });
1273                    break;
1274                case ExportKind.ExportEquals:
1275                    break;
1276            }
1277            if (indirectSearch) {
1278                for (const indirectUser of indirectUsers) {
1279                    searchForName(indirectUser, indirectSearch, state);
1280                }
1281            }
1282        }
1283    }
1284
1285    export function eachExportReference(
1286        sourceFiles: readonly SourceFile[],
1287        checker: TypeChecker,
1288        cancellationToken: CancellationToken | undefined,
1289        exportSymbol: Symbol,
1290        exportingModuleSymbol: Symbol,
1291        exportName: string,
1292        isDefaultExport: boolean,
1293        cb: (ref: Identifier) => void,
1294    ): void {
1295        const importTracker = createImportTracker(sourceFiles, new Set(sourceFiles.map(f => f.fileName)), checker, cancellationToken);
1296        const { importSearches, indirectUsers, singleReferences } = importTracker(exportSymbol, { exportKind: isDefaultExport ? ExportKind.Default : ExportKind.Named, exportingModuleSymbol }, /*isForRename*/ false);
1297        for (const [importLocation] of importSearches) {
1298            cb(importLocation);
1299        }
1300        for (const singleReference of singleReferences) {
1301            if (isIdentifier(singleReference) && isImportTypeNode(singleReference.parent)) {
1302                cb(singleReference);
1303            }
1304        }
1305        for (const indirectUser of indirectUsers) {
1306            for (const node of getPossibleSymbolReferenceNodes(indirectUser, isDefaultExport ? "default" : exportName)) {
1307                // Import specifiers should be handled by importSearches
1308                const symbol = checker.getSymbolAtLocation(node);
1309                const hasExportAssignmentDeclaration = some(symbol?.declarations, d => tryCast(d, isExportAssignment) ? true : false);
1310                if (isIdentifier(node) && !isImportOrExportSpecifier(node.parent) && (symbol === exportSymbol || hasExportAssignmentDeclaration)) {
1311                    cb(node);
1312                }
1313            }
1314        }
1315    }
1316
1317    function shouldAddSingleReference(singleRef: Identifier | StringLiteral, state: State): boolean {
1318        if (!hasMatchingMeaning(singleRef, state)) return false;
1319        if (state.options.use !== FindReferencesUse.Rename) return true;
1320        // Don't rename an import type `import("./module-name")` when renaming `name` in `export = name;`
1321        if (!isIdentifier(singleRef)) return false;
1322        // At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename.
1323        return !(isImportOrExportSpecifier(singleRef.parent) && singleRef.escapedText === InternalSymbolName.Default);
1324    }
1325
1326    // Go to the symbol we imported from and find references for it.
1327    function searchForImportedSymbol(symbol: Symbol, state: State): void {
1328        if (!symbol.declarations) return;
1329
1330        for (const declaration of symbol.declarations) {
1331            const exportingFile = declaration.getSourceFile();
1332            // Need to search in the file even if it's not in the search-file set, because it might export the symbol.
1333            getReferencesInSourceFile(exportingFile, state.createSearch(declaration, symbol, ImportExport.Import), state, state.includesSourceFile(exportingFile));
1334        }
1335    }
1336
1337    /** Search for all occurrences of an identifier in a source file (and filter out the ones that match). */
1338    function searchForName(sourceFile: SourceFile, search: Search, state: State): void {
1339        if (getNameTable(sourceFile).get(search.escapedText) !== undefined) {
1340            getReferencesInSourceFile(sourceFile, search, state);
1341        }
1342    }
1343
1344    function getPropertySymbolOfDestructuringAssignment(location: Node, checker: TypeChecker): Symbol | undefined {
1345        return isArrayLiteralOrObjectLiteralDestructuringPattern(location.parent.parent)
1346            ? checker.getPropertySymbolOfDestructuringAssignment(location as Identifier)
1347            : undefined;
1348    }
1349
1350    /**
1351     * Determines the smallest scope in which a symbol may have named references.
1352     * Note that not every construct has been accounted for. This function can
1353     * probably be improved.
1354     *
1355     * @returns undefined if the scope cannot be determined, implying that
1356     * a reference to a symbol can occur anywhere.
1357     */
1358    function getSymbolScope(symbol: Symbol): Node | undefined {
1359        // If this is the symbol of a named function expression or named class expression,
1360        // then named references are limited to its own scope.
1361        const { declarations, flags, parent, valueDeclaration } = symbol;
1362        if (valueDeclaration && (valueDeclaration.kind === SyntaxKind.FunctionExpression || valueDeclaration.kind === SyntaxKind.ClassExpression)) {
1363            return valueDeclaration;
1364        }
1365
1366        if (!declarations) {
1367            return undefined;
1368        }
1369
1370        // If this is private property or method, the scope is the containing class
1371        if (flags & (SymbolFlags.Property | SymbolFlags.Method)) {
1372            const privateDeclaration = find(declarations, d => hasEffectiveModifier(d, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(d));
1373            if (privateDeclaration) {
1374                return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration);
1375            }
1376            // Else this is a public property and could be accessed from anywhere.
1377            return undefined;
1378        }
1379
1380        // If symbol is of object binding pattern element without property name we would want to
1381        // look for property too and that could be anywhere
1382        if (declarations.some(isObjectBindingElementWithoutPropertyName)) {
1383            return undefined;
1384        }
1385
1386        /*
1387        If the symbol has a parent, it's globally visible unless:
1388        - It's a private property (handled above).
1389        - It's a type parameter.
1390        - The parent is an external module: then we should only search in the module (and recurse on the export later).
1391        - But if the parent has `export as namespace`, the symbol is globally visible through that namespace.
1392        */
1393        const exposedByParent = parent && !(symbol.flags & SymbolFlags.TypeParameter);
1394        if (exposedByParent && !(isExternalModuleSymbol(parent) && !parent.globalExports)) {
1395            return undefined;
1396        }
1397
1398        let scope: Node | undefined;
1399        for (const declaration of declarations) {
1400            const container = getContainerNode(declaration);
1401            if (scope && scope !== container) {
1402                // Different declarations have different containers, bail out
1403                return undefined;
1404            }
1405
1406            if (!container || container.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(container as SourceFile)) {
1407                // This is a global variable and not an external module, any declaration defined
1408                // within this scope is visible outside the file
1409                return undefined;
1410            }
1411
1412            scope = container;
1413            if (isFunctionExpression(scope)) {
1414                let next: Node | undefined;
1415                while (next = getNextJSDocCommentLocation(scope)) {
1416                    scope = next;
1417                }
1418            }
1419        }
1420
1421        // If symbol.parent, this means we are in an export of an external module. (Otherwise we would have returned `undefined` above.)
1422        // For an export of a module, we may be in a declaration file, and it may be accessed elsewhere. E.g.:
1423        //     declare module "a" { export type T = number; }
1424        //     declare module "b" { import { T } from "a"; export const x: T; }
1425        // So we must search the whole source file. (Because we will mark the source file as seen, we we won't return to it when searching for imports.)
1426        return exposedByParent ? scope!.getSourceFile() : scope; // TODO: GH#18217
1427    }
1428
1429    /** Used as a quick check for whether a symbol is used at all in a file (besides its definition). */
1430    export function isSymbolReferencedInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, searchContainer: Node = sourceFile): boolean {
1431        return eachSymbolReferenceInFile(definition, checker, sourceFile, () => true, searchContainer) || false;
1432    }
1433
1434    export function eachSymbolReferenceInFile<T>(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, cb: (token: Identifier) => T, searchContainer: Node = sourceFile): T | undefined {
1435        const symbol = isParameterPropertyDeclaration(definition.parent, definition.parent.parent)
1436            ? first(checker.getSymbolsOfParameterPropertyDeclaration(definition.parent, definition.text))
1437            : checker.getSymbolAtLocation(definition);
1438        if (!symbol) return undefined;
1439        for (const token of getPossibleSymbolReferenceNodes(sourceFile, symbol.name, searchContainer)) {
1440            if (!isIdentifier(token) || token === definition || token.escapedText !== definition.escapedText) continue;
1441            const referenceSymbol = checker.getSymbolAtLocation(token)!;
1442            if (referenceSymbol === symbol
1443                || checker.getShorthandAssignmentValueSymbol(token.parent) === symbol
1444                || isExportSpecifier(token.parent) && getLocalSymbolForExportSpecifier(token, referenceSymbol, token.parent, checker) === symbol) {
1445                const res = cb(token);
1446                if (res) return res;
1447            }
1448        }
1449    }
1450
1451    export function getTopMostDeclarationNamesInFile(declarationName: string, sourceFile: SourceFile): readonly Node[] {
1452        const candidates = filter(getPossibleSymbolReferenceNodes(sourceFile, declarationName), name => !!getDeclarationFromName(name));
1453        return candidates.reduce((topMost, decl) => {
1454            const depth = getDepth(decl);
1455            if (!some(topMost.declarationNames) || depth === topMost.depth) {
1456                topMost.declarationNames.push(decl);
1457                topMost.depth = depth;
1458            }
1459            else if (depth < topMost.depth) {
1460                topMost.declarationNames = [decl];
1461                topMost.depth = depth;
1462            }
1463            return topMost;
1464        }, { depth: Infinity, declarationNames: [] as Node[] }).declarationNames;
1465
1466        function getDepth(declaration: Node | undefined) {
1467            let depth = 0;
1468            while (declaration) {
1469                declaration = getContainerNode(declaration);
1470                depth++;
1471            }
1472            return depth;
1473        }
1474    }
1475
1476    export function someSignatureUsage(
1477        signature: SignatureDeclaration,
1478        sourceFiles: readonly SourceFile[],
1479        checker: TypeChecker,
1480        cb: (name: Identifier, call?: CallExpression) => boolean
1481    ): boolean {
1482        if (!signature.name || !isIdentifier(signature.name)) return false;
1483
1484        const symbol = Debug.checkDefined(checker.getSymbolAtLocation(signature.name));
1485
1486        for (const sourceFile of sourceFiles) {
1487            for (const name of getPossibleSymbolReferenceNodes(sourceFile, symbol.name)) {
1488                if (!isIdentifier(name) || name === signature.name || name.escapedText !== signature.name.escapedText) continue;
1489                const called = climbPastPropertyAccess(name);
1490                const call = isCallExpression(called.parent) && called.parent.expression === called ? called.parent : undefined;
1491                const referenceSymbol = checker.getSymbolAtLocation(name);
1492                if (referenceSymbol && checker.getRootSymbols(referenceSymbol).some(s => s === symbol)) {
1493                    if (cb(name, call)) {
1494                        return true;
1495                    }
1496                }
1497            }
1498        }
1499        return false;
1500    }
1501
1502    function getPossibleSymbolReferenceNodes(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): readonly Node[] {
1503        return getPossibleSymbolReferencePositions(sourceFile, symbolName, container).map(pos => getTouchingPropertyName(sourceFile, pos));
1504    }
1505
1506    function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): readonly number[] {
1507        const positions: number[] = [];
1508
1509        /// TODO: Cache symbol existence for files to save text search
1510        // Also, need to make this work for unicode escapes.
1511
1512        // Be resilient in the face of a symbol with no name or zero length name
1513        if (!symbolName || !symbolName.length) {
1514            return positions;
1515        }
1516
1517        const text = sourceFile.text;
1518        const sourceLength = text.length;
1519        const symbolNameLength = symbolName.length;
1520
1521        let position = text.indexOf(symbolName, container.pos);
1522        while (position >= 0) {
1523            // If we are past the end, stop looking
1524            if (position > container.end) break;
1525
1526            // We found a match.  Make sure it's not part of a larger word (i.e. the char
1527            // before and after it have to be a non-identifier char).
1528            const endPosition = position + symbolNameLength;
1529
1530            if ((position === 0 || !isIdentifierPart(text.charCodeAt(position - 1), ScriptTarget.Latest)) &&
1531                (endPosition === sourceLength || !isIdentifierPart(text.charCodeAt(endPosition), ScriptTarget.Latest))) {
1532                // Found a real match.  Keep searching.
1533                positions.push(position);
1534            }
1535            position = text.indexOf(symbolName, position + symbolNameLength + 1);
1536        }
1537
1538        return positions;
1539    }
1540
1541    function getLabelReferencesInNode(container: Node, targetLabel: Identifier): SymbolAndEntries[] {
1542        const sourceFile = container.getSourceFile();
1543        const labelName = targetLabel.text;
1544        const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, labelName, container), node =>
1545            // Only pick labels that are either the target label, or have a target that is the target label
1546            node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel) ? nodeEntry(node) : undefined);
1547        return [{ definition: { type: DefinitionKind.Label, node: targetLabel }, references }];
1548    }
1549
1550    function isValidReferencePosition(node: Node, searchSymbolName: string): boolean {
1551        // Compare the length so we filter out strict superstrings of the symbol we are looking for
1552        switch (node.kind) {
1553            case SyntaxKind.PrivateIdentifier:
1554                if (isJSDocMemberName(node.parent)) {
1555                    return true;
1556                }
1557                // falls through I guess
1558            case SyntaxKind.Identifier:
1559                return (node as PrivateIdentifier | Identifier).text.length === searchSymbolName.length;
1560            case SyntaxKind.NoSubstitutionTemplateLiteral:
1561            case SyntaxKind.StringLiteral: {
1562                const str = node as StringLiteralLike;
1563                return (isLiteralNameOfPropertyDeclarationOrIndexAccess(str) || isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node) || (isCallExpression(node.parent) && isBindableObjectDefinePropertyCall(node.parent) && node.parent.arguments[1] === node)) &&
1564                    str.text.length === searchSymbolName.length;
1565            }
1566
1567            case SyntaxKind.NumericLiteral:
1568                return isLiteralNameOfPropertyDeclarationOrIndexAccess(node as NumericLiteral) && (node as NumericLiteral).text.length === searchSymbolName.length;
1569
1570            case SyntaxKind.DefaultKeyword:
1571                return "default".length === searchSymbolName.length;
1572
1573            default:
1574                return false;
1575        }
1576    }
1577
1578    function getAllReferencesForImportMeta(sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
1579        const references = flatMap(sourceFiles, sourceFile => {
1580            cancellationToken.throwIfCancellationRequested();
1581            return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, "meta", sourceFile), node => {
1582                const parent = node.parent;
1583                if (isImportMeta(parent)) {
1584                    return nodeEntry(parent);
1585                }
1586            });
1587        });
1588        return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined;
1589    }
1590
1591    function getAllReferencesForKeyword(sourceFiles: readonly SourceFile[], keywordKind: SyntaxKind, cancellationToken: CancellationToken, filter?: (node: Node) => boolean): SymbolAndEntries[] | undefined {
1592        const references = flatMap(sourceFiles, sourceFile => {
1593            cancellationToken.throwIfCancellationRequested();
1594            return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation => {
1595                if (referenceLocation.kind === keywordKind && (!filter || filter(referenceLocation))) {
1596                    return nodeEntry(referenceLocation);
1597                }
1598            });
1599        });
1600        return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined;
1601    }
1602
1603    function getReferencesInSourceFile(sourceFile: SourceFile, search: Search, state: State, addReferencesHere = true): void {
1604        state.cancellationToken.throwIfCancellationRequested();
1605        return getReferencesInContainer(sourceFile, sourceFile, search, state, addReferencesHere);
1606    }
1607
1608    /**
1609     * Search within node "container" for references for a search value, where the search value is defined as a
1610     * tuple of(searchSymbol, searchText, searchLocation, and searchMeaning).
1611     * searchLocation: a node where the search value
1612     */
1613    function getReferencesInContainer(container: Node, sourceFile: SourceFile, search: Search, state: State, addReferencesHere: boolean): void {
1614        if (!state.markSearchedSymbols(sourceFile, search.allSearchSymbols)) {
1615            return;
1616        }
1617
1618        for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container)) {
1619            getReferencesAtLocation(sourceFile, position, search, state, addReferencesHere);
1620        }
1621    }
1622
1623    function hasMatchingMeaning(referenceLocation: Node, state: State): boolean {
1624        return !!(getMeaningFromLocation(referenceLocation) & state.searchMeaning);
1625    }
1626
1627    function getReferencesAtLocation(sourceFile: SourceFile, position: number, search: Search, state: State, addReferencesHere: boolean): void {
1628        const referenceLocation = getTouchingPropertyName(sourceFile, position);
1629
1630        if (!isValidReferencePosition(referenceLocation, search.text)) {
1631            // This wasn't the start of a token.  Check to see if it might be a
1632            // match in a comment or string if that's what the caller is asking
1633            // for.
1634            if (!state.options.implementations && (state.options.findInStrings && isInString(sourceFile, position) || state.options.findInComments && isInNonReferenceComment(sourceFile, position))) {
1635                // In the case where we're looking inside comments/strings, we don't have
1636                // an actual definition.  So just use 'undefined' here.  Features like
1637                // 'Rename' won't care (as they ignore the definitions), and features like
1638                // 'FindReferences' will just filter out these results.
1639                state.addStringOrCommentReference(sourceFile.fileName, createTextSpan(position, search.text.length));
1640            }
1641
1642            return;
1643        }
1644
1645        if (!hasMatchingMeaning(referenceLocation, state)) return;
1646
1647        let referenceSymbol = state.checker.getSymbolAtLocation(referenceLocation);
1648        if (!referenceSymbol) {
1649            return;
1650        }
1651
1652        const parent = referenceLocation.parent;
1653        if (isImportSpecifier(parent) && parent.propertyName === referenceLocation) {
1654            // This is added through `singleReferences` in ImportsResult. If we happen to see it again, don't add it again.
1655            return;
1656        }
1657
1658        if (isExportSpecifier(parent)) {
1659            Debug.assert(referenceLocation.kind === SyntaxKind.Identifier);
1660            getReferencesAtExportSpecifier(referenceLocation as Identifier, referenceSymbol, parent, search, state, addReferencesHere);
1661            return;
1662        }
1663
1664        const relatedSymbol = getRelatedSymbol(search, referenceSymbol, referenceLocation, state);
1665        if (!relatedSymbol) {
1666            getReferenceForShorthandProperty(referenceSymbol, search, state);
1667            return;
1668        }
1669
1670        switch (state.specialSearchKind) {
1671            case SpecialSearchKind.None:
1672                if (addReferencesHere) addReference(referenceLocation, relatedSymbol, state);
1673                break;
1674            case SpecialSearchKind.Constructor:
1675                addConstructorReferences(referenceLocation, sourceFile, search, state);
1676                break;
1677            case SpecialSearchKind.Class:
1678                addClassStaticThisReferences(referenceLocation, search, state);
1679                break;
1680            default:
1681                Debug.assertNever(state.specialSearchKind);
1682        }
1683
1684        // Use the parent symbol if the location is commonjs require syntax on javascript files only.
1685        if (isInJSFile(referenceLocation)
1686            && referenceLocation.parent.kind === SyntaxKind.BindingElement
1687            && isVariableDeclarationInitializedToBareOrAccessedRequire(referenceLocation.parent.parent.parent)) {
1688            referenceSymbol = referenceLocation.parent.symbol;
1689            // The parent will not have a symbol if it's an ObjectBindingPattern (when destructuring is used).  In
1690            // this case, just skip it, since the bound identifiers are not an alias of the import.
1691            if (!referenceSymbol) return;
1692        }
1693
1694        getImportOrExportReferences(referenceLocation, referenceSymbol, search, state);
1695    }
1696
1697    function getReferencesAtExportSpecifier(
1698        referenceLocation: Identifier,
1699        referenceSymbol: Symbol,
1700        exportSpecifier: ExportSpecifier,
1701        search: Search,
1702        state: State,
1703        addReferencesHere: boolean,
1704        alwaysGetReferences?: boolean,
1705    ): void {
1706        Debug.assert(!alwaysGetReferences || !!state.options.providePrefixAndSuffixTextForRename, "If alwaysGetReferences is true, then prefix/suffix text must be enabled");
1707
1708        const { parent, propertyName, name } = exportSpecifier;
1709        const exportDeclaration = parent.parent;
1710        const localSymbol = getLocalSymbolForExportSpecifier(referenceLocation, referenceSymbol, exportSpecifier, state.checker);
1711        if (!alwaysGetReferences && !search.includes(localSymbol)) {
1712            return;
1713        }
1714
1715        if (!propertyName) {
1716            // Don't rename at `export { default } from "m";`. (but do continue to search for imports of the re-export)
1717            if (!(state.options.use === FindReferencesUse.Rename && (name.escapedText === InternalSymbolName.Default))) {
1718                addRef();
1719            }
1720        }
1721        else if (referenceLocation === propertyName) {
1722            // For `export { foo as bar } from "baz"`, "`foo`" will be added from the singleReferences for import searches of the original export.
1723            // For `export { foo as bar };`, where `foo` is a local, so add it now.
1724            if (!exportDeclaration.moduleSpecifier) {
1725                addRef();
1726            }
1727
1728            if (addReferencesHere && state.options.use !== FindReferencesUse.Rename && state.markSeenReExportRHS(name)) {
1729                addReference(name, Debug.checkDefined(exportSpecifier.symbol), state);
1730            }
1731        }
1732        else {
1733            if (state.markSeenReExportRHS(referenceLocation)) {
1734                addRef();
1735            }
1736        }
1737
1738        // For `export { foo as bar }`, rename `foo`, but not `bar`.
1739        if (!isForRenameWithPrefixAndSuffixText(state.options) || alwaysGetReferences) {
1740            const isDefaultExport = referenceLocation.originalKeywordKind === SyntaxKind.DefaultKeyword
1741                || exportSpecifier.name.originalKeywordKind === SyntaxKind.DefaultKeyword;
1742            const exportKind = isDefaultExport ? ExportKind.Default : ExportKind.Named;
1743            const exportSymbol = Debug.checkDefined(exportSpecifier.symbol);
1744            const exportInfo = getExportInfo(exportSymbol, exportKind, state.checker);
1745            if (exportInfo) {
1746                searchForImportsOfExport(referenceLocation, exportSymbol, exportInfo, state);
1747            }
1748        }
1749
1750        // At `export { x } from "foo"`, also search for the imported symbol `"foo".x`.
1751        if (search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName && !isForRenameWithPrefixAndSuffixText(state.options)) {
1752            const imported = state.checker.getExportSpecifierLocalTargetSymbol(exportSpecifier);
1753            if (imported) searchForImportedSymbol(imported, state);
1754        }
1755
1756        function addRef() {
1757            if (addReferencesHere) addReference(referenceLocation, localSymbol, state);
1758        }
1759    }
1760
1761    function getLocalSymbolForExportSpecifier(referenceLocation: Identifier, referenceSymbol: Symbol, exportSpecifier: ExportSpecifier, checker: TypeChecker): Symbol {
1762        return isExportSpecifierAlias(referenceLocation, exportSpecifier) && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier) || referenceSymbol;
1763    }
1764
1765    function isExportSpecifierAlias(referenceLocation: Identifier, exportSpecifier: ExportSpecifier): boolean {
1766        const { parent, propertyName, name } = exportSpecifier;
1767        Debug.assert(propertyName === referenceLocation || name === referenceLocation);
1768        if (propertyName) {
1769            // Given `export { foo as bar } [from "someModule"]`: It's an alias at `foo`, but at `bar` it's a new symbol.
1770            return propertyName === referenceLocation;
1771        }
1772        else {
1773            // `export { foo } from "foo"` is a re-export.
1774            // `export { foo };` is not a re-export, it creates an alias for the local variable `foo`.
1775            return !parent.parent.moduleSpecifier;
1776        }
1777    }
1778
1779    function getImportOrExportReferences(referenceLocation: Node, referenceSymbol: Symbol, search: Search, state: State): void {
1780        const importOrExport = getImportOrExportSymbol(referenceLocation, referenceSymbol, state.checker, search.comingFrom === ImportExport.Export);
1781        if (!importOrExport) return;
1782
1783        const { symbol } = importOrExport;
1784
1785        if (importOrExport.kind === ImportExport.Import) {
1786            if (!(isForRenameWithPrefixAndSuffixText(state.options))) {
1787                searchForImportedSymbol(symbol, state);
1788            }
1789        }
1790        else {
1791            searchForImportsOfExport(referenceLocation, symbol, importOrExport.exportInfo, state);
1792        }
1793    }
1794
1795    function getReferenceForShorthandProperty({ flags, valueDeclaration }: Symbol, search: Search, state: State): void {
1796        const shorthandValueSymbol = state.checker.getShorthandAssignmentValueSymbol(valueDeclaration)!;
1797        const name = valueDeclaration && getNameOfDeclaration(valueDeclaration);
1798        /*
1799        * Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
1800        * has two meanings: property name and property value. Therefore when we do findAllReference at the position where
1801        * an identifier is declared, the language service should return the position of the variable declaration as well as
1802        * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
1803        * position of property accessing, the referenceEntry of such position will be handled in the first case.
1804        */
1805        if (!(flags & SymbolFlags.Transient) && name && search.includes(shorthandValueSymbol)) {
1806            addReference(name, shorthandValueSymbol, state);
1807        }
1808    }
1809
1810    function addReference(referenceLocation: Node, relatedSymbol: Symbol | RelatedSymbol, state: State): void {
1811        const { kind, symbol } = "kind" in relatedSymbol ? relatedSymbol : { kind: undefined, symbol: relatedSymbol }; // eslint-disable-line local/no-in-operator
1812
1813        // if rename symbol from default export anonymous function, for example `export default function() {}`, we do not need to add reference
1814        if (state.options.use === FindReferencesUse.Rename && referenceLocation.kind === SyntaxKind.DefaultKeyword) {
1815            return;
1816        }
1817
1818        const addRef = state.referenceAdder(symbol);
1819        if (state.options.implementations) {
1820            addImplementationReferences(referenceLocation, addRef, state);
1821        }
1822        else {
1823            addRef(referenceLocation, kind);
1824        }
1825    }
1826
1827    /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses.  */
1828    function addConstructorReferences(referenceLocation: Node, sourceFile: SourceFile, search: Search, state: State): void {
1829        if (isNewExpressionTarget(referenceLocation)) {
1830            addReference(referenceLocation, search.symbol, state);
1831        }
1832
1833        const pusher = () => state.referenceAdder(search.symbol);
1834
1835        if (isClassLike(referenceLocation.parent)) {
1836            Debug.assert(referenceLocation.kind === SyntaxKind.DefaultKeyword || referenceLocation.parent.name === referenceLocation);
1837            // This is the class declaration containing the constructor.
1838            findOwnConstructorReferences(search.symbol, sourceFile, pusher());
1839        }
1840        else {
1841            // If this class appears in `extends C`, then the extending class' "super" calls are references.
1842            const classExtending = tryGetClassByExtendingIdentifier(referenceLocation);
1843            if (classExtending) {
1844                findSuperConstructorAccesses(classExtending, pusher());
1845                findInheritedConstructorReferences(classExtending, state);
1846            }
1847        }
1848    }
1849
1850    function addClassStaticThisReferences(referenceLocation: Node, search: Search, state: State): void {
1851        addReference(referenceLocation, search.symbol, state);
1852        const classLike = referenceLocation.parent;
1853        if (state.options.use === FindReferencesUse.Rename || !isClassLike(classLike)) return;
1854        Debug.assert(classLike.name === referenceLocation);
1855        const addRef = state.referenceAdder(search.symbol);
1856        for (const member of classLike.members) {
1857            if (!(isMethodOrAccessor(member) && isStatic(member))) {
1858                continue;
1859            }
1860            if (member.body) {
1861                member.body.forEachChild(function cb(node) {
1862                    if (node.kind === SyntaxKind.ThisKeyword) {
1863                        addRef(node);
1864                    }
1865                    else if (!isFunctionLike(node) && !isClassLike(node)) {
1866                        node.forEachChild(cb);
1867                    }
1868                });
1869            }
1870        }
1871    }
1872
1873    /**
1874     * `classSymbol` is the class where the constructor was defined.
1875     * Reference the constructor and all calls to `new this()`.
1876     */
1877    function findOwnConstructorReferences(classSymbol: Symbol, sourceFile: SourceFile, addNode: (node: Node) => void): void {
1878        const constructorSymbol = getClassConstructorSymbol(classSymbol);
1879        if (constructorSymbol && constructorSymbol.declarations) {
1880            for (const decl of constructorSymbol.declarations) {
1881                const ctrKeyword = findChildOfKind(decl, SyntaxKind.ConstructorKeyword, sourceFile)!;
1882                Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword);
1883                addNode(ctrKeyword);
1884            }
1885        }
1886
1887        if (classSymbol.exports) {
1888            classSymbol.exports.forEach(member => {
1889                const decl = member.valueDeclaration;
1890                if (decl && decl.kind === SyntaxKind.MethodDeclaration) {
1891                    const body = (decl as MethodDeclaration).body;
1892                    if (body) {
1893                        forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => {
1894                            if (isNewExpressionTarget(thisKeyword)) {
1895                                addNode(thisKeyword);
1896                            }
1897                        });
1898                    }
1899                }
1900            });
1901        }
1902    }
1903
1904    function getClassConstructorSymbol(classSymbol: Symbol): Symbol | undefined {
1905        return classSymbol.members && classSymbol.members.get(InternalSymbolName.Constructor);
1906    }
1907
1908    /** Find references to `super` in the constructor of an extending class.  */
1909    function findSuperConstructorAccesses(classDeclaration: ClassLikeDeclaration, addNode: (node: Node) => void): void {
1910        const constructor = getClassConstructorSymbol(classDeclaration.symbol);
1911        if (!(constructor && constructor.declarations)) {
1912            return;
1913        }
1914
1915        for (const decl of constructor.declarations) {
1916            Debug.assert(decl.kind === SyntaxKind.Constructor);
1917            const body = (decl as ConstructorDeclaration).body;
1918            if (body) {
1919                forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => {
1920                    if (isCallExpressionTarget(node)) {
1921                        addNode(node);
1922                    }
1923                });
1924            }
1925        }
1926    }
1927
1928    function hasOwnConstructor(classDeclaration: ClassLikeDeclaration): boolean {
1929        return !!getClassConstructorSymbol(classDeclaration.symbol);
1930    }
1931
1932    function findInheritedConstructorReferences(classDeclaration: ClassLikeDeclaration, state: State): void {
1933        if (hasOwnConstructor(classDeclaration)) return;
1934        const classSymbol = classDeclaration.symbol;
1935        const search = state.createSearch(/*location*/ undefined, classSymbol, /*comingFrom*/ undefined);
1936        getReferencesInContainerOrFiles(classSymbol, state, search);
1937    }
1938
1939    function addImplementationReferences(refNode: Node, addReference: (node: Node) => void, state: State): void {
1940        // Check if we found a function/propertyAssignment/method with an implementation or initializer
1941        if (isDeclarationName(refNode) && isImplementation(refNode.parent)) {
1942            addReference(refNode);
1943            return;
1944        }
1945
1946        if (refNode.kind !== SyntaxKind.Identifier) {
1947            return;
1948        }
1949
1950        if (refNode.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
1951            // Go ahead and dereference the shorthand assignment by going to its definition
1952            getReferenceEntriesForShorthandPropertyAssignment(refNode, state.checker, addReference);
1953        }
1954
1955        // Check if the node is within an extends or implements clause
1956        const containingClass = getContainingClassIfInHeritageClause(refNode);
1957        if (containingClass) {
1958            addReference(containingClass);
1959            return;
1960        }
1961
1962        // If we got a type reference, try and see if the reference applies to any expressions that can implement an interface
1963        // Find the first node whose parent isn't a type node -- i.e., the highest type node.
1964        const typeNode = findAncestor(refNode, a => !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent))!;
1965        const typeHavingNode = typeNode.parent;
1966        if (hasType(typeHavingNode) && typeHavingNode.type === typeNode && state.markSeenContainingTypeReference(typeHavingNode)) {
1967            if (hasInitializer(typeHavingNode)) {
1968                addIfImplementation(typeHavingNode.initializer!);
1969            }
1970            else if (isFunctionLike(typeHavingNode) && (typeHavingNode as FunctionLikeDeclaration).body) {
1971                const body = (typeHavingNode as FunctionLikeDeclaration).body!;
1972                if (body.kind === SyntaxKind.Block) {
1973                    forEachReturnStatement(body as Block, returnStatement => {
1974                        if (returnStatement.expression) addIfImplementation(returnStatement.expression);
1975                    });
1976                }
1977                else {
1978                    addIfImplementation(body);
1979                }
1980            }
1981            else if (isAssertionExpression(typeHavingNode)) {
1982                addIfImplementation(typeHavingNode.expression);
1983            }
1984        }
1985
1986        function addIfImplementation(e: Expression): void {
1987            if (isImplementationExpression(e)) addReference(e);
1988        }
1989    }
1990
1991    function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration | undefined {
1992        return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingClassIfInHeritageClause(node.parent)
1993            : isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, isClassLike) : undefined;
1994    }
1995
1996    /**
1997     * Returns true if this is an expression that can be considered an implementation
1998     */
1999    function isImplementationExpression(node: Expression): boolean {
2000        switch (node.kind) {
2001            case SyntaxKind.ParenthesizedExpression:
2002                return isImplementationExpression((node as ParenthesizedExpression).expression);
2003            case SyntaxKind.ArrowFunction:
2004            case SyntaxKind.FunctionExpression:
2005            case SyntaxKind.ObjectLiteralExpression:
2006            case SyntaxKind.ClassExpression:
2007            case SyntaxKind.ArrayLiteralExpression:
2008                return true;
2009            default:
2010                return false;
2011        }
2012    }
2013
2014    /**
2015     * Determines if the parent symbol occurs somewhere in the child's ancestry. If the parent symbol
2016     * is an interface, determines if some ancestor of the child symbol extends or inherits from it.
2017     * Also takes in a cache of previous results which makes this slightly more efficient and is
2018     * necessary to avoid potential loops like so:
2019     *     class A extends B { }
2020     *     class B extends A { }
2021     *
2022     * We traverse the AST rather than using the type checker because users are typically only interested
2023     * in explicit implementations of an interface/class when calling "Go to Implementation". Sibling
2024     * implementations of types that share a common ancestor with the type whose implementation we are
2025     * searching for need to be filtered out of the results. The type checker doesn't let us make the
2026     * distinction between structurally compatible implementations and explicit implementations, so we
2027     * must use the AST.
2028     *
2029     * @param symbol         A class or interface Symbol
2030     * @param parent        Another class or interface Symbol
2031     * @param cachedResults A map of symbol id pairs (i.e. "child,parent") to booleans indicating previous results
2032     */
2033    function explicitlyInheritsFrom(symbol: Symbol, parent: Symbol, cachedResults: ESMap<string, boolean>, checker: TypeChecker): boolean {
2034        if (symbol === parent) {
2035            return true;
2036        }
2037
2038        const key = getSymbolId(symbol) + "," + getSymbolId(parent);
2039        const cached = cachedResults.get(key);
2040        if (cached !== undefined) {
2041            return cached;
2042        }
2043
2044        // Set the key so that we don't infinitely recurse
2045        cachedResults.set(key, false);
2046
2047        const inherits = !!symbol.declarations && symbol.declarations.some(declaration =>
2048            getAllSuperTypeNodes(declaration).some(typeReference => {
2049                const type = checker.getTypeAtLocation(typeReference);
2050                return !!type && !!type.symbol && explicitlyInheritsFrom(type.symbol, parent, cachedResults, checker);
2051            }));
2052        cachedResults.set(key, inherits);
2053        return inherits;
2054    }
2055
2056    function getReferencesForSuperKeyword(superKeyword: Node): SymbolAndEntries[] | undefined {
2057        let searchSpaceNode = getSuperContainer(superKeyword, /*stopOnFunctions*/ false);
2058        if (!searchSpaceNode) {
2059            return undefined;
2060        }
2061        // Whether 'super' occurs in a static context within a class.
2062        let staticFlag = ModifierFlags.Static;
2063
2064        switch (searchSpaceNode.kind) {
2065            case SyntaxKind.PropertyDeclaration:
2066            case SyntaxKind.PropertySignature:
2067            case SyntaxKind.MethodDeclaration:
2068            case SyntaxKind.MethodSignature:
2069            case SyntaxKind.Constructor:
2070            case SyntaxKind.GetAccessor:
2071            case SyntaxKind.SetAccessor:
2072                staticFlag &= getSyntacticModifierFlags(searchSpaceNode);
2073                searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class
2074                break;
2075            default:
2076                return undefined;
2077        }
2078
2079        const sourceFile = searchSpaceNode.getSourceFile();
2080        const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, "super", searchSpaceNode), node => {
2081            if (node.kind !== SyntaxKind.SuperKeyword) {
2082                return;
2083            }
2084
2085            const container = getSuperContainer(node, /*stopOnFunctions*/ false);
2086
2087            // If we have a 'super' container, we must have an enclosing class.
2088            // Now make sure the owning class is the same as the search-space
2089            // and has the same static qualifier as the original 'super's owner.
2090            return container && isStatic(container) === !!staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
2091        });
2092
2093        return [{ definition: { type: DefinitionKind.Symbol, symbol: searchSpaceNode.symbol }, references }];
2094    }
2095
2096    function isParameterName(node: Node) {
2097        return node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.Parameter && (node.parent as ParameterDeclaration).name === node;
2098    }
2099
2100    function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
2101        let searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false);
2102
2103        // Whether 'this' occurs in a static context within a class.
2104        let staticFlag = ModifierFlags.Static;
2105
2106        switch (searchSpaceNode.kind) {
2107            case SyntaxKind.MethodDeclaration:
2108            case SyntaxKind.MethodSignature:
2109                if (isObjectLiteralMethod(searchSpaceNode)) {
2110                    staticFlag &= getSyntacticModifierFlags(searchSpaceNode);
2111                    searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning object literals
2112                    break;
2113                }
2114                // falls through
2115            case SyntaxKind.PropertyDeclaration:
2116            case SyntaxKind.PropertySignature:
2117            case SyntaxKind.Constructor:
2118            case SyntaxKind.GetAccessor:
2119            case SyntaxKind.SetAccessor:
2120                staticFlag &= getSyntacticModifierFlags(searchSpaceNode);
2121                searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class
2122                break;
2123            case SyntaxKind.SourceFile:
2124                if (isExternalModule(searchSpaceNode as SourceFile) || isParameterName(thisOrSuperKeyword)) {
2125                    return undefined;
2126                }
2127                // falls through
2128            case SyntaxKind.FunctionDeclaration:
2129            case SyntaxKind.FunctionExpression:
2130                break;
2131            // Computed properties in classes are not handled here because references to this are illegal,
2132            // so there is no point finding references to them.
2133            default:
2134                return undefined;
2135        }
2136
2137        const references = flatMap(searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFiles : [searchSpaceNode.getSourceFile()], sourceFile => {
2138            cancellationToken.throwIfCancellationRequested();
2139            return getPossibleSymbolReferenceNodes(sourceFile, "this", isSourceFile(searchSpaceNode) ? sourceFile : searchSpaceNode).filter(node => {
2140                if (!isThis(node)) {
2141                    return false;
2142                }
2143                const container = getThisContainer(node, /* includeArrowFunctions */ false);
2144                switch (searchSpaceNode.kind) {
2145                    case SyntaxKind.FunctionExpression:
2146                    case SyntaxKind.FunctionDeclaration:
2147                        return searchSpaceNode.symbol === container.symbol;
2148                    case SyntaxKind.MethodDeclaration:
2149                    case SyntaxKind.MethodSignature:
2150                        return isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol;
2151                    case SyntaxKind.ClassExpression:
2152                    case SyntaxKind.ClassDeclaration:
2153                    case SyntaxKind.ObjectLiteralExpression:
2154                        // Make sure the container belongs to the same class/object literals
2155                    case SyntaxKind.StructDeclaration:
2156                        // Make sure the container belongs to the same class
2157                        // and has the appropriate static modifier from the original container.
2158                        return container.parent && searchSpaceNode.symbol === container.parent.symbol && isStatic(container) === !!staticFlag;
2159                    case SyntaxKind.SourceFile:
2160                        return container.kind === SyntaxKind.SourceFile && !isExternalModule(container as SourceFile) && !isParameterName(node);
2161                }
2162            });
2163        }).map(n => nodeEntry(n));
2164
2165        const thisParameter = firstDefined(references, r => isParameter(r.node.parent) ? r.node : undefined);
2166        return [{
2167            definition: { type: DefinitionKind.This, node: thisParameter || thisOrSuperKeyword },
2168            references
2169        }];
2170    }
2171
2172    function getReferencesForStringLiteral(node: StringLiteralLike, sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken): SymbolAndEntries[] {
2173        const type = getContextualTypeFromParentOrAncestorTypeNode(node, checker);
2174        const references = flatMap(sourceFiles, sourceFile => {
2175            cancellationToken.throwIfCancellationRequested();
2176            return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, node.text), ref => {
2177                if (isStringLiteralLike(ref) && ref.text === node.text) {
2178                    if (type) {
2179                        const refType = getContextualTypeFromParentOrAncestorTypeNode(ref, checker);
2180                        if (type !== checker.getStringType() && type === refType) {
2181                            return nodeEntry(ref, EntryKind.StringLiteral);
2182                        }
2183                    }
2184                    else {
2185                        return isNoSubstitutionTemplateLiteral(ref) && !rangeIsOnSingleLine(ref, sourceFile) ? undefined :
2186                            nodeEntry(ref, EntryKind.StringLiteral);
2187                    }
2188                }
2189            });
2190        });
2191
2192        return [{
2193            definition: { type: DefinitionKind.String, node },
2194            references
2195        }];
2196    }
2197
2198    // For certain symbol kinds, we need to include other symbols in the search set.
2199    // This is not needed when searching for re-exports.
2200    function populateSearchSymbolSet(symbol: Symbol, location: Node, checker: TypeChecker, isForRename: boolean, providePrefixAndSuffixText: boolean, implementations: boolean): Symbol[] {
2201        const result: Symbol[] = [];
2202        forEachRelatedSymbol<void>(symbol, location, checker, isForRename, !(isForRename && providePrefixAndSuffixText),
2203            (sym, root, base) => {
2204                // static method/property and instance method/property might have the same name. Only include static or only include instance.
2205                if (base) {
2206                    if (isStaticSymbol(symbol) !== isStaticSymbol(base)) {
2207                        base = undefined;
2208                    }
2209                }
2210                result.push(base || root || sym);
2211            },
2212            // when try to find implementation, implementations is true, and not allowed to find base class
2213            /*allowBaseTypes*/() => !implementations);
2214        return result;
2215    }
2216
2217    /**
2218     * @param allowBaseTypes return true means it would try to find in base class or interface.
2219     */
2220    function forEachRelatedSymbol<T>(
2221        symbol: Symbol, location: Node, checker: TypeChecker, isForRenamePopulateSearchSymbolSet: boolean, onlyIncludeBindingElementAtReferenceLocation: boolean,
2222        /**
2223         * @param baseSymbol This symbol means one property/mehtod from base class or interface when it is not null or undefined,
2224         */
2225        cbSymbol: (symbol: Symbol, rootSymbol?: Symbol, baseSymbol?: Symbol, kind?: NodeEntryKind) => T | undefined,
2226        allowBaseTypes: (rootSymbol: Symbol) => boolean,
2227    ): T | undefined {
2228        const containingObjectLiteralElement = getContainingObjectLiteralElement(location);
2229        if (containingObjectLiteralElement) {
2230            /* Because in short-hand property assignment, location has two meaning : property name and as value of the property
2231            * When we do findAllReference at the position of the short-hand property assignment, we would want to have references to position of
2232            * property name and variable declaration of the identifier.
2233            * Like in below example, when querying for all references for an identifier 'name', of the property assignment, the language service
2234            * should show both 'name' in 'obj' and 'name' in variable declaration
2235            *      const name = "Foo";
2236            *      const obj = { name };
2237            * In order to do that, we will populate the search set with the value symbol of the identifier as a value of the property assignment
2238            * so that when matching with potential reference symbol, both symbols from property declaration and variable declaration
2239            * will be included correctly.
2240            */
2241            const shorthandValueSymbol = checker.getShorthandAssignmentValueSymbol(location.parent); // gets the local symbol
2242            if (shorthandValueSymbol && isForRenamePopulateSearchSymbolSet) {
2243                // When renaming 'x' in `const o = { x }`, just rename the local variable, not the property.
2244                return cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty);
2245            }
2246
2247            // If the location is in a context sensitive location (i.e. in an object literal) try
2248            // to get a contextual type for it, and add the property symbol from the contextual
2249            // type to the search set
2250            const contextualType = checker.getContextualType(containingObjectLiteralElement.parent);
2251            const res = contextualType && firstDefined(
2252                getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker, contextualType, /*unionSymbolOk*/ true),
2253                sym => fromRoot(sym, EntryKind.SearchedPropertyFoundLocal));
2254            if (res) return res;
2255
2256            // If the location is name of property symbol from object literal destructuring pattern
2257            // Search the property symbol
2258            //      for ( { property: p2 } of elems) { }
2259            const propertySymbol = getPropertySymbolOfDestructuringAssignment(location, checker);
2260            const res1 = propertySymbol && cbSymbol(propertySymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedPropertyFoundLocal);
2261            if (res1) return res1;
2262
2263            const res2 = shorthandValueSymbol && cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty);
2264            if (res2) return res2;
2265        }
2266
2267        const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration(location, symbol, checker);
2268        if (aliasedSymbol) {
2269            // In case of UMD module and global merging, search for global as well
2270            const res = cbSymbol(aliasedSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node);
2271            if (res) return res;
2272        }
2273
2274        const res = fromRoot(symbol);
2275        if (res) return res;
2276
2277        if (symbol.valueDeclaration && isParameterPropertyDeclaration(symbol.valueDeclaration, symbol.valueDeclaration.parent)) {
2278            // For a parameter property, now try on the other symbol (property if this was a parameter, parameter if this was a property).
2279            const paramProps = checker.getSymbolsOfParameterPropertyDeclaration(cast(symbol.valueDeclaration, isParameter), symbol.name);
2280            Debug.assert(paramProps.length === 2 && !!(paramProps[0].flags & SymbolFlags.FunctionScopedVariable) && !!(paramProps[1].flags & SymbolFlags.Property)); // is [parameter, property]
2281            return fromRoot(symbol.flags & SymbolFlags.FunctionScopedVariable ? paramProps[1] : paramProps[0]);
2282        }
2283
2284        const exportSpecifier = getDeclarationOfKind<ExportSpecifier>(symbol, SyntaxKind.ExportSpecifier);
2285        if (!isForRenamePopulateSearchSymbolSet || exportSpecifier && !exportSpecifier.propertyName) {
2286            const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier);
2287            if (localSymbol) {
2288                const res = cbSymbol(localSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node);
2289                if (res) return res;
2290            }
2291        }
2292
2293        // symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property.
2294        // Don't do this when populating search set for a rename when prefix and suffix text will be provided -- just rename the local.
2295        if (!isForRenamePopulateSearchSymbolSet) {
2296            let bindingElementPropertySymbol: Symbol | undefined;
2297            if (onlyIncludeBindingElementAtReferenceLocation) {
2298                bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined;
2299            }
2300            else {
2301                bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker);
2302            }
2303            return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal);
2304        }
2305
2306        Debug.assert(isForRenamePopulateSearchSymbolSet);
2307        // due to the above assert and the arguments at the uses of this function,
2308        // (onlyIncludeBindingElementAtReferenceLocation <=> !providePrefixAndSuffixTextForRename) holds
2309        const includeOriginalSymbolOfBindingElement = onlyIncludeBindingElementAtReferenceLocation;
2310
2311        if (includeOriginalSymbolOfBindingElement) {
2312            const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker);
2313            return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal);
2314        }
2315
2316        function fromRoot(sym: Symbol, kind?: NodeEntryKind): T | undefined {
2317            // If this is a union property:
2318            //   - In populateSearchSymbolsSet we will add all the symbols from all its source symbols in all unioned types.
2319            //   - In findRelatedSymbol, we will just use the union symbol if any source symbol is included in the search.
2320            // If the symbol is an instantiation from a another symbol (e.g. widened symbol):
2321            //   - In populateSearchSymbolsSet, add the root the list
2322            //   - In findRelatedSymbol, return the source symbol if that is in the search. (Do not return the instantiation symbol.)
2323            return firstDefined(checker.getRootSymbols(sym), rootSymbol =>
2324                cbSymbol(sym, rootSymbol, /*baseSymbol*/ undefined, kind)
2325                // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
2326                || (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface) && allowBaseTypes(rootSymbol)
2327                    ? getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker, base => cbSymbol(sym, rootSymbol, base, kind))
2328                    : undefined));
2329        }
2330
2331        function getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol: Symbol, checker: TypeChecker): Symbol | undefined {
2332            const bindingElement = getDeclarationOfKind<BindingElement>(symbol, SyntaxKind.BindingElement);
2333            if (bindingElement && isObjectBindingElementWithoutPropertyName(bindingElement)) {
2334                return getPropertySymbolFromBindingElement(checker, bindingElement);
2335            }
2336        }
2337    }
2338
2339    /**
2340     * Find symbol of the given property-name and add the symbol to the given result array
2341     * @param symbol a symbol to start searching for the given propertyName
2342     * @param propertyName a name of property to search for
2343     * @param result an array of symbol of found property symbols
2344     * @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol.
2345     *                                The value of previousIterationSymbol is undefined when the function is first called.
2346     */
2347    function getPropertySymbolsFromBaseTypes<T>(symbol: Symbol, propertyName: string, checker: TypeChecker, cb: (symbol: Symbol) => T | undefined): T | undefined {
2348        const seen = new Map<SymbolId, true>();
2349        return recur(symbol);
2350
2351        function recur(symbol: Symbol): T | undefined {
2352            // Use `addToSeen` to ensure we don't infinitely recurse in this situation:
2353            //      interface C extends C {
2354            //          /*findRef*/propName: string;
2355            //      }
2356            if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return;
2357
2358            return firstDefined(symbol.declarations, declaration => firstDefined(getAllSuperTypeNodes(declaration), typeReference => {
2359                const type = checker.getTypeAtLocation(typeReference);
2360                const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName);
2361                // Visit the typeReference as well to see if it directly or indirectly uses that property
2362                return type && propertySymbol && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type.symbol));
2363            }));
2364        }
2365    }
2366
2367    interface RelatedSymbol {
2368        readonly symbol: Symbol;
2369        readonly kind: NodeEntryKind | undefined;
2370    }
2371
2372    function isStaticSymbol(symbol: Symbol): boolean {
2373        if (!symbol.valueDeclaration) return false;
2374        const modifierFlags = getEffectiveModifierFlags(symbol.valueDeclaration);
2375        return !!(modifierFlags & ModifierFlags.Static);
2376    }
2377
2378    function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): RelatedSymbol | undefined {
2379        const { checker } = state;
2380        return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker, /*isForRenamePopulateSearchSymbolSet*/ false,
2381            /*onlyIncludeBindingElementAtReferenceLocation*/ state.options.use !== FindReferencesUse.Rename || !!state.options.providePrefixAndSuffixTextForRename,
2382            (sym, rootSymbol, baseSymbol, kind): RelatedSymbol | undefined => {
2383                // check whether the symbol used to search itself is just the searched one.
2384                if (baseSymbol) {
2385                    // static method/property and instance method/property might have the same name. Only check static or only check instance.
2386                    if (isStaticSymbol(referenceSymbol) !== isStaticSymbol(baseSymbol)) {
2387                        baseSymbol = undefined;
2388                    }
2389                }
2390                return search.includes(baseSymbol || rootSymbol || sym)
2391                    // For a base type, use the symbol for the derived type. For a synthetic (e.g. union) property, use the union symbol.
2392                    ? { symbol: rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym, kind }
2393                    : undefined;
2394            },
2395            /*allowBaseTypes*/ rootSymbol =>
2396                !(search.parents && !search.parents.some(parent => explicitlyInheritsFrom(rootSymbol.parent!, parent, state.inheritsFromCache, checker)))
2397        );
2398    }
2399
2400    /**
2401     * Given an initial searchMeaning, extracted from a location, widen the search scope based on the declarations
2402     * of the corresponding symbol. e.g. if we are searching for "Foo" in value position, but "Foo" references a class
2403     * then we need to widen the search to include type positions as well.
2404     * On the contrary, if we are searching for "Bar" in type position and we trace bar to an interface, and an uninstantiated
2405     * module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module)
2406     * do not intersect in any of the three spaces.
2407     */
2408    export function getIntersectingMeaningFromDeclarations(node: Node, symbol: Symbol): SemanticMeaning {
2409        let meaning = getMeaningFromLocation(node);
2410        const { declarations } = symbol;
2411        if (declarations) {
2412            let lastIterationMeaning: SemanticMeaning;
2413            do {
2414                // The result is order-sensitive, for instance if initialMeaning === Namespace, and declarations = [class, instantiated module]
2415                // we need to consider both as they initialMeaning intersects with the module in the namespace space, and the module
2416                // intersects with the class in the value space.
2417                // To achieve that we will keep iterating until the result stabilizes.
2418
2419                // Remember the last meaning
2420                lastIterationMeaning = meaning;
2421
2422                for (const declaration of declarations) {
2423                    const declarationMeaning = getMeaningFromDeclaration(declaration);
2424
2425                    if (declarationMeaning & meaning) {
2426                        meaning |= declarationMeaning;
2427                    }
2428                }
2429            }
2430            while (meaning !== lastIterationMeaning);
2431        }
2432        return meaning;
2433    }
2434
2435    function isImplementation(node: Node): boolean {
2436        return !!(node.flags & NodeFlags.Ambient) ? !(isInterfaceDeclaration(node) || isTypeAliasDeclaration(node)) :
2437            (isVariableLike(node) ? hasInitializer(node) :
2438            isFunctionLikeDeclaration(node) ? !!node.body :
2439            isClassLike(node) || isModuleOrEnumDeclaration(node));
2440    }
2441
2442    export function getReferenceEntriesForShorthandPropertyAssignment(node: Node, checker: TypeChecker, addReference: (node: Node) => void): void {
2443        const refSymbol = checker.getSymbolAtLocation(node)!;
2444        const shorthandSymbol = checker.getShorthandAssignmentValueSymbol(refSymbol.valueDeclaration);
2445
2446        if (shorthandSymbol) {
2447            for (const declaration of shorthandSymbol.getDeclarations()!) {
2448                if (getMeaningFromDeclaration(declaration) & SemanticMeaning.Value) {
2449                    addReference(declaration);
2450                }
2451            }
2452        }
2453    }
2454
2455    function forEachDescendantOfKind(node: Node, kind: SyntaxKind, action: (node: Node) => void): void {
2456        forEachChild(node, child => {
2457            if (child.kind === kind) {
2458                action(child);
2459            }
2460            forEachDescendantOfKind(child, kind, action);
2461        });
2462    }
2463
2464    /** Get `C` given `N` if `N` is in the position `class C extends N` or `class C extends foo.N` where `N` is an identifier. */
2465    function tryGetClassByExtendingIdentifier(node: Node): ClassLikeDeclaration | undefined {
2466        return tryGetClassExtendingExpressionWithTypeArguments(climbPastPropertyAccess(node).parent);
2467    }
2468
2469    /**
2470     * If we are just looking for implementations and this is a property access expression, we need to get the
2471     * symbol of the local type of the symbol the property is being accessed on. This is because our search
2472     * symbol may have a different parent symbol if the local type's symbol does not declare the property
2473     * being accessed (i.e. it is declared in some parent class or interface)
2474     */
2475    function getParentSymbolsOfPropertyAccess(location: Node, symbol: Symbol, checker: TypeChecker): readonly Symbol[] | undefined {
2476        const propertyAccessExpression = isRightSideOfPropertyAccess(location) ? location.parent as PropertyAccessExpression : undefined;
2477        const lhsType = propertyAccessExpression && checker.getTypeAtLocation(propertyAccessExpression.expression);
2478        const res = mapDefined(lhsType && (lhsType.isUnionOrIntersection() ? lhsType.types : lhsType.symbol === symbol.parent ? undefined : [lhsType]), t =>
2479            t.symbol && t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? t.symbol : undefined);
2480        return res.length === 0 ? undefined : res;
2481    }
2482
2483    function isForRenameWithPrefixAndSuffixText(options: Options) {
2484        return options.use === FindReferencesUse.Rename && options.providePrefixAndSuffixTextForRename;
2485    }
2486}
2487