Skip to content

Commit 38ece3b

Browse files
author
Andy
authored
Merge pull request #15737 from Microsoft/findAllRefs_module
Support find-all-references for a module specifier
2 parents 7325c89 + eec8240 commit 38ece3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+311
-155
lines changed

src/compiler/program.ts

+45-32
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,8 @@ namespace ts {
529529
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
530530
getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
531531
isSourceFileFromExternalLibrary,
532-
dropDiagnosticsProducingTypeChecker
532+
dropDiagnosticsProducingTypeChecker,
533+
getSourceFileFromReference,
533534
};
534535

535536
verifyCompilerOptions();
@@ -1442,48 +1443,60 @@ namespace ts {
14421443
}
14431444
}
14441445

1445-
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number) {
1446-
let diagnosticArgument: string[];
1447-
let diagnostic: DiagnosticMessage;
1446+
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
1447+
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
1448+
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName, currentDirectory, getCanonicalFileName)));
1449+
}
1450+
1451+
function getSourceFileFromReferenceWorker(
1452+
fileName: string,
1453+
getSourceFile: (fileName: string) => SourceFile | undefined,
1454+
fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
1455+
refFile?: SourceFile): SourceFile | undefined {
1456+
14481457
if (hasExtension(fileName)) {
14491458
if (!options.allowNonTsExtensions && !forEach(supportedExtensions, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
1450-
diagnostic = Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1;
1451-
diagnosticArgument = [fileName, "'" + supportedExtensions.join("', '") + "'"];
1452-
}
1453-
else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd)) {
1454-
diagnostic = Diagnostics.File_0_not_found;
1455-
diagnosticArgument = [fileName];
1459+
if (fail) fail(Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + supportedExtensions.join("', '") + "'");
1460+
return undefined;
14561461
}
1457-
else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) {
1458-
diagnostic = Diagnostics.A_file_cannot_have_a_reference_to_itself;
1459-
diagnosticArgument = [fileName];
1460-
}
1461-
}
1462-
else {
1463-
const nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd);
1464-
if (!nonTsFile) {
1465-
if (options.allowNonTsExtensions) {
1466-
diagnostic = Diagnostics.File_0_not_found;
1467-
diagnosticArgument = [fileName];
1462+
1463+
const sourceFile = getSourceFile(fileName);
1464+
if (fail) {
1465+
if (!sourceFile) {
1466+
fail(Diagnostics.File_0_not_found, fileName);
14681467
}
1469-
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd))) {
1470-
diagnostic = Diagnostics.File_0_not_found;
1471-
fileName += ".ts";
1472-
diagnosticArgument = [fileName];
1468+
else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) {
1469+
fail(Diagnostics.A_file_cannot_have_a_reference_to_itself, fileName);
14731470
}
14741471
}
1475-
}
1472+
return sourceFile;
1473+
} else {
1474+
const sourceFileNoExtension = options.allowNonTsExtensions && getSourceFile(fileName);
1475+
if (sourceFileNoExtension) return sourceFileNoExtension;
14761476

1477-
if (diagnostic) {
1478-
if (refFile !== undefined && refEnd !== undefined && refPos !== undefined) {
1479-
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...diagnosticArgument));
1480-
}
1481-
else {
1482-
fileProcessingDiagnostics.add(createCompilerDiagnostic(diagnostic, ...diagnosticArgument));
1477+
if (fail && options.allowNonTsExtensions) {
1478+
fail(Diagnostics.File_0_not_found, fileName);
1479+
return undefined;
14831480
}
1481+
1482+
const sourceFileWithAddedExtension = forEach(supportedExtensions, extension => getSourceFile(fileName + extension));
1483+
if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.File_0_not_found, fileName + ".ts");
1484+
return sourceFileWithAddedExtension;
14841485
}
14851486
}
14861487

