Skip to content

Commit 43c01e2

Browse files
committed
Fix navigation on symbols that are not aliases but resolve through aliases in chain
1 parent 7e57890 commit 43c01e2

File tree

4 files changed

+43
-34
lines changed

4 files changed

+43
-34
lines changed

Diff for: src/server/session.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1184,7 +1184,6 @@ namespace ts.server {
11841184
containerName: info.containerName,
11851185
kind: info.kind,
11861186
name: info.name,
1187-
isAliasTarget: info.isAliasTarget,
11881187
failedAliasResolution: info.failedAliasResolution,
11891188
...info.unverified && { unverified: info.unverified },
11901189
};
@@ -1236,7 +1235,7 @@ namespace ts.server {
12361235
}
12371236

12381237
let definitions = this.mapDefinitionInfoLocations(unmappedDefinitionAndBoundSpan.definitions, project).slice();
1239-
const needsJsResolution = !some(definitions, d => !!d.isAliasTarget && !d.isAmbient) || some(definitions, d => !!d.failedAliasResolution);
1238+
const needsJsResolution = !some(definitions, d => toNormalizedPath(d.fileName) !== file && !d.isAmbient) || some(definitions, d => !!d.failedAliasResolution);
12401239
if (needsJsResolution) {
12411240
project.withAuxiliaryProjectForFiles([file], auxiliaryProject => {
12421241
const ls = auxiliaryProject.getLanguageService();

Diff for: src/services/goToDefinition.ts

+27-31
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,27 @@ namespace ts.GoToDefinition {
2828

2929
if (isStaticModifier(node) && isClassStaticBlockDeclaration(node.parent)) {
3030
const classDecl = node.parent.parent;
31-
const { symbol, isAliasTarget, failedAliasResolution } = getSymbol(classDecl, typeChecker);
32-
if (aliasesOnly && !isAliasTarget) return undefined;
31+
const { symbol, failedAliasResolution } = getSymbol(classDecl, typeChecker);
3332

3433
const staticBlocks = filter(classDecl.members, isClassStaticBlockDeclaration);
3534
const containerName = symbol ? typeChecker.symbolToString(symbol, classDecl) : "";
3635
const sourceFile = node.getSourceFile();
3736
return map(staticBlocks, staticBlock => {
3837
let { pos } = moveRangePastModifiers(staticBlock);
3938
pos = skipTrivia(sourceFile.text, pos);
40-
return createDefinitionInfoFromName(typeChecker, staticBlock, ScriptElementKind.constructorImplementationElement, "static {}", containerName, isAliasTarget, failedAliasResolution, { start: pos, length: "static".length });
39+
return createDefinitionInfoFromName(typeChecker, staticBlock, ScriptElementKind.constructorImplementationElement, "static {}", containerName, failedAliasResolution, { start: pos, length: "static".length });
4140
});
4241
}
4342

44-
let { symbol, isAliasTarget, failedAliasResolution } = getSymbol(node, typeChecker);
43+
let { symbol, failedAliasResolution } = getSymbol(node, typeChecker);
4544
let fallbackNode = node;
4645

4746
if (aliasesOnly && failedAliasResolution) {
4847
// We couldn't resolve the specific import, try on the module specifier.
4948
const importDeclaration = findAncestor(node, isAnyImportOrBareOrAccessedRequire);
5049
const moduleSpecifier = importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration);
5150
if (moduleSpecifier) {
52-
({ symbol, isAliasTarget, failedAliasResolution } = getSymbol(moduleSpecifier, typeChecker));
51+
({ symbol, failedAliasResolution } = getSymbol(moduleSpecifier, typeChecker));
5352
fallbackNode = moduleSpecifier;
5453
}
5554
}
@@ -66,33 +65,32 @@ namespace ts.GoToDefinition {
6665
containerKind: undefined!,
6766
kind: ScriptElementKind.scriptElement,
6867
textSpan: createTextSpan(0, 0),
69-
isAliasTarget: true,
7068
failedAliasResolution,
7169
isAmbient: isDeclarationFileName(ref.resolvedFileName),
7270
unverified: fallbackNode !== node,
7371
}];
7472
}
7573
}
7674

