internal/lsp/source: do not panic in "var func" outgoing callhierarchy

When trying to get outgoing call hierarchy from an var func like:

func main() {
    foo := func() {}
    foo()
}

gopls crashed with a panic.

This change makes it return an empty call hierarchy instead.
It also adds support for testing outgoing calls where the expected
result is 0 items, to be able to test this change.

Fixes golang/go#43376

Change-Id: Icd91bf54cb4fbd5203f5865f0ff9d81365c27d5d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/279469
Trust: Pontus Leitzler <leitzler@gmail.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Pontus Leitzler <leitzler@gmail.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Pontus Leitzler 2020-12-25 11:51:51 +01:00 committed by Rebecca Stambler
parent 2b0845dc78
commit b1c90890d2
4 changed files with 15 additions and 16 deletions

View File

@ -193,7 +193,9 @@ func OutgoingCalls(ctx context.Context, snapshot Snapshot, fh FileHandle, pos pr
if _, ok := identifier.Declaration.obj.Type().Underlying().(*types.Signature); !ok {
return nil, nil
}
if identifier.Declaration.node == nil {
return nil, nil
}
if len(identifier.Declaration.MappedRange) == 0 {
return nil, nil
}

View File

@ -26,12 +26,14 @@ var x = func() { //@mark(hierarchyLiteral, "func"),mark(hierarchyLiteralOut, "x"
}
// D is exported to test incoming/outgoing calls across packages
func D() { //@mark(hierarchyD, "D"),incomingcalls(hierarchyD, hierarchyA, hierarchyB, hierarchyC, hierarchyLiteral, incomingA),outgoingcalls(hierarchyD, hierarchyE, hierarchyF, hierarchyG, hierarchyLiteralOut, outgoingB)
func D() { //@mark(hierarchyD, "D"),incomingcalls(hierarchyD, hierarchyA, hierarchyB, hierarchyC, hierarchyLiteral, incomingA),outgoingcalls(hierarchyD, hierarchyE, hierarchyF, hierarchyG, hierarchyLiteralOut, outgoingB, hierarchyFoo)
e()
x()
F()
g()
outgoing.B()
foo := func() {} //@mark(hierarchyFoo, "foo"),incomingcalls(hierarchyFoo, hierarchyD),outgoingcalls(hierarchyFoo)
foo()
}
func e() {} //@mark(hierarchyE, "e")

View File

@ -1,5 +1,5 @@
-- summary --
CallHierarchyCount = 1
CallHierarchyCount = 2
CodeLensCount = 5
CompletionsCount = 258
CompletionSnippetCount = 88

View File

@ -1131,6 +1131,9 @@ func (data *Data) collectIncomingCalls(src span.Span, calls []span.Span) {
}
func (data *Data) collectOutgoingCalls(src span.Span, calls []span.Span) {
if data.CallHierarchy[src] == nil {
data.CallHierarchy[src] = &CallHierarchyResult{}
}
for _, call := range calls {
m, err := data.Mapper(call.URI())
if err != nil {
@ -1141,19 +1144,11 @@ func (data *Data) collectOutgoingCalls(src span.Span, calls []span.Span) {
data.t.Fatal(err)
}
// we're only comparing protocol.range
if data.CallHierarchy[src] != nil {
data.CallHierarchy[src].OutgoingCalls = append(data.CallHierarchy[src].OutgoingCalls,
protocol.CallHierarchyItem{
URI: protocol.DocumentURI(call.URI()),
Range: rng,
})
} else {
data.CallHierarchy[src] = &CallHierarchyResult{
OutgoingCalls: []protocol.CallHierarchyItem{
{URI: protocol.DocumentURI(call.URI()), Range: rng},
},
}
}
data.CallHierarchy[src].OutgoingCalls = append(data.CallHierarchy[src].OutgoingCalls,
protocol.CallHierarchyItem{
URI: protocol.DocumentURI(call.URI()),
Range: rng,
})
}
}