1488+
/** This has side effects through `findSourceFile`. */
1489+
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
1490+
getSourceFileFromReferenceWorker(fileName,
1491+
fileName => findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd),
1492+
(diagnostic, ...args) => {
1493+
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
1494+
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
1495+
: createCompilerDiagnostic(diagnostic, ...args));
1496+
},
1497+
refFile);
1498+
}
1499+
14871500
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFileName: string, refFile: SourceFile, refPos: number, refEnd: number): void {
14881501
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
14891502
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,

src/compiler/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -2425,6 +2425,8 @@ namespace ts {
24252425
/* @internal */ isSourceFileFromExternalLibrary(file: SourceFile): boolean;
24262426
// For testing purposes only.
24272427
/* @internal */ structureIsReused?: StructureIsReused;
2428+
2429+
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined;
24282430
}
24292431

24302432
/* @internal */

src/compiler/utilities.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -1918,21 +1918,19 @@ namespace ts {
19181918
const isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/gim;
19191919
if (simpleReferenceRegEx.test(comment)) {
19201920
if (isNoDefaultLibRegEx.test(comment)) {
1921-
return {
1922-
isNoDefaultLib: true
1923-
};
1921+
return { isNoDefaultLib: true };
19241922
}
19251923
else {
19261924
const refMatchResult = fullTripleSlashReferencePathRegEx.exec(comment);
19271925
const refLibResult = !refMatchResult && fullTripleSlashReferenceTypeReferenceDirectiveRegEx.exec(comment);
1928-
if (refMatchResult || refLibResult) {
1929-
const start = commentRange.pos;
1930-
const end = commentRange.end;
1926+
const match = refMatchResult || refLibResult;
1927+
if (match) {
1928+
const pos = commentRange.pos + match[1].length + match[2].length;
19311929
return {
19321930
fileReference: {
1933-
pos: start,
1934-
end: end,
1935-
fileName: (refMatchResult || refLibResult)[3]
1931+
pos,
1932+
end: pos + match[3].length,
1933+
fileName: match[3]
19361934
},
19371935
isNoDefaultLib: false,
19381936
isTypeReferenceDirective: !!refLibResult

src/harness/fourslash.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -995,16 +995,15 @@ namespace FourSlash {
995995

996996
public verifyReferenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void {
997997
interface ReferenceJson { definition: string; ranges: ts.ReferenceEntry[]; }
998-
type ReferencesJson = ReferenceJson[];
999-
const fullExpected = parts.map<ReferenceJson>(({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
998+
const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
1000999

10011000
for (const startRange of toArray(startRanges)) {
10021001
this.goToRangeStart(startRange);
10031002
const fullActual = ts.map<ts.ReferencedSymbol, ReferenceJson>(this.findReferencesAtCaret(), ({ definition, references }) => ({
10041003
definition: definition.displayParts.map(d => d.text).join(""),
10051004
ranges: references
10061005
}));
1007-
this.assertObjectsEqual<ReferencesJson>(fullActual, fullExpected);
1006+
this.assertObjectsEqual(fullActual, fullExpected);
10081007
}
10091008

10101009
function rangeToReferenceEntry(r: Range): ts.ReferenceEntry {
@@ -1062,6 +1061,14 @@ namespace FourSlash {
10621061
}
10631062
}
10641063
};
1064+
if (fullActual === undefined || fullExpected === undefined) {
1065+
if (fullActual === fullExpected) {
1066+
return;
1067+
}
1068+
console.log("Expected:", stringify(fullExpected));
1069+
console.log("Actual: ", stringify(fullActual));
1070+
this.raiseError(msgPrefix);
1071+
}
10651072
recur(fullActual, fullExpected, "");
10661073

10671074
}

src/harness/unittests/services/preProcessFile.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ describe("PreProcessFile:", function () {
3737
/*readImportFile*/ true,
3838
/*detectJavaScriptImports*/ false,
3939
{
40-
referencedFiles: [{ fileName: "refFile1.ts", pos: 0, end: 37 }, { fileName: "refFile2.ts", pos: 38, end: 73 },
41-
{ fileName: "refFile3.ts", pos: 74, end: 109 }, { fileName: "..\\refFile4d.ts", pos: 110, end: 150 }],
40+
referencedFiles: [{ fileName: "refFile1.ts", pos: 22, end: 33 }, { fileName: "refFile2.ts", pos: 59, end: 70 },
41+
{ fileName: "refFile3.ts", pos: 94, end: 105 }, { fileName: "..\\refFile4d.ts", pos: 131, end: 146 }],
4242
importedFiles: <ts.FileReference[]>[],
4343
typeReferenceDirectives: [],
4444
ambientExternalModules: undefined,
@@ -104,7 +104,7 @@ describe("PreProcessFile:", function () {
104104
/*readImportFile*/ true,
105105
/*detectJavaScriptImports*/ false,
106106
{
107-
referencedFiles: [{ fileName: "refFile1.ts", pos: 0, end: 35 }, { fileName: "refFile2.ts", pos: 36, end: 71 }],
107+
referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }, { fileName: "refFile2.ts", pos: 57, end: 68 }],
108108
typeReferenceDirectives: [],
109109
importedFiles: [{ fileName: "r1.ts", pos: 92, end: 97 }, { fileName: "r2.ts", pos: 121, end: 126 }],
110110
ambientExternalModules: undefined,
@@ -117,7 +117,7 @@ describe("PreProcessFile:", function () {
117117
/*readImportFile*/ true,
118118
/*detectJavaScriptImports*/ false,
119119
{
120-
referencedFiles: [{ fileName: "refFile1.ts", pos: 0, end: 35 }],
120+
referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }],
121121
typeReferenceDirectives: [],
122122
importedFiles: [{ fileName: "r1.ts", pos: 91, end: 96 }, { fileName: "r3.ts", pos: 148, end: 153 }],
123123
ambientExternalModules: undefined,
@@ -442,12 +442,12 @@ describe("PreProcessFile:", function () {
442442
/*detectJavaScriptImports*/ false,
443443
{
444444
referencedFiles: [
445-
{ "pos": 13, "end": 38, "fileName": "a" },
446-
{ "pos": 91, "end": 117, "fileName": "a2" }
445+
{ "pos": 34, "end": 35, "fileName": "a" },
446+
{ "pos": 112, "end": 114, "fileName": "a2" }
447447
],
448448
typeReferenceDirectives: [
449-
{ "pos": 51, "end": 78, "fileName": "a1" },
450-
{ "pos": 130, "end": 157, "fileName": "a3" }
449+
{ "pos": 73, "end": 75, "fileName": "a1" },
450+
{ "pos": 152, "end": 154, "fileName": "a3" }
451451
],
452452
importedFiles: [],
453453
ambientExternalModules: undefined,

src/services/documentHighlights.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/* @internal */
22
namespace ts.DocumentHighlights {
3-
export function getDocumentHighlights(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
3+
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
44
const node = getTouchingWord(sourceFile, position);
5-
return node && (getSemanticDocumentHighlights(node, typeChecker, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile));
5+
return node && (getSemanticDocumentHighlights(node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile));
66
}
77

88
function getHighlightSpanForNode(node: Node, sourceFile: SourceFile): HighlightSpan {
@@ -16,8 +16,8 @@ namespace ts.DocumentHighlights {
1616
};
1717
}
1818

19-
function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
20-
const referenceEntries = FindAllReferences.getReferenceEntriesForNode(node, sourceFilesToSearch, typeChecker, cancellationToken);
19+
function getSemanticDocumentHighlights(node: Node, program: Program, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
20+
const referenceEntries = FindAllReferences.getReferenceEntriesForNode(node, program, sourceFilesToSearch, cancellationToken);
2121
return referenceEntries && convertReferencedSymbols(referenceEntries);
2222
}
2323

0 commit comments

Comments
 (0)