Skip to content

Commit f34de1a

Browse files
author
Andy
authored
Support find-all-references starting from a reference path or reference types comment (#21007)
1 parent fef7ad4 commit f34de1a

File tree

5 files changed

+41
-46
lines changed

5 files changed

+41
-46
lines changed

src/services/documentHighlights.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,15 @@
22
namespace ts.DocumentHighlights {
33
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] | undefined {
44
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
5-
// Note that getTouchingWord indicates failure by returning the sourceFile node.
6-
if (node === sourceFile) return undefined;
75

8-
Debug.assert(node.parent !== undefined);
9-
10-
if (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent)) {
6+
if (node.parent && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent))) {
117
// For a JSX element, just highlight the matching tag, not all references.
128
const { openingElement, closingElement } = node.parent.parent;
139
const highlightSpans = [openingElement, closingElement].map(({ tagName }) => getHighlightSpanForNode(tagName, sourceFile));
1410
return [{ fileName: sourceFile.fileName, highlightSpans }];
1511
}
1612

17-
return getSemanticDocumentHighlights(node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile);
13+
return getSemanticDocumentHighlights(position, node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile);
1814
}
1915

2016
function getHighlightSpanForNode(node: Node, sourceFile: SourceFile): HighlightSpan {
@@ -25,8 +21,8 @@ namespace ts.DocumentHighlights {
2521
};
2622
}
2723

28-
function getSemanticDocumentHighlights(node: Node, program: Program, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
29-
const referenceEntries = FindAllReferences.getReferenceEntriesForNode(node, program, sourceFilesToSearch, cancellationToken);
24+
function getSemanticDocumentHighlights(position: number, node: Node, program: Program, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
25+
const referenceEntries = FindAllReferences.getReferenceEntriesForNode(position, node, program, sourceFilesToSearch, cancellationToken);
3026
return referenceEntries && convertReferencedSymbols(referenceEntries);
3127
}
3228

src/services/findAllReferences.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ namespace ts.FindAllReferences {
5252
export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ImplementationLocation[] {
5353
// A node in a JSDoc comment can't have an implementation anyway.
5454
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ false);
55-
const referenceEntries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node);
55+
const referenceEntries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node, position);
5656
const checker = program.getTypeChecker();
5757
return map(referenceEntries, entry => toImplementationLocation(entry, checker));
5858
}
5959

60-
function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node): Entry[] | undefined {
60+
function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node, position: number): Entry[] | undefined {
6161
if (node.kind === SyntaxKind.SourceFile) {
6262
return undefined;
6363
}
@@ -78,7 +78,7 @@ namespace ts.FindAllReferences {
7878
}
7979
else {
8080
// Perform "Find all References" and retrieve only those that are implementations
81-
return getReferenceEntriesForNode(node, program, sourceFiles, cancellationToken, { implementations: true });
81+
return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { implementations: true });
8282
}
8383
}
8484

@@ -87,13 +87,13 @@ namespace ts.FindAllReferences {
8787
return map(x, toReferenceEntry);
8888
}
8989

90-
export function getReferenceEntriesForNode(node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}): Entry[] | undefined {
91-
return flattenEntries(Core.getReferencedSymbolsForNode(node, program, sourceFiles, cancellationToken, options));
90+
export function getReferenceEntriesForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}): Entry[] | undefined {
91+
return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options));
9292
}
9393

9494
function findAllReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number, options?: Options): SymbolAndEntries[] | undefined {
9595
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
96-
return Core.getReferencedSymbolsForNode(node, program, sourceFiles, cancellationToken, options);
96+
return Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options);
9797
}
9898

