Skip to content

Commit 7cca4ba

Browse files
author
Andy
authored
Merge pull request #16081 from Microsoft/findAllRefs-state
findAllRefs: Replace 'interface State' and 'createState' with just 'class State'
2 parents 2e6f31f + 528a59f commit 7cca4ba

File tree

1 file changed

+50
-69
lines changed

1 file changed

+50
-69
lines changed

src/services/findAllReferences.ts

Lines changed: 50 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ namespace ts.FindAllReferences.Core {
386386
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), symbol.declarations);
387387

388388
const result: SymbolAndEntries[] = [];
389-
const state = createState(sourceFiles, node, checker, cancellationToken, searchMeaning, options, result);
389+
const state = new State(sourceFiles, /*isForConstructor*/ node.kind === SyntaxKind.ConstructorKeyword, checker, cancellationToken, searchMeaning, options, result);
390390
const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: populateSearchSymbolSet(symbol, node, checker, options.implementations) });
391391

392392
// Try to get the smallest valid scope that we can limit our search to;
@@ -446,35 +446,9 @@ namespace ts.FindAllReferences.Core {
446446
* Holds all state needed for the finding references.
447447
* Unlike `Search`, there is only one `State`.
448448
*/
449-
interface State extends Options {
450-
/** True if we're searching for constructor references. */
451-
readonly isForConstructor: boolean;
452-
453-
readonly sourceFiles: SourceFile[];
454-
readonly checker: TypeChecker;
455-
readonly cancellationToken: CancellationToken;
456-
readonly searchMeaning: SemanticMeaning;
457-
449+
class State {
458450
/** Cache for `explicitlyinheritsFrom`. */
459-
readonly inheritsFromCache: Map<boolean>;
460-
461-
/** Gets every place to look for references of an exported symbols. See `ImportsResult` in `importTracker.ts` for more documentation. */
462-
getImportSearches(exportSymbol: Symbol, exportInfo: ExportInfo): ImportsResult;
463-
464-
/** @param allSearchSymbols set of additinal symbols for use by `includes`. */
465-
createSearch(location: Node, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions?: { text?: string, allSearchSymbols?: Symbol[] }): Search;
466-
467-
/**
468-
* Callback to add references for a particular searched symbol.
469-
* This initializes a reference group, so only call this if you will add at least one reference.
470-
*/
471-
referenceAdder(searchSymbol: Symbol, searchLocation: Node): (node: Node) => void;
472-
473-
/** Add a reference with no associated definition. */
474-
addStringOrCommentReference(fileName: string, textSpan: TextSpan): void;
475-
476-
/** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */
477-
markSearchedSymbol(sourceFile: SourceFile, symbol: Symbol): boolean;
451+
readonly inheritsFromCache = createMap<boolean>();
478452

479453
/**
480454
* Type nodes can contain multiple references to the same type. For example:
@@ -483,7 +457,7 @@ namespace ts.FindAllReferences.Core {
483457
* duplicate entries would be returned here as each of the type references is part of
484458
* the same implementation. For that reason, check before we add a new entry.
485459
*/
486-
markSeenContainingTypeReference(containingTypeReference: Node): boolean;
460+
readonly markSeenContainingTypeReference = nodeSeenTracker();
487461

488462
/**
489463
* It's possible that we will encounter the right side of `export { foo as bar } from "x";` more than once.
@@ -496,61 +470,68 @@ namespace ts.FindAllReferences.Core {
496470
* But another reference to it may appear in the same source file.
497471
* See `tests/cases/fourslash/transitiveExportImports3.ts`.
498472
*/
499-
markSeenReExportRHS(rhs: Identifier): boolean;
500-
}
501-
502-
function createState(sourceFiles: SourceFile[], originalLocation: Node, checker: TypeChecker, cancellationToken: CancellationToken, searchMeaning: SemanticMeaning, options: Options, result: Push<SymbolAndEntries>): State {
503-
const symbolIdToReferences: Entry[][] = [];
504-
const inheritsFromCache = createMap<boolean>();
505-
// Source file ID → symbol ID → Whether the symbol has been searched for in the source file.
506-
const sourceFileToSeenSymbols: Array<Array<true>> = [];
507-
const isForConstructor = originalLocation.kind === SyntaxKind.ConstructorKeyword;
508-
let importTracker: ImportTracker | undefined;
509-
510-
return {
511-
...options,
512-
sourceFiles, isForConstructor, checker, cancellationToken, searchMeaning, inheritsFromCache, getImportSearches, createSearch, referenceAdder, addStringOrCommentReference,
513-
markSearchedSymbol, markSeenContainingTypeReference: nodeSeenTracker(), markSeenReExportRHS: nodeSeenTracker(),
514-
};
515-
516-
function getImportSearches(exportSymbol: Symbol, exportInfo: ExportInfo): ImportsResult {
517-
if (!importTracker) importTracker = createImportTracker(sourceFiles, checker, cancellationToken);
518-
return importTracker(exportSymbol, exportInfo, options.isForRename);
473+
readonly markSeenReExportRHS = nodeSeenTracker();
474+
475+
constructor(
476+
readonly sourceFiles: SourceFile[],
477+
/** True if we're searching for constructor references. */
478+
readonly isForConstructor: boolean,
479+
readonly checker: TypeChecker,
480+
readonly cancellationToken: CancellationToken,
481+
readonly searchMeaning: SemanticMeaning,
482+
readonly options: Options,
483+
private readonly result: Push<SymbolAndEntries>) {}
484+
485+
private importTracker: ImportTracker | undefined;
486+
/** Gets every place to look for references of an exported symbols. See `ImportsResult` in `importTracker.ts` for more documentation. */
487+
getImportSearches(exportSymbol: Symbol, exportInfo: ExportInfo): ImportsResult {
488+
if (!this.importTracker) this.importTracker = createImportTracker(this.sourceFiles, this.checker, this.cancellationToken);
489+
return this.importTracker(exportSymbol, exportInfo, this.options.isForRename);
519490
}
520491

521-
function createSearch(location: Node, symbol: Symbol, comingFrom: ImportExport, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search {
492+
/** @param allSearchSymbols set of additinal symbols for use by `includes`. */
493+
createSearch(location: Node, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search {
522494
// Note: if this is an external module symbol, the name doesn't include quotes.
523-
const { text = stripQuotes(getDeclaredName(checker, symbol, location)), allSearchSymbols = undefined } = searchOptions;
495+
const { text = stripQuotes(getDeclaredName(this.checker, symbol, location)), allSearchSymbols = undefined } = searchOptions;
524496
const escapedText = escapeIdentifier(text);
525-
const parents = options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, checker);
497+
const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker);
526498
return { location, symbol, comingFrom, text, escapedText, parents, includes };
527499

528500
function includes(referenceSymbol: Symbol): boolean {
529501
return allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol;
530502
}
531503
}
532504

533-
function referenceAdder(referenceSymbol: Symbol, searchLocation: Node): (node: Node) => void {
534-
const symbolId = getSymbolId(referenceSymbol);
535-
let references = symbolIdToReferences[symbolId];
505+
private readonly symbolIdToReferences: Entry[][] = [];
506+
/**
507+
* Callback to add references for a particular searched symbol.
508+
* This initializes a reference group, so only call this if you will add at least one reference.
509+
*/
510+
referenceAdder(searchSymbol: Symbol, searchLocation: Node): (node: Node) => void {
511+
const symbolId = getSymbolId(searchSymbol);
512+
let references = this.symbolIdToReferences[symbolId];
536513
if (!references) {
537-
references = symbolIdToReferences[symbolId] = [];
538-
result.push({ definition: { type: "symbol", symbol: referenceSymbol, node: searchLocation }, references });
514+
references = this.symbolIdToReferences[symbolId] = [];
515+
this.result.push({ definition: { type: "symbol", symbol: searchSymbol, node: searchLocation }, references });
539516
}
540517
return node => references.push(nodeEntry(node));
541518
}
542519

543-
function addStringOrCommentReference(fileName: string, textSpan: TextSpan): void {
544-
result.push({
520+
/** Add a reference with no associated definition. */
521+
addStringOrCommentReference(fileName: string, textSpan: TextSpan): void {
522+
this.result.push({
545523
definition: undefined,
546524
references: [{ type: "span", fileName, textSpan }]
547525
});
548526
}
549527

550-
function markSearchedSymbol(sourceFile: SourceFile, symbol: Symbol): boolean {
528+
// Source file ID → symbol ID → Whether the symbol has been searched for in the source file.
529+
private readonly sourceFileToSeenSymbols: Array<Array<true>> = [];
530+
/** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */
531+
markSearchedSymbol(sourceFile: SourceFile, symbol: Symbol): boolean {
551532
const sourceId = getNodeId(sourceFile);
552533
const symbolId = getSymbolId(symbol);
553-
const seenSymbols = sourceFileToSeenSymbols[sourceId] || (sourceFileToSeenSymbols[sourceId] = []);
534+
const seenSymbols = this.sourceFileToSeenSymbols[sourceId] || (this.sourceFileToSeenSymbols[sourceId] = []);
554535
return !seenSymbols[symbolId] && (seenSymbols[symbolId] = true);
555536
}
556537
}
@@ -580,7 +561,7 @@ namespace ts.FindAllReferences.Core {
580561
break;
581562
case ExportKind.Default:
582563
// Search for a property access to '.default'. This can't be renamed.
583-
indirectSearch = state.isForRename ? undefined : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" });
564+
indirectSearch = state.options.isForRename ? undefined : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" });
584565
break;
585566
case ExportKind.ExportEquals:
586567
break;
@@ -803,7 +784,7 @@ namespace ts.FindAllReferences.Core {
803784
return;
804785
}
805786

806-
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, /*fullStart*/ state.findInComments || container.jsDoc !== undefined)) {
787+
for (const position of getPossibleSymbolReferencePositions(sourceFile, search.text, container, /*fullStart*/ state.options.findInComments || container.jsDoc !== undefined)) {
807788
getReferencesAtLocation(sourceFile, position, search, state);
808789
}
809790
}
@@ -815,7 +796,7 @@ namespace ts.FindAllReferences.Core {
815796
// This wasn't the start of a token. Check to see if it might be a
816797
// match in a comment or string if that's what the caller is asking
817798
// for.
818-
if (!state.implementations && (state.findInStrings && isInString(sourceFile, position) || state.findInComments && isInNonReferenceComment(sourceFile, position))) {
799+
if (!state.options.implementations && (state.options.findInStrings && isInString(sourceFile, position) || state.options.findInComments && isInNonReferenceComment(sourceFile, position))) {
819800
// In the case where we're looking inside comments/strings, we don't have
820801
// an actual definition. So just use 'undefined' here. Features like
821802
// 'Rename' won't care (as they ignore the definitions), and features like
@@ -881,7 +862,7 @@ namespace ts.FindAllReferences.Core {
881862
addRef();
882863
}
883864

884-
if (!state.isForRename && state.markSeenReExportRHS(name)) {
865+
if (!state.options.isForRename && state.markSeenReExportRHS(name)) {
885866
addReference(name, referenceSymbol, name, state);
886867
}
887868
}
@@ -892,7 +873,7 @@ namespace ts.FindAllReferences.Core {
892873
}
893874

894875
// For `export { foo as bar }`, rename `foo`, but not `bar`.
895-
if (!(referenceLocation === propertyName && state.isForRename)) {
876+
if (!(referenceLocation === propertyName && state.options.isForRename)) {
896877
const exportKind = (referenceLocation as Identifier).originalKeywordKind === ts.SyntaxKind.DefaultKeyword ? ExportKind.Default : ExportKind.Named;
897878
const exportInfo = getExportInfo(referenceSymbol, exportKind, state.checker);
898879
Debug.assert(!!exportInfo);
@@ -934,7 +915,7 @@ namespace ts.FindAllReferences.Core {
934915
const { symbol } = importOrExport;
935916

936917
if (importOrExport.kind === ImportExport.Import) {
937-
if (!state.isForRename || importOrExport.isNamedImport) {
918+
if (!state.options.isForRename || importOrExport.isNamedImport) {
938919
searchForImportedSymbol(symbol, state);
939920
}
940921
}
@@ -960,7 +941,7 @@ namespace ts.FindAllReferences.Core {
960941

961942
function addReference(referenceLocation: Node, relatedSymbol: Symbol, searchLocation: Node, state: State): void {
962943
const addRef = state.referenceAdder(relatedSymbol, searchLocation);
963-
if (state.implementations) {
944+
if (state.options.implementations) {
964945
addImplementationReferences(referenceLocation, addRef, state);
965946
}
966947
else {

0 commit comments

Comments
 (0)