77-
if (aliasesOnly && !isAliasTarget) return undefined;
78-
7975
// Could not find a symbol e.g. node is string or number keyword,
8076
// or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol
8177
if (!symbol) {
8278
return concatenate(fileReferenceDefinition, getDefinitionInfoForIndexSignatures(node, typeChecker));
8379
}
8480

81+
if (aliasesOnly && every(symbol.declarations, d => d.getSourceFile().fileName === sourceFile.fileName)) return undefined;
82+
8583
const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node);
8684
// Don't go to the component constructor definition for a JSX element, just go to the component definition.
8785
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorLike(calledDeclaration))) {
88-
const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration, isAliasTarget, failedAliasResolution);
86+
const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration, failedAliasResolution);
8987
// For a function, if this is the original function definition, return just sigInfo.
9088
// If this is the original constructor definition, parent is the class.
9189
if (typeChecker.getRootSymbols(symbol).some(s => symbolMatchesSignature(s, calledDeclaration))) {
9290
return [sigInfo];
9391
}
9492
else {
95-
const defs = getDefinitionFromSymbol(typeChecker, symbol, node, isAliasTarget, failedAliasResolution, calledDeclaration) || emptyArray;
93+
const defs = getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution, calledDeclaration) || emptyArray;
9694
// For a 'super()' call, put the signature first, else put the variable first.
9795
return node.kind === SyntaxKind.SuperKeyword ? [sigInfo, ...defs] : [...defs, sigInfo];
9896
}
@@ -105,7 +103,7 @@ namespace ts.GoToDefinition {
105103
// assignment. This case and others are handled by the following code.
106104
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
107105
const shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
108-
const definitions = shorthandSymbol?.declarations ? shorthandSymbol.declarations.map(decl => createDefinitionInfo(decl, typeChecker, shorthandSymbol, node, isAliasTarget, failedAliasResolution)) : emptyArray;
106+
const definitions = shorthandSymbol?.declarations ? shorthandSymbol.declarations.map(decl => createDefinitionInfo(decl, typeChecker, shorthandSymbol, node, failedAliasResolution)) : emptyArray;
109107
return concatenate(definitions, getDefinitionFromObjectLiteralElement(typeChecker, node) || emptyArray);
110108
}
111109

@@ -130,7 +128,7 @@ namespace ts.GoToDefinition {
130128
});
131129
}
132130

133-
return concatenate(fileReferenceDefinition, getDefinitionFromObjectLiteralElement(typeChecker, node) || getDefinitionFromSymbol(typeChecker, symbol, node, isAliasTarget, failedAliasResolution));
131+
return concatenate(fileReferenceDefinition, getDefinitionFromObjectLiteralElement(typeChecker, node) || getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution));
134132
}
135133

136134
/**
@@ -234,25 +232,25 @@ namespace ts.GoToDefinition {
234232
}
235233

236234
if (isImportMeta(node.parent) && node.parent.name === node) {
237-
return definitionFromType(typeChecker.getTypeAtLocation(node.parent), typeChecker, node.parent, /*isAliasTarget*/ false, /*failedAliasResolution*/ false);
235+
return definitionFromType(typeChecker.getTypeAtLocation(node.parent), typeChecker, node.parent, /*failedAliasResolution*/ false);
238236
}
239237

240-
const { symbol, isAliasTarget, failedAliasResolution } = getSymbol(node, typeChecker);
238+
const { symbol, failedAliasResolution } = getSymbol(node, typeChecker);
241239
if (!symbol) return undefined;
242240