9999
function flattenEntries(referenceSymbols: SymbolAndEntries[]): Entry[] {
@@ -242,9 +242,10 @@ namespace ts.FindAllReferences {
242242
/* @internal */
243243
namespace ts.FindAllReferences.Core {
244244
/** Core find-all-references algorithm. Handles special cases before delegating to `getReferencedSymbolsForSymbol`. */
245-
export function getReferencedSymbolsForNode(node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}): SymbolAndEntries[] | undefined {
246-
if (node.kind === ts.SyntaxKind.SourceFile) {
247-
return undefined;
245+
export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}): SymbolAndEntries[] | undefined {
246+
if (isSourceFile(node)) {
247+
const reference = GoToDefinition.getReferenceAtPosition(node, position, program);
248+
return reference && getReferencedSymbolsForModule(program, program.getTypeChecker().getMergedSymbol(reference.file.symbol), sourceFiles);
248249
}
249250

250251
if (!options.implementations) {
@@ -260,11 +261,7 @@ namespace ts.FindAllReferences.Core {
260261
// Could not find a symbol e.g. unknown identifier
261262
if (!symbol) {
262263
// String literal might be a property (and thus have a symbol), so do this here rather than in getReferencedSymbolsSpecial.
263-
if (!options.implementations && node.kind === SyntaxKind.StringLiteral) {
264-
return getReferencesForStringLiteral(<StringLiteral>node, sourceFiles, cancellationToken);
265-
}
266-
// Can't have references to something that we have no symbol for.
267-
return undefined;
264+
return !options.implementations && isStringLiteral(node) ? getReferencesForStringLiteral(node, sourceFiles, cancellationToken) : undefined;
268265
}
269266

270267
if (symbol.flags & SymbolFlags.Module && isModuleReferenceLocation(node)) {

src/services/goToDefinition.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,9 @@
11
/* @internal */
22
namespace ts.GoToDefinition {
33
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): DefinitionInfo[] {
4-
/// Triple slash reference comments
5-
const comment = findReferenceInPosition(sourceFile.referencedFiles, position);
6-
if (comment) {
7-
const referenceFile = tryResolveScriptReference(program, sourceFile, comment);
8-
if (referenceFile) {
9-
return [getDefinitionInfoForFileReference(comment.fileName, referenceFile.fileName)];
10-
}
11-
// Might still be on jsdoc, so keep looking.
12-
}
13-
14-
// Type reference directives
15-
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
16-
if (typeReferenceDirective) {
17-
const referenceFile = program.getResolvedTypeReferenceDirectives().get(typeReferenceDirective.fileName);
18-
return referenceFile && referenceFile.resolvedFileName &&
19-
[getDefinitionInfoForFileReference(typeReferenceDirective.fileName, referenceFile.resolvedFileName)];
4+
const reference = getReferenceAtPosition(sourceFile, position, program);
5+
if (reference) {
6+
return [getDefinitionInfoForFileReference(reference.fileName, reference.file.fileName)];
207
}
218

229
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
@@ -115,6 +102,23 @@ namespace ts.GoToDefinition {
115102
return getDefinitionFromSymbol(typeChecker, symbol, node);
116103
}
117104

105+
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { fileName: string, file: SourceFile } | undefined {
106+
const referencePath = findReferenceInPosition(sourceFile.referencedFiles, position);
107+
if (referencePath) {
108+
const file = tryResolveScriptReference(program, sourceFile, referencePath);
109+
return file && { fileName: referencePath.fileName, file };
110+
}
111+
112+
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
113+
if (typeReferenceDirective) {
114+
const reference = program.getResolvedTypeReferenceDirectives().get(typeReferenceDirective.fileName);
115+
const file = reference && program.getSourceFile(reference.resolvedFileName);
116+
return file && { fileName: typeReferenceDirective.fileName, file };
117+
}
118+
119+
return undefined;
120+
}
121+
118122
/// Goto type
119123
export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): DefinitionInfo[] {
120124
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
@@ -301,7 +305,7 @@ namespace ts.GoToDefinition {
301305
return createDefinitionInfo(decl, symbolKind, symbolName, containerName);
302306
}
303307

304-
function findReferenceInPosition(refs: ReadonlyArray<FileReference>, pos: number): FileReference {
308+
export function findReferenceInPosition(refs: ReadonlyArray<FileReference>, pos: number): FileReference {
305309
for (const ref of refs) {
306310
if (ref.pos <= pos && pos <= ref.end) {
307311
return ref;

tests/cases/fourslash/findAllRefsForModule.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
////const a = require("[|../a|]");
1313

1414
// @Filename: /d.ts
15-
//// /// <reference path="[|./a|]" />
15+
//// /// <reference path="[|./a.ts|]" />
1616

1717
verify.noErrors();
1818

1919
const ranges = test.ranges();
2020
const [r0, r1, r2] = ranges;
21-
verify.referenceGroups([r0, r1], [{ definition: 'module "/a"', ranges: [r0, r2, r1] }]);
22-
// TODO:GH#15736
23-
verify.referenceGroups(r2, undefined);
21+
verify.referenceGroups(ranges, [{ definition: 'module "/a"', ranges: [r0, r2, r1] }]);
22+
// Testing that it works with documentHighlights too
23+
verify.rangesAreDocumentHighlights();

tests/cases/fourslash/findAllRefsForModuleGlobal.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,4 @@ verify.noErrors();
1212

1313
const ranges = test.ranges();
1414
const [r0, r1, r2] = ranges;
15-
verify.referenceGroups([r1, r2], [{ definition: 'module "/node_modules/foo/index"', ranges: [r0, r1, r2] }]);
16-
// TODO:GH#15736
17-
verify.referenceGroups(r0, undefined);
15+
verify.singleReferenceGroup('module "/node_modules/foo/index"');

0 commit comments

Comments
 (0)