Skip to content

Commit 6fdba9f

Browse files
committed
Add more keywords, move logic out of checker and into services
1 parent 8d962aa commit 6fdba9f

13 files changed

+810
-191
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -413,13 +413,9 @@ namespace ts {
413413
location = getParseTreeNode(location);
414414
return location ? getSymbolsInScope(location, meaning) : [];
415415
},
416-
getSymbolAtLocation: (node: Node, includeKeywords?: boolean) => {
416+
getSymbolAtLocation: (node: Node) => {
417417
node = getParseTreeNode(node);
418-
if (node) {
419-
return includeKeywords ?
420-
getSymbolAtLocation(node) ?? getSymbolAtKeyword(node) :
421-
getSymbolAtLocation(node);
422-
}
418+
return node && getSymbolAtLocation(node);
423419
},
424420
getShorthandAssignmentValueSymbol: node => {
425421
node = getParseTreeNode(node);
@@ -34298,65 +34294,6 @@ namespace ts {
3429834294
}
3429934295
}
3430034296

34301-
/**
34302-
* Gets the symbol related to the provided location, if it that location is a keyword.
34303-
* These additional keywords are normally only used to resolve references but would
34304-
* not be used for document highlights, quickinfo, etc.
34305-
*/
34306-
function getSymbolAtKeyword(node: Node): Symbol | undefined {
34307-
if (node.flags & NodeFlags.InWithStatement) {
34308-
// We cannot answer semantic questions within a with block, do not proceed any further
34309-
return undefined;
34310-
}
34311-
34312-
const { parent } = node;
34313-
34314-
// If the node is a modifier of its parent, get the symbol for the parent.
34315-
if (isModifier(node) && contains(parent.modifiers, node)) {
34316-
return getSymbolOfNode(parent);
34317-
}
34318-
34319-
switch (node.kind) {
34320-
case SyntaxKind.InterfaceKeyword:
34321-
case SyntaxKind.EnumKeyword:
34322-
case SyntaxKind.NamespaceKeyword:
34323-
case SyntaxKind.ModuleKeyword:
34324-
case SyntaxKind.GetKeyword:
34325-
case SyntaxKind.SetKeyword:
34326-
return getSymbolOfNode(parent);
34327-
34328-
case SyntaxKind.TypeKeyword:
34329-
if (isTypeAliasDeclaration(parent)) {
34330-
return getSymbolOfNode(parent);
34331-
}
34332-
if (isImportClause(parent)) {
34333-
return getSymbolAtLocation(parent.parent.moduleSpecifier);
34334-
}
34335-
if (isLiteralImportTypeNode(parent)) {
34336-
return getSymbolAtLocation(parent.argument.literal);
34337-
}
34338-
break;
34339-
34340-
case SyntaxKind.VarKeyword:
34341-
case SyntaxKind.ConstKeyword:
34342-
case SyntaxKind.LetKeyword:
34343-
if (isVariableDeclarationList(parent) && parent.declarations.length === 1) {
34344-
return getSymbolOfNode(parent.declarations[0]);
34345-
}
34346-
break;
34347-
}
34348-
if (node.kind === SyntaxKind.NewKeyword && isNewExpression(parent) ||
34349-
node.kind === SyntaxKind.VoidKeyword && isVoidExpression(parent) ||
34350-
node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) ||
34351-
node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) ||
34352-
node.kind === SyntaxKind.YieldKeyword && isYieldExpression(parent) ||
34353-
node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent)) {
34354-
if (parent.expression) {
34355-
return getSymbolAtLocation(skipOuterExpressions(parent.expression));
34356-
}
34357-
}
34358-
}
34359-
3436034297
function getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined {
3436134298
if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) {
3436234299
return resolveEntityName((<ShorthandPropertyAssignment>location).name, SymbolFlags.Value | SymbolFlags.Alias);

src/compiler/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3405,7 +3405,6 @@ namespace ts {
34053405

34063406
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
34073407
getSymbolAtLocation(node: Node): Symbol | undefined;
3408-
/* @internal*/ getSymbolAtLocation(node: Node, includeKeywords?: boolean): Symbol | undefined; // eslint-disable-line @typescript-eslint/unified-signatures
34093408
getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[];
34103409
/**
34113410
* The function returns the value (local variable) symbol of an identifier in the short-hand property assignment.

src/harness/fourslashImpl.ts

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ namespace FourSlash {
229229
}
230230
}
231231

232-
constructor(private originalInputFileName: string, private basePath: string, private testType: FourSlashTestType, public testData: FourSlashData) {
232+
constructor(public originalInputFileName: string, private basePath: string, private testType: FourSlashTestType, public testData: FourSlashData) {
233233
// Create a new Services Adapter
234234
this.cancellationToken = new TestCancellationToken();
235235
let compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions);
@@ -998,16 +998,18 @@ namespace FourSlash {
998998
references: ts.ReferenceEntry[];
999999
}
10001000
interface RangeMarkerData {
1001+
id?: string;
10011002
isWriteAccess?: boolean,
10021003
isDefinition?: boolean,
10031004
isInString?: true,
10041005
contextRangeIndex?: number,
1005-
contextRangeDelta?: number
1006+
contextRangeDelta?: number,
1007+
contextRangeId?: string
10061008
}
10071009
const fullExpected = ts.map<FourSlashInterface.ReferenceGroup, ReferenceGroupJson>(parts, ({ definition, ranges }) => ({
10081010
definition: typeof definition === "string" ? definition : { ...definition, range: ts.createTextSpanFromRange(definition.range) },
10091011
references: ranges.map<ts.ReferenceEntry>(r => {
1010-
const { isWriteAccess = false, isDefinition = false, isInString, contextRangeIndex, contextRangeDelta } = (r.marker && r.marker.data || {}) as RangeMarkerData;
1012+
const { isWriteAccess = false, isDefinition = false, isInString, contextRangeIndex, contextRangeDelta, contextRangeId } = (r.marker && r.marker.data || {}) as RangeMarkerData;
10111013
let contextSpan: ts.TextSpan | undefined;
10121014
if (contextRangeDelta !== undefined) {
10131015
const allRanges = this.getRanges();
@@ -1016,15 +1018,22 @@ namespace FourSlash {
10161018
contextSpan = ts.createTextSpanFromRange(allRanges[index + contextRangeDelta]);
10171019
}
10181020
}
1021+
else if (contextRangeId !== undefined) {
1022+
const allRanges = this.getRanges();
1023+
const contextRange = ts.find(allRanges, range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId);
1024+
if (contextRange) {
1025+
contextSpan = ts.createTextSpanFromRange(contextRange);
1026+
}
1027+
}
10191028
else if (contextRangeIndex !== undefined) {
10201029
contextSpan = ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]);
10211030
}
10221031
return {
1023-
fileName: r.fileName,
10241032
textSpan: ts.createTextSpanFromRange(r),
1033+
fileName: r.fileName,
1034+
...(contextSpan ? { contextSpan } : undefined),
10251035
isWriteAccess,
10261036
isDefinition,
1027-
...(contextSpan ? { contextSpan } : undefined),
10281037
...(isInString ? { isInString: true } : undefined),
10291038
};
10301039
}),
@@ -1250,8 +1259,10 @@ namespace FourSlash {
12501259

12511260
public verifyRenameLocations(startRanges: ArrayOrSingle<Range>, options: FourSlashInterface.RenameLocationsOptions) {
12521261
interface RangeMarkerData {
1262+
id?: string;
12531263
contextRangeIndex?: number,
12541264
contextRangeDelta?: number
1265+
contextRangeId?: string;
12551266
}
12561267
const { findInStrings = false, findInComments = false, ranges = this.getRanges(), providePrefixAndSuffixTextForRename = true } = ts.isArray(options) ? { findInStrings: false, findInComments: false, ranges: options, providePrefixAndSuffixTextForRename: true } : options;
12571268

@@ -1273,7 +1284,7 @@ namespace FourSlash {
12731284
locations && ts.sort(locations, (r1, r2) => ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) || r1.textSpan.start - r2.textSpan.start);
12741285
assert.deepEqual(sort(references), sort(ranges.map((rangeOrOptions): ts.RenameLocation => {
12751286
const { range, ...prefixSuffixText } = "range" in rangeOrOptions ? rangeOrOptions : { range: rangeOrOptions }; // eslint-disable-line no-in-operator
1276-
const { contextRangeIndex, contextRangeDelta } = (range.marker && range.marker.data || {}) as RangeMarkerData;
1287+
const { contextRangeIndex, contextRangeDelta, contextRangeId } = (range.marker && range.marker.data || {}) as RangeMarkerData;
12771288
let contextSpan: ts.TextSpan | undefined;
12781289
if (contextRangeDelta !== undefined) {
12791290
const allRanges = this.getRanges();
@@ -1282,6 +1293,13 @@ namespace FourSlash {
12821293
contextSpan = ts.createTextSpanFromRange(allRanges[index + contextRangeDelta]);
12831294
}
12841295
}
1296+
else if (contextRangeId !== undefined) {
1297+
const allRanges = this.getRanges();
1298+
const contextRange = ts.find(allRanges, range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId);
1299+
if (contextRange) {
1300+
contextSpan = ts.createTextSpanFromRange(contextRange);
1301+
}
1302+
}
12851303
else if (contextRangeIndex !== undefined) {
12861304
contextSpan = ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]);
12871305
}
@@ -3618,19 +3636,43 @@ namespace FourSlash {
36183636
// Parse out the files and their metadata
36193637
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
36203638
const state = new TestState(absoluteFileName, absoluteBasePath, testType, testData);
3621-
const output = ts.transpileModule(content, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ES2015 } });
3639+
const actualFileName = Harness.IO.resolvePath(fileName) || absoluteFileName;
3640+
const output = ts.transpileModule(content, { reportDiagnostics: true, fileName: actualFileName, compilerOptions: { target: ts.ScriptTarget.ES2015, sourceMap: true } });
36223641
if (output.diagnostics!.length > 0) {
36233642
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`);
36243643
}
3625-
runCode(output.outputText, state);
3644+
runCode(output, state, actualFileName);
36263645
}
36273646

3628-
function runCode(code: string, state: TestState): void {
3647+
function runCode(output: ts.TranspileOutput, state: TestState, fileName: string): void {
36293648
// Compile and execute the test
3630-
const wrappedCode =
3631-
`(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) {
3632-
${code}
3633-
})`;
3649+
const generatedFile = ts.changeExtension(fileName, ".js");
3650+
const mapFile = generatedFile + ".map";
3651+
const wrappedCode = `(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) {${output.outputText}\n//# sourceURL=${generatedFile}\n})`;
3652+
3653+
type SourceMapSupportModule = typeof import("source-map-support") & {
3654+
// TODO(rbuckton): This is missing from the DT definitions and needs to be added.
3655+
resetRetrieveHandlers(): void
3656+
};
3657+
3658+
// Provide the content of the current test to 'source-map-support' so that it can give us the correct source positions
3659+
// for test failures.
3660+
let sourceMapSupportModule: SourceMapSupportModule | undefined;
3661+
try {
3662+
sourceMapSupportModule = require("source-map-support");
3663+
}
3664+
catch {
3665+
// do nothing
3666+
}
3667+
3668+
sourceMapSupportModule?.install({
3669+
retrieveFile: path => {
3670+
return path === generatedFile ? wrappedCode :
3671+
path === mapFile ? output.sourceMapText! :
3672+
undefined!;
3673+
}
3674+
});
3675+
36343676
try {
36353677
const test = new FourSlashInterface.Test(state);
36363678
const goTo = new FourSlashInterface.GoTo(state);
@@ -3645,8 +3687,13 @@ ${code}
36453687
f(test, goTo, plugins, verify, edit, debug, format, cancellation, FourSlashInterface.Classification, FourSlashInterface.Completion, verifyOperationIsCancelled);
36463688
}
36473689
catch (err) {
3690+
// ensure we trigger 'source-map-support' while we still have the handler attached
3691+
err.stack?.toString();
36483692
throw err;
36493693
}
3694+
finally {
3695+
sourceMapSupportModule?.resetRetrieveHandlers();
3696+
}
36503697
}
36513698

36523699
function chompLeadingSpace(content: string) {
@@ -3815,7 +3862,7 @@ ${code}
38153862
markerValue = JSON.parse("{ " + text + " }");
38163863
}
38173864
catch (e) {
3818-
reportError(fileName, location.sourceLine, location.sourceColumn, "Unable to parse marker text " + e.message);
3865+
reportError(fileName, location.sourceLine, location.sourceColumn, "Unable to parse marker text " + e.message + "\nSource:\n {| " + text + " |}");
38193866
}
38203867

38213868
if (markerValue === undefined) {

src/services/callHierarchy.ts

Lines 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, { keywords: true }, 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)