Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 01af3aa

Browse filesBrowse files
authored
Support 'find references' on most declaration-related keywords (microsoft#36490)
* Allow 'find references' to work on most declaration keywords * Add support for rename * Add more keywords, move logic out of checker and into services * Add additional type and expression keywords
1 parent afddaf0 commit 01af3aa
Copy full SHA for 01af3aa
Expand file treeCollapse file tree

17 files changed

+1079
-56
lines changed

‎src/harness/fourslashImpl.ts

Copy file name to clipboardExpand all lines: src/harness/fourslashImpl.ts
+91-17Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,18 +1003,43 @@ namespace FourSlash {
10031003
definition: string | { text: string, range: ts.TextSpan };
10041004
references: ts.ReferenceEntry[];
10051005
}
1006+
interface RangeMarkerData {
1007+
id?: string;
1008+
isWriteAccess?: boolean,
1009+
isDefinition?: boolean,
1010+
isInString?: true,
1011+
contextRangeIndex?: number,
1012+
contextRangeDelta?: number,
1013+
contextRangeId?: string
1014+
}
10061015
const fullExpected = ts.map<FourSlashInterface.ReferenceGroup, ReferenceGroupJson>(parts, ({ definition, ranges }) => ({
10071016
definition: typeof definition === "string" ? definition : { ...definition, range: ts.createTextSpanFromRange(definition.range) },
10081017
references: ranges.map<ts.ReferenceEntry>(r => {
1009-
const { isWriteAccess = false, isDefinition = false, isInString, contextRangeIndex } = (r.marker && r.marker.data || {}) as { isWriteAccess?: boolean, isDefinition?: boolean, isInString?: true, contextRangeIndex?: number };
1018+
const { isWriteAccess = false, isDefinition = false, isInString, contextRangeIndex, contextRangeDelta, contextRangeId } = (r.marker && r.marker.data || {}) as RangeMarkerData;
1019+
let contextSpan: ts.TextSpan | undefined;
1020+
if (contextRangeDelta !== undefined) {
1021+
const allRanges = this.getRanges();
1022+
const index = allRanges.indexOf(r);
1023+
if (index !== -1) {
1024+
contextSpan = ts.createTextSpanFromRange(allRanges[index + contextRangeDelta]);
1025+
}
1026+
}
1027+
else if (contextRangeId !== undefined) {
1028+
const allRanges = this.getRanges();
1029+
const contextRange = ts.find(allRanges, range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId);
1030+
if (contextRange) {
1031+
contextSpan = ts.createTextSpanFromRange(contextRange);
1032+
}
1033+
}
1034+
else if (contextRangeIndex !== undefined) {
1035+
contextSpan = ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]);
1036+
}
10101037
return {
1011-
fileName: r.fileName,
10121038
textSpan: ts.createTextSpanFromRange(r),
1039+
fileName: r.fileName,
1040+
...(contextSpan ? { contextSpan } : undefined),
10131041
isWriteAccess,
10141042
isDefinition,
1015-
...(contextRangeIndex !== undefined ?
1016-
{ contextSpan: ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]) } :
1017-
undefined),
10181043
...(isInString ? { isInString: true } : undefined),
10191044
};
10201045
}),
@@ -1038,7 +1063,7 @@ namespace FourSlash {
10381063
}
10391064

