Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash in goto-def on @override #51016

Merged
merged 8 commits into from Oct 3, 2022
10 changes: 6 additions & 4 deletions src/services/goToDefinition.ts
Expand Up @@ -171,13 +171,15 @@ namespace ts.GoToDefinition {
if (!baseDeclaration) return;

const baseTypeNode = getEffectiveBaseTypeNode(baseDeclaration);
const baseType = baseTypeNode ? typeChecker.getTypeAtLocation(baseTypeNode) : undefined;
if (!baseType) return;
if (!baseTypeNode) return;
const expression = skipParentheses(baseTypeNode.expression);
const base = isClassExpression(expression) ? expression.symbol : typeChecker.getSymbolAtLocation(expression);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, why are you checking for isClassExpression? Can't you use getDeclaredTypeOfSymbol?

Copy link
Member Author

@sandersn sandersn Oct 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to follow Node -> Symbol -> Type, and getSymbolAtLocation doesn't support (parenthesised) class expressions right now, which breaks the Node -> Symbol. Previously, the code used getTypeAtLocation, which does support class expressions. I happen to know that class expressions have a symbol, so I can special-case the Node -> Symbol step for now.

I'm going to follow this PR with one that moves the paren/class-expr check into getTypeAtLocation, but it changes lots of our baselines since, apparently, we use it for type baselines.

if (!base) return;

const name = unescapeLeadingUnderscores(getTextOfPropertyName(classElement.name));
const symbol = hasStaticModifier(classElement)
? typeChecker.getPropertyOfType(typeChecker.getTypeOfSymbolAtLocation(baseType.symbol, baseDeclaration), name)
: typeChecker.getPropertyOfType(baseType, name);
? typeChecker.getPropertyOfType(typeChecker.getTypeOfSymbol(base), name)
: typeChecker.getPropertyOfType(typeChecker.getDeclaredTypeOfSymbol(base), name);
if (!symbol) return;

return getDefinitionFromSymbol(typeChecker, symbol, node);
Expand Down
16 changes: 16 additions & 0 deletions tests/cases/fourslash/goToDefinitionOverriddenMember16.ts
@@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />
// @Filename: goToDefinitionOverrideJsdoc.ts
// @allowJs: true
// @checkJs: true

//// export class C extends CompletelyUndefined {
//// /**
//// * @override/*1*/
//// * @returns {{}}
//// */
//// static foo() {
//// return {}
//// }
//// }

verify.goToDefinition(['1'], [])