243241
const typeAtLocation = typeChecker.getTypeOfSymbolAtLocation(symbol, node);
244242
const returnType = tryGetReturnTypeOfFunction(symbol, typeAtLocation, typeChecker);
245-
const fromReturnType = returnType && definitionFromType(returnType, typeChecker, node, isAliasTarget, failedAliasResolution);
243+
const fromReturnType = returnType && definitionFromType(returnType, typeChecker, node, failedAliasResolution);
246244
// If a function returns 'void' or some other type with no definition, just return the function definition.
247-
const typeDefinitions = fromReturnType && fromReturnType.length !== 0 ? fromReturnType : definitionFromType(typeAtLocation, typeChecker, node, isAliasTarget, failedAliasResolution);
245+
const typeDefinitions = fromReturnType && fromReturnType.length !== 0 ? fromReturnType : definitionFromType(typeAtLocation, typeChecker, node, failedAliasResolution);
248246
return typeDefinitions.length ? typeDefinitions
249-
: !(symbol.flags & SymbolFlags.Value) && symbol.flags & SymbolFlags.Type ? getDefinitionFromSymbol(typeChecker, skipAlias(symbol, typeChecker), node, isAliasTarget, failedAliasResolution)
247+
: !(symbol.flags & SymbolFlags.Value) && symbol.flags & SymbolFlags.Type ? getDefinitionFromSymbol(typeChecker, skipAlias(symbol, typeChecker), node, failedAliasResolution)
250248
: undefined;
251249
}
252250

253-
function definitionFromType(type: Type, checker: TypeChecker, node: Node, isAliasTarget: boolean, failedAliasResolution: boolean | undefined): readonly DefinitionInfo[] {
251+
function definitionFromType(type: Type, checker: TypeChecker, node: Node, failedAliasResolution: boolean | undefined): readonly DefinitionInfo[] {
254252
return flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t =>
255-
t.symbol && getDefinitionFromSymbol(checker, t.symbol, node, isAliasTarget, failedAliasResolution));
253+
t.symbol && getDefinitionFromSymbol(checker, t.symbol, node, failedAliasResolution));
256254
}
257255

258256
function tryGetReturnTypeOfFunction(symbol: Symbol, type: Type, checker: TypeChecker): Type | undefined {
@@ -304,13 +302,13 @@ namespace ts.GoToDefinition {
304302
if (symbol?.declarations && symbol.flags & SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) {
305303
const aliased = checker.getAliasedSymbol(symbol);
306304
if (aliased.declarations) {
307-
return { symbol: aliased, isAliasTarget: true };
305+
return { symbol: aliased };
308306
}
309307
else {
310308
failedAliasResolution = true;
311309
}
312310
}
313-
return { symbol, isAliasTarget: !!(symbol && isExternalModuleSymbol(symbol)), failedAliasResolution };
311+
return { symbol, failedAliasResolution };
314312
}
315313

316314
// Go to the original declaration for cases:
@@ -358,11 +356,11 @@ namespace ts.GoToDefinition {
358356
return !!containingAssignment && getAssignmentDeclarationKind(containingAssignment) === AssignmentDeclarationKind.Property;
359357
}
360358

361-
function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node, isAliasTarget?: boolean, failedAliasResolution?: boolean, excludeDeclaration?: Node): DefinitionInfo[] | undefined {
359+
function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node, failedAliasResolution?: boolean, excludeDeclaration?: Node): DefinitionInfo[] | undefined {
362360
const filteredDeclarations = filter(symbol.declarations, d => d !== excludeDeclaration);
363361
const withoutExpandos = filter(filteredDeclarations, d => !isExpandoDeclaration(d));
364362
const results = some(withoutExpandos) ? withoutExpandos : filteredDeclarations;
365-
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(results, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node, isAliasTarget, failedAliasResolution));
363+
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(results, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node, failedAliasResolution));
366364

367365
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
368366
// Applicable only if we are in a new expression, or we are on a constructor declaration
@@ -390,21 +388,21 @@ namespace ts.GoToDefinition {
390388
return declarations.length
391389
? declarationsWithBody.length !== 0
392390
? declarationsWithBody.map(x => createDefinitionInfo(x, typeChecker, symbol, node))
393-
: [createDefinitionInfo(last(declarations), typeChecker, symbol, node, isAliasTarget, failedAliasResolution)]
391+
: [createDefinitionInfo(last(declarations), typeChecker, symbol, node, failedAliasResolution)]
394392
: undefined;
395393
}
396394
}
397395

