Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package fourslash_test

import (
"testing"

"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/testutil"
)

func TestGoToDefinitionShorthandObjectLiteralWithInterface(t *testing.T) {
t.Parallel()

defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `interface Something {
[|foo|]: string;
}

function makeSomething([|foo|]: string): Something {
return { [|f/*1*/oo|] };
}`
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
f.VerifyBaselineGoToDefinition(t, true, "1")
}
33 changes: 32 additions & 1 deletion internal/ls/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,15 @@ func (l *LanguageService) createLocationFromFileAndRange(file *ast.SourceFile, t

func getDeclarationsFromLocation(c *checker.Checker, node *ast.Node) []*ast.Node {
if ast.IsIdentifier(node) && ast.IsShorthandPropertyAssignment(node.Parent) {
return c.GetResolvedSymbol(node).Declarations
// For shorthand property assignments, return both the value symbol's declarations
// and the contextual type's property declarations
shorthandSymbol := c.GetResolvedSymbol(node)
var declarations []*ast.Node
if shorthandSymbol != nil {
declarations = shorthandSymbol.Declarations
}
contextualDeclarations := getDeclarationsFromObjectLiteralElement(c, node)
return core.Concatenate(declarations, contextualDeclarations)
}
node = getDeclarationNameForKeyword(node)
if symbol := c.GetSymbolAtLocation(node); symbol != nil {
Expand Down Expand Up @@ -196,6 +204,29 @@ func getDeclarationsFromLocation(c *checker.Checker, node *ast.Node) []*ast.Node
return nil
}

// getDeclarationsFromObjectLiteralElement returns declarations from the contextual type
// of an object literal element, if available.
func getDeclarationsFromObjectLiteralElement(c *checker.Checker, node *ast.Node) []*ast.Node {
element := getContainingObjectLiteralElement(node)
if element == nil {
return nil
}

// Get the contextual type of the object literal
objectLiteral := element.Parent
if objectLiteral == nil || !ast.IsObjectLiteralExpression(objectLiteral) {
return nil
}

// Get the name of the property
name := ast.GetTextOfPropertyName(element.Name())
if name == "" {
return nil
}

return c.GetContextualDeclarationsForObjectLiteralElement(objectLiteral, name)
}

// Returns a CallLikeExpression where `node` is the target being invoked.
func getAncestorCallLikeExpression(node *ast.Node) *ast.Node {
target := ast.FindAncestor(node, func(n *ast.Node) bool {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// === goToDefinition ===
// === /goToDefinitionShorthandObjectLiteralWithInterface.ts ===
// interface Something {
// [|foo|]: string;
// }
//
// function makeSomething([|foo|]: string): Something {
// return { f/*GOTO DEF*/oo };
// }
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// === goToDefinition ===
// === /goToDefinitionShorthandProperty04.ts ===
// interface Foo {
// foo(): void
// [|foo|](): void
// }
//
// let x: Foo = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// === goToDefinition ===
// === /goToDefinitionShorthandProperty05.ts ===
// interface Foo {
// foo(): void
// [|foo|](): void
// }
// const [|foo|] = 1;
// let x: Foo = {
Expand Down