From f1a0a7f863a0b247471626a0188c42c59ddbe18e Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 17 Jun 2019 13:30:07 -0700 Subject: [PATCH] Don't let the additional property setting on an object show up as a definition for the lanmguage server --- src/services/goToDefinition.ts | 12 ++++++++---- .../goToDefinitionPropertyAssignment.ts | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/cases/fourslash/goToDefinitionPropertyAssignment.ts diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index 8f495aadfe1..19959871500 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -26,7 +26,7 @@ namespace ts.GoToDefinition { if (!symbol) { return getDefinitionInfoForIndexSignatures(node, typeChecker); } - + const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node); // Don't go to the component constructor definition for a JSX element, just go to the component definition. if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorLike(calledDeclaration))) { @@ -233,20 +233,24 @@ namespace ts.GoToDefinition { } function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo[] | undefined { - return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(symbol.declarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node)); + // There are cases when you extend a function by adding properties to it afterwards, + // we want to strip those extra properties + const filteredDeclarations = symbol.declarations.filter(d => !ts.isAssignmentDeclaration(d) || d === symbol.valueDeclaration) + + return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(filteredDeclarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node)); function getConstructSignatureDefinition(): DefinitionInfo[] | undefined { // Applicable only if we are in a new expression, or we are on a constructor declaration // and in either case the symbol has a construct signature definition, i.e. class if (symbol.flags & SymbolFlags.Class && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword)) { - const cls = find(symbol.declarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration"); + const cls = find(filteredDeclarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration"); return getSignatureDefinition(cls.members, /*selectConstructors*/ true); } } function getCallSignatureDefinition(): DefinitionInfo[] | undefined { return isCallOrNewExpressionTarget(node) || isNameOfFunctionDeclaration(node) - ? getSignatureDefinition(symbol.declarations, /*selectConstructors*/ false) + ? getSignatureDefinition(filteredDeclarations, /*selectConstructors*/ false) : undefined; } diff --git a/tests/cases/fourslash/goToDefinitionPropertyAssignment.ts b/tests/cases/fourslash/goToDefinitionPropertyAssignment.ts new file mode 100644 index 00000000000..5da8604f548 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionPropertyAssignment.ts @@ -0,0 +1,16 @@ +/// + +//// export const /*FunctionResult*/Component = () => { return "OK"} +//// Component./*PropertyResult*/displayName = 'Component' +//// +//// [|/*FunctionClick*/Component|] +//// +//// Component.[|/*PropertyClick*/displayName|] + +verify.goToDefinition("FunctionClick", "FunctionResult") + +verify.goToDefinition("PropertyClick", "PropertyResult") + +// export const Component = () => { return "OK"} +// Component.displayName = 'Component' +