10401065
public verifyNoReferences(markerNameOrRange?: string | Range) {
1041-
if (markerNameOrRange) this.goToMarkerOrRange(markerNameOrRange);
1066+
if (markerNameOrRange !== undefined) this.goToMarkerOrRange(markerNameOrRange);
10421067
const refs = this.getReferencesAtCaret();
10431068
if (refs && refs.length) {
10441069
this.raiseError(`Expected getReferences to fail, but saw references: ${stringify(refs)}`);
@@ -1239,6 +1264,12 @@ namespace FourSlash {
12391264
}
12401265

12411266
public verifyRenameLocations(startRanges: ArrayOrSingle<Range>, options: FourSlashInterface.RenameLocationsOptions) {
1267+
interface RangeMarkerData {
1268+
id?: string;
1269+
contextRangeIndex?: number,
1270+
contextRangeDelta?: number
1271+
contextRangeId?: string;
1272+
}
12421273
const { findInStrings = false, findInComments = false, ranges = this.getRanges(), providePrefixAndSuffixTextForRename = true } = ts.isArray(options) ? { findInStrings: false, findInComments: false, ranges: options, providePrefixAndSuffixTextForRename: true } : options;
12431274

12441275
const _startRanges = toArray(startRanges);
@@ -1259,13 +1290,29 @@ namespace FourSlash {
12591290
locations && ts.sort(locations, (r1, r2) => ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) || r1.textSpan.start - r2.textSpan.start);
12601291
assert.deepEqual(sort(references), sort(ranges.map((rangeOrOptions): ts.RenameLocation => {
12611292
const { range, ...prefixSuffixText } = "range" in rangeOrOptions ? rangeOrOptions : { range: rangeOrOptions }; // eslint-disable-line no-in-operator
1262-
const { contextRangeIndex } = (range.marker && range.marker.data || {}) as { contextRangeIndex?: number; };
1293+
const { contextRangeIndex, contextRangeDelta, contextRangeId } = (range.marker && range.marker.data || {}) as RangeMarkerData;
1294+
let contextSpan: ts.TextSpan | undefined;
1295+
if (contextRangeDelta !== undefined) {
1296+
const allRanges = this.getRanges();
1297+
const index = allRanges.indexOf(range);
1298+
if (index !== -1) {
1299+
contextSpan = ts.createTextSpanFromRange(allRanges[index + contextRangeDelta]);
1300+
}
1301+
}
1302+
else if (contextRangeId !== undefined) {
1303+
const allRanges = this.getRanges();
1304+
const contextRange = ts.find(allRanges, range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId);
1305+
if (contextRange) {
1306+
contextSpan = ts.createTextSpanFromRange(contextRange);
1307+
}
1308+
}
1309+
else if (contextRangeIndex !== undefined) {
1310+
contextSpan = ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]);
1311+
}
12631312
return {
12641313
fileName: range.fileName,
12651314
textSpan: ts.createTextSpanFromRange(range),
1266-
...(contextRangeIndex !== undefined ?
1267-
{ contextSpan: ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]) } :
1268-
undefined),
1315+
...(contextSpan ? { contextSpan } : undefined),
12691316
...prefixSuffixText
12701317
};
12711318
})));
@@ -3595,19 +3642,41 @@ namespace FourSlash {
35953642
// Parse out the files and their metadata
35963643
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
35973644
const state = new TestState(absoluteFileName, absoluteBasePath, testType, testData);
3598-
const output = ts.transpileModule(content, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ES2015 } });
3645+
const actualFileName = Harness.IO.resolvePath(fileName) || absoluteFileName;
3646+
const output = ts.transpileModule(content, { reportDiagnostics: true, fileName: actualFileName, compilerOptions: { target: ts.ScriptTarget.ES2015, inlineSourceMap: true } });
35993647
if (output.diagnostics!.length > 0) {
36003648
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`);
36013649
}
3602-
runCode(output.outputText, state);
3650+
runCode(output.outputText, state, actualFileName);
36033651
}
36043652

3605-
function runCode(code: string, state: TestState): void {
3653+
function runCode(code: string, state: TestState, fileName: string): void {
36063654
// Compile and execute the test
3607-
const wrappedCode =
3608-
`(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) {
3609-
${code}
3610-
})`;
3655+
const generatedFile = ts.changeExtension(fileName, ".js");
3656+
const wrappedCode = `(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) {${code}\n//# sourceURL=${generatedFile}\n})`;
3657+
3658+
type SourceMapSupportModule = typeof import("source-map-support") & {
3659+
// TODO(rbuckton): This is missing from the DT definitions and needs to be added.
3660+
resetRetrieveHandlers(): void
3661+
};
3662+
3663+
// Provide the content of the current test to 'source-map-support' so that it can give us the correct source positions
3664+
// for test failures.
3665+
let sourceMapSupportModule: SourceMapSupportModule | undefined;
3666+
try {
3667+
sourceMapSupportModule = require("source-map-support");
3668+
}
3669+
catch {
3670+
// do nothing
3671+
}
3672+
3673+
sourceMapSupportModule?.install({
3674+
retrieveFile: path => {
3675+
return path === generatedFile ? wrappedCode :
3676+
undefined!;
3677+
}
3678+
});
3679+
36113680
try {
36123681
const test = new FourSlashInterface.Test(state);
36133682
const goTo = new FourSlashInterface.GoTo(state);
@@ -3622,8 +3691,13 @@ ${code}
36223691
f(test, goTo, plugins, verify, edit, debug, format, cancellation, FourSlashInterface.Classification, FourSlashInterface.Completion, verifyOperationIsCancelled);
36233692
}
36243693
catch (err) {
3694+
// ensure 'source-map-support' is triggered while we still have the handler attached by accessing `error.stack`.
3695+
err.stack?.toString();
36253696
throw err;
36263697
}
3698+
finally {
3699+
sourceMapSupportModule?.resetRetrieveHandlers();
3700+
}
36273701
}
36283702

36293703
function chompLeadingSpace(content: string) {

‎src/services/callHierarchy.ts

Copy file name to clipboardExpand all lines: src/services/callHierarchy.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ namespace ts.CallHierarchy {
293293
return [];
294294
}
295295
const location = getCallHierarchyDeclarationReferenceNode(declaration);
296-
const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, /*options*/ undefined, convertEntryToCallSite), isDefined);
296+
const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, { use: FindAllReferences.FindReferencesUse.References }, convertEntryToCallSite), isDefined);
297297
return calls ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) : [];
298298
}
299299

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.