398396
/** Creates a DefinitionInfo from a Declaration, using the declaration's name if possible. */
399-
export function createDefinitionInfo(declaration: Declaration, checker: TypeChecker, symbol: Symbol, node: Node, isAliasTarget?: boolean, failedAliasResolution?: boolean): DefinitionInfo {
397+
export function createDefinitionInfo(declaration: Declaration, checker: TypeChecker, symbol: Symbol, node: Node, failedAliasResolution?: boolean): DefinitionInfo {
400398
const symbolName = checker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
401399
const symbolKind = SymbolDisplay.getSymbolKind(checker, symbol, node);
402400
const containerName = symbol.parent ? checker.symbolToString(symbol.parent, node) : "";
403-
return createDefinitionInfoFromName(checker, declaration, symbolKind, symbolName, containerName, isAliasTarget, failedAliasResolution);
401+
return createDefinitionInfoFromName(checker, declaration, symbolKind, symbolName, containerName, failedAliasResolution);
404402
}
405403

406404
/** Creates a DefinitionInfo directly from the name of a declaration. */
407-
function createDefinitionInfoFromName(checker: TypeChecker, declaration: Declaration, symbolKind: ScriptElementKind, symbolName: string, containerName: string, isAliasTarget?: boolean, failedAliasResolution?: boolean, textSpan?: TextSpan): DefinitionInfo {
405+
function createDefinitionInfoFromName(checker: TypeChecker, declaration: Declaration, symbolKind: ScriptElementKind, symbolName: string, containerName: string, failedAliasResolution?: boolean, textSpan?: TextSpan): DefinitionInfo {
408406
const sourceFile = declaration.getSourceFile();
409407
if (!textSpan) {
410408
const name = getNameOfDeclaration(declaration) || declaration;
@@ -424,7 +422,6 @@ namespace ts.GoToDefinition {
424422
),
425423
isLocal: !isDefinitionVisible(checker, declaration),
426424
isAmbient: !!(declaration.flags & NodeFlags.Ambient),
427-
isAliasTarget,
428425
failedAliasResolution,
429426
};
430427
}
@@ -460,8 +457,8 @@ namespace ts.GoToDefinition {
460457
}
461458
}
462459

463-
function createDefinitionFromSignatureDeclaration(typeChecker: TypeChecker, decl: SignatureDeclaration, isAliasTarget?: boolean, failedAliasResolution?: boolean): DefinitionInfo {
464-
return createDefinitionInfo(decl, typeChecker, decl.symbol, decl, isAliasTarget, failedAliasResolution);
460+
function createDefinitionFromSignatureDeclaration(typeChecker: TypeChecker, decl: SignatureDeclaration, failedAliasResolution?: boolean): DefinitionInfo {
461+
return createDefinitionInfo(decl, typeChecker, decl.symbol, decl, failedAliasResolution);
465462
}
466463

467464
export function findReferenceInPosition(refs: readonly FileReference[], pos: number): FileReference | undefined {
@@ -477,7 +474,6 @@ namespace ts.GoToDefinition {
477474
containerName: undefined!,
478475
containerKind: undefined!, // TODO: GH#18217
479476
unverified,
480-
isAliasTarget: true,
481477
};
482478
}
483479

Diff for: src/services/types.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,6 @@ namespace ts {
10371037
unverified?: boolean;
10381038
/* @internal */ isLocal?: boolean;
10391039
/* @internal */ isAmbient?: boolean;
1040-
/* @internal */ isAliasTarget?: boolean;
10411040
/* @internal */ failedAliasResolution?: boolean;
10421041
}
10431042

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path="../fourslash.ts" />
2+
3+
// @moduleResolution: node
4+
5+
// @Filename: /a.js
6+
//// export const a = { /*end*/a: 'a' };
7+
8+
// @Filename: /a.d.ts
9+
//// export declare const a: { a: string };
10+
11+
// @Filename: /b.ts
12+
//// import { a } from './a';
13+
//// a.[|a/*start*/|]
14+
15+
verify.goToSourceDefinition("start", "end");

0 commit comments

Comments
 (0)