Skip to content

Commit 71fb02c

Browse files
author
Andy Hanson
committed
Support find-all-references for a module specifier
1 parent 8321b81 commit 71fb02c

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

+310
-154
lines changed

src/compiler/program.ts

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,8 @@ namespace ts {
434434
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
435435
getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
436436
isSourceFileFromExternalLibrary,
437-
dropDiagnosticsProducingTypeChecker
437+
dropDiagnosticsProducingTypeChecker,
438+
getSourceFileFromReference,
438439
};
439440

440441
verifyCompilerOptions();
@@ -1348,48 +1349,60 @@ namespace ts {
13481349
}
13491350
}
13501351

1351-
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number) {
1352-
let diagnosticArgument: string[];
1353-
let diagnostic: DiagnosticMessage;
1352+
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
1353+
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
1354+
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName, currentDirectory, getCanonicalFileName)));
1355+
}
1356+
1357+
function getSourceFileFromReferenceWorker(
1358+
fileName: string,
1359+
getSourceFile: (fileName: string) => SourceFile | undefined,
1360+
fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
1361+
refFile?: SourceFile): SourceFile | undefined {
1362+
13541363
if (hasExtension(fileName)) {
13551364
if (!options.allowNonTsExtensions && !forEach(supportedExtensions, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
1356-
diagnostic = Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1;
1357-
diagnosticArgument = [fileName, "'" + supportedExtensions.join("', '") + "'"];
1358-
}
1359-
else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd)) {
1360-
diagnostic = Diagnostics.File_0_not_found;
1361-
diagnosticArgument = [fileName];
1365+
if (fail) fail(Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + supportedExtensions.join("', '") + "'");
1366+
return undefined;
13621367
}
1363-
else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) {
1364-
diagnostic = Diagnostics.A_file_cannot_have_a_reference_to_itself;
1365-
diagnosticArgument = [fileName];
1366-
}
1367-
}
1368-
else {
1369-
const nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd);
1370-
if (!nonTsFile) {
1371-
if (options.allowNonTsExtensions) {
1372-
diagnostic = Diagnostics.File_0_not_found;
1373-
diagnosticArgument = [fileName];
1368+
1369+
const sourceFile = getSourceFile(fileName);
1370+
if (fail) {
1371+
if (!sourceFile) {
1372+
fail(Diagnostics.File_0_not_found, fileName);
13741373
}
1375-
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd))) {
1376-
diagnostic = Diagnostics.File_0_not_found;
1377-
fileName += ".ts";
1378-
diagnosticArgument = [fileName];
1374+
else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) {
1375+
fail(Diagnostics.A_file_cannot_have_a_reference_to_itself, fileName);
13791376
}
13801377
}
1381-
}
1378+
return sourceFile;
1379+
} else {
1380+
const sourceFileNoExtension = options.allowNonTsExtensions && getSourceFile(fileName);
1381+
if (sourceFileNoExtension) return sourceFileNoExtension;
13821382

1383-
if (diagnostic) {
1384-
if (refFile !== undefined && refEnd !== undefined && refPos !== undefined) {
1385-
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...diagnosticArgument));
1386-
}
1387-
else {
1388-
fileProcessingDiagnostics.add(createCompilerDiagnostic(diagnostic, ...diagnosticArgument));
1383+
if (fail && options.allowNonTsExtensions) {
1384+
fail(Diagnostics.File_0_not_found, fileName);
1385+
return undefined;
13891386
}
1387+
1388+
const sourceFileWithAddedExtension = forEach(supportedExtensions, extension => getSourceFile(fileName + extension));
1389+
if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.File_0_not_found, fileName + ".ts");
1390+
return sourceFileWithAddedExtension;
13901391
}
13911392
}
13921393

1394+
/** This has side effects through `findSourceFile`. */
1395+
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
1396+
getSourceFileFromReferenceWorker(fileName,
1397+
fileName => findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd),
1398+
(diagnostic, ...args) => {
1399+
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
1400+
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
1401+
: createCompilerDiagnostic(diagnostic, ...args));
1402+
},
1403+
refFile);
1404+
}
1405+
13931406
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFileName: string, refFile: SourceFile, refPos: number, refEnd: number): void {
13941407
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
13951408
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,8 @@ namespace ts {
24112411
/* @internal */ isSourceFileFromExternalLibrary(file: SourceFile): boolean;
24122412
// For testing purposes only.
24132413
/* @internal */ structureIsReused?: StructureIsReused;
2414+
2415+
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined;
24142416
}
24152417

24162418
/* @internal */

src/compiler/utilities.ts

Lines changed: 7 additions & 9 deletions
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

Lines changed: 10 additions & 3 deletions
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

Lines changed: 8 additions & 8 deletions
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

Lines changed: 4 additions & 4 deletions
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)