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