mirror of
https://github.com/golang/go
synced 2024-11-18 08:44:43 -07:00
internal: add call hierarchy cmd and lsp scaffolding
* adds gopls command line tool for call hierarchy * adds lsp setup for call hierarchy * adds handler for textDocument/prepareCallHierarchy to display selected identifier and get incoming/outgoing calls for it * setup testing Change-Id: I0a0904abdbe11273a56162b6e5be93b97ceb9c26 Reviewed-on: https://go-review.googlesource.com/c/tools/+/246521 Run-TryBot: Danish Dua <danishdua@google.com> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
f15f0bfc61
commit
a5d4502270
@ -87,6 +87,10 @@ func Requests(m string) interface{} {
|
||||
return new(p.TextDocumentPositionParams)
|
||||
case "textDocument/foldingRange":
|
||||
return new(p.FoldingRangeParams)
|
||||
case "textDocument/incomingCalls":
|
||||
return new(p.CallHierarchyIncomingCallsParams)
|
||||
case "textDocument/outgoingCalls":
|
||||
return new(p.CallHierarchyOutgoingCallsParams)
|
||||
}
|
||||
log.Fatalf("request(%s) undefined", m)
|
||||
return ""
|
||||
@ -210,6 +214,10 @@ func Responses(m string) []interface{} {
|
||||
return []interface{}{new(p.Range), nil}
|
||||
case "textDocument/foldingRange":
|
||||
return []interface{}{new([]p.FoldingRange), nil}
|
||||
case "callHierarchy/incomingCalls":
|
||||
return []interface{}{new([]p.CallHierarchyIncomingCall), nil}
|
||||
case "callHierarchy/outgoingCalls":
|
||||
return []interface{}{new([]p.CallHierarchyOutgoingCall), nil}
|
||||
}
|
||||
log.Fatalf("responses(%q) undefined", m)
|
||||
return nil
|
||||
@ -307,4 +315,6 @@ var fromMethod = map[string]Msgtype{
|
||||
"textDocument/rename": Mreq | Mcl,
|
||||
"textDocument/prepareRename": Mreq | Mcl,
|
||||
"textDocument/foldingRange": Mreq | Mcl,
|
||||
"callHierarchy/incomingCalls": Mreq | Mcl,
|
||||
"callHierarchy/outgoingCalls": Mreq | Mcl,
|
||||
}
|
||||
|
39
internal/lsp/call_hierarchy.go
Normal file
39
internal/lsp/call_hierarchy.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package lsp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
func (s *Server) prepareCallHierarchy(ctx context.Context, params *protocol.CallHierarchyPrepareParams) ([]protocol.CallHierarchyItem, error) {
|
||||
snapshot, fh, ok, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return source.PrepareCallHierarchy(ctx, snapshot, fh, params.Position)
|
||||
}
|
||||
|
||||
func (s *Server) incomingCalls(ctx context.Context, params *protocol.CallHierarchyIncomingCallsParams) ([]protocol.CallHierarchyIncomingCall, error) {
|
||||
snapshot, fh, ok, err := s.beginFileRequest(ctx, params.Item.URI, source.Go)
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return source.IncomingCalls(ctx, snapshot, fh, params.Item.Range.Start)
|
||||
}
|
||||
|
||||
func (s *Server) outgoingCalls(ctx context.Context, params *protocol.CallHierarchyOutgoingCallsParams) ([]protocol.CallHierarchyOutgoingCall, error) {
|
||||
snapshot, fh, ok, err := s.beginFileRequest(ctx, params.Item.URI, source.Go)
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return source.OutgoingCalls(ctx, snapshot, fh, params.Item.Range.Start)
|
||||
}
|
117
internal/lsp/cmd/call_hierarchy.go
Normal file
117
internal/lsp/cmd/call_hierarchy.go
Normal file
@ -0,0 +1,117 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/span"
|
||||
"golang.org/x/tools/internal/tool"
|
||||
)
|
||||
|
||||
// callHierarchy implements the callHierarchy verb for gopls
|
||||
type callHierarchy struct {
|
||||
app *Application
|
||||
}
|
||||
|
||||
func (c *callHierarchy) Name() string { return "call_hierarchy" }
|
||||
func (c *callHierarchy) Usage() string { return "<position>" }
|
||||
func (c *callHierarchy) ShortHelp() string { return "display selected identifier's call hierarchy" }
|
||||
func (c *callHierarchy) DetailedHelp(f *flag.FlagSet) {
|
||||
fmt.Fprint(f.Output(), `
|
||||
Example:
|
||||
|
||||
$ # 1-indexed location (:line:column or :#offset) of the target identifier
|
||||
$ gopls call_hierarchy helper/helper.go:8:6
|
||||
$ gopls call_hierarchy helper/helper.go:#53
|
||||
|
||||
gopls call_hierarchy flags are:
|
||||
`)
|
||||
f.PrintDefaults()
|
||||
}
|
||||
|
||||
func (c *callHierarchy) Run(ctx context.Context, args ...string) error {
|
||||
if len(args) != 1 {
|
||||
return tool.CommandLineErrorf("call_hierarchy expects 1 argument (position)")
|
||||
}
|
||||
|
||||
conn, err := c.app.connect(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.terminate(ctx)
|
||||
|
||||
from := span.Parse(args[0])
|
||||
file := conn.AddFile(ctx, from.URI())
|
||||
if file.err != nil {
|
||||
return file.err
|
||||
}
|
||||
|
||||
columnMapper := file.mapper
|
||||
loc, err := columnMapper.Location(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := protocol.CallHierarchyPrepareParams{
|
||||
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
|
||||
Position: loc.Range.Start,
|
||||
},
|
||||
}
|
||||
|
||||
callItems, err := conn.PrepareCallHierarchy(ctx, &p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(callItems) == 0 {
|
||||
return fmt.Errorf("function declaration identifier not found at %v", args[0])
|
||||
}
|
||||
|
||||
for _, item := range callItems {
|
||||
incomingCalls, err := conn.IncomingCalls(ctx, &protocol.CallHierarchyIncomingCallsParams{Item: item})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, call := range incomingCalls {
|
||||
printString, err := toPrintString(columnMapper, call.From)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("caller[%d]: %s\n", i, printString)
|
||||
}
|
||||
|
||||
printString, err := toPrintString(columnMapper, item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("identifier: %s\n", printString)
|
||||
|
||||
outgoingCalls, err := conn.OutgoingCalls(ctx, &protocol.CallHierarchyOutgoingCallsParams{Item: item})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, call := range outgoingCalls {
|
||||
printString, err := toPrintString(columnMapper, call.To)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("callee[%d]: %s\n", i, printString)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func toPrintString(mapper *protocol.ColumnMapper, item protocol.CallHierarchyItem) (string, error) {
|
||||
span, err := mapper.Span(protocol.Location{URI: item.URI, Range: item.Range})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%v %v at %v", item.Detail, item.Name, span), nil
|
||||
}
|
@ -175,6 +175,7 @@ func (app *Application) mainCommands() []tool.Application {
|
||||
|
||||
func (app *Application) featureCommands() []tool.Application {
|
||||
return []tool.Application{
|
||||
&callHierarchy{app: app},
|
||||
&check{app: app},
|
||||
&definition{app: app},
|
||||
&foldingRanges{app: app},
|
||||
|
50
internal/lsp/cmd/test/call_hierarchy.go
Normal file
50
internal/lsp/cmd/test/call_hierarchy.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmdtest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/tests"
|
||||
"golang.org/x/tools/internal/span"
|
||||
)
|
||||
|
||||
func (r *runner) CallHierarchy(t *testing.T, spn span.Span, expectedCalls *tests.CallHierarchyResult) {
|
||||
var result []string
|
||||
// TODO: add expectedCalls.IncomingCalls and expectedCalls.OutgoingCalls to this array once implemented
|
||||
result = append(result, fmt.Sprint(spn))
|
||||
|
||||
sort.Strings(result) // to make tests deterministic
|
||||
expect := r.Normalize(strings.Join(result, "\n"))
|
||||
|
||||
uri := spn.URI()
|
||||
filename := uri.Filename()
|
||||
target := filename + fmt.Sprintf(":%v:%v", spn.Start().Line(), spn.Start().Column())
|
||||
|
||||
got, stderr := r.NormalizeGoplsCmd(t, "call_hierarchy", target)
|
||||
got = cleanCallHierarchyCmdResult(got)
|
||||
if stderr != "" {
|
||||
t.Errorf("call_hierarchy failed for %s: %s", target, stderr)
|
||||
} else if expect != got {
|
||||
t.Errorf("call_hierarchy failed for %s expected:\n%s\ngot:\n%s", target, expect, got)
|
||||
}
|
||||
}
|
||||
|
||||
// removes all info except URI and Range from printed output and sorts the result
|
||||
// ex: "identifier: func() d at file://callhierarchy/callhierarchy.go:19:6-7" -> "file://callhierarchy/callhierarchy.go:19:6-7"
|
||||
func cleanCallHierarchyCmdResult(output string) string {
|
||||
var clean []string
|
||||
for _, out := range strings.Split(output, "\n") {
|
||||
if out == "" {
|
||||
continue
|
||||
}
|
||||
clean = append(clean, out[strings.LastIndex(out, " ")+1:])
|
||||
}
|
||||
sort.Strings(clean)
|
||||
return strings.Join(clean, "\n")
|
||||
}
|
@ -85,7 +85,8 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitializ
|
||||
|
||||
return &protocol.InitializeResult{
|
||||
Capabilities: protocol.ServerCapabilities{
|
||||
CodeActionProvider: codeActionProvider,
|
||||
CallHierarchyProvider: true,
|
||||
CodeActionProvider: codeActionProvider,
|
||||
CompletionProvider: protocol.CompletionOptions{
|
||||
TriggerCharacters: []string{"."},
|
||||
},
|
||||
|
@ -99,6 +99,50 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) CallHierarchy(t *testing.T, spn span.Span, expectedCalls *tests.CallHierarchyResult) {
|
||||
mapper, err := r.data.Mapper(spn.URI())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
loc, err := mapper.Location(spn)
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", spn, err)
|
||||
}
|
||||
|
||||
params := &protocol.CallHierarchyPrepareParams{
|
||||
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
|
||||
Position: loc.Range.Start,
|
||||
},
|
||||
}
|
||||
|
||||
items, err := r.server.PrepareCallHierarchy(r.ctx, params)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(items) == 0 {
|
||||
t.Errorf("expected call hierarchy item to be returned for identifier at %v\n", loc.Range)
|
||||
}
|
||||
|
||||
callLocation := protocol.Location{
|
||||
URI: items[0].URI,
|
||||
Range: items[0].Range,
|
||||
}
|
||||
if callLocation != loc {
|
||||
t.Errorf("expected server.PrepareCallHierarchy to return identifier at %v but got %v\n", loc, callLocation)
|
||||
}
|
||||
|
||||
// TODO: add span comparison tests for expectedCalls once call hierarchy is implemented
|
||||
incomingCalls, err := r.server.IncomingCalls(r.ctx, &protocol.CallHierarchyIncomingCallsParams{Item: items[0]})
|
||||
if len(incomingCalls) != 0 {
|
||||
t.Errorf("expected no incoming calls but got %d", len(incomingCalls))
|
||||
}
|
||||
outgoingCalls, err := r.server.OutgoingCalls(r.ctx, &protocol.CallHierarchyOutgoingCallsParams{Item: items[0]})
|
||||
if len(outgoingCalls) != 0 {
|
||||
t.Errorf("expected no outgoing calls but got %d", len(outgoingCalls))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) {
|
||||
if source.DetectLanguage("", uri.Filename()) != source.Mod {
|
||||
return
|
||||
|
@ -100,8 +100,8 @@ func (s *Server) Implementation(ctx context.Context, params *protocol.Implementa
|
||||
return s.implementation(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) IncomingCalls(context.Context, *protocol.CallHierarchyIncomingCallsParams) ([]protocol.CallHierarchyIncomingCall, error) {
|
||||
return nil, notImplemented("IncomingCalls")
|
||||
func (s *Server) IncomingCalls(ctx context.Context, params *protocol.CallHierarchyIncomingCallsParams) ([]protocol.CallHierarchyIncomingCall, error) {
|
||||
return s.incomingCalls(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) Initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) {
|
||||
@ -124,12 +124,12 @@ func (s *Server) OnTypeFormatting(context.Context, *protocol.DocumentOnTypeForma
|
||||
return nil, notImplemented("OnTypeFormatting")
|
||||
}
|
||||
|
||||
func (s *Server) OutgoingCalls(context.Context, *protocol.CallHierarchyOutgoingCallsParams) ([]protocol.CallHierarchyOutgoingCall, error) {
|
||||
return nil, notImplemented("OutgoingCalls")
|
||||
func (s *Server) OutgoingCalls(ctx context.Context, params *protocol.CallHierarchyOutgoingCallsParams) ([]protocol.CallHierarchyOutgoingCall, error) {
|
||||
return s.outgoingCalls(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) PrepareCallHierarchy(context.Context, *protocol.CallHierarchyPrepareParams) ([]protocol.CallHierarchyItem, error) {
|
||||
return nil, notImplemented("PrepareCallHierarchy")
|
||||
func (s *Server) PrepareCallHierarchy(ctx context.Context, params *protocol.CallHierarchyPrepareParams) ([]protocol.CallHierarchyItem, error) {
|
||||
return s.prepareCallHierarchy(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) PrepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.Range, error) {
|
||||
|
68
internal/lsp/source/call_hierarchy.go
Normal file
68
internal/lsp/source/call_hierarchy.go
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/ast"
|
||||
|
||||
"golang.org/x/tools/internal/event"
|
||||
"golang.org/x/tools/internal/lsp/debug/tag"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// PrepareCallHierarchy returns an array of CallHierarchyItem for a file and the position within the file
|
||||
func PrepareCallHierarchy(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]protocol.CallHierarchyItem, error) {
|
||||
ctx, done := event.Start(ctx, "source.prepareCallHierarchy")
|
||||
defer done()
|
||||
|
||||
identifier, err := Identifier(ctx, snapshot, fh, pos)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrNoIdentFound) {
|
||||
event.Log(ctx, err.Error(), tag.Position.Of(pos))
|
||||
} else {
|
||||
event.Error(ctx, "error getting identifier", err, tag.Position.Of(pos))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if identifier is not of type function
|
||||
_, ok := identifier.Declaration.node.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
event.Log(ctx, "invalid identifier type, expected funtion declaration", tag.Position.Of(pos))
|
||||
return nil, nil
|
||||
}
|
||||
rng, err := identifier.Range()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
callHierarchyItem := protocol.CallHierarchyItem{
|
||||
Name: identifier.Name,
|
||||
Kind: protocol.Function,
|
||||
Tags: []protocol.SymbolTag{},
|
||||
Detail: "func()",
|
||||
URI: protocol.DocumentURI(fh.URI()),
|
||||
Range: rng,
|
||||
SelectionRange: rng,
|
||||
}
|
||||
return []protocol.CallHierarchyItem{callHierarchyItem}, nil
|
||||
}
|
||||
|
||||
// IncomingCalls returns an array of CallHierarchyIncomingCall for a file and the position within the file
|
||||
func IncomingCalls(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]protocol.CallHierarchyIncomingCall, error) {
|
||||
ctx, done := event.Start(ctx, "source.incomingCalls")
|
||||
defer done()
|
||||
|
||||
return []protocol.CallHierarchyIncomingCall{}, nil
|
||||
}
|
||||
|
||||
// OutgoingCalls returns an array of CallHierarchyOutgoingCall for a file and the position within the file
|
||||
func OutgoingCalls(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]protocol.CallHierarchyOutgoingCall, error) {
|
||||
ctx, done := event.Start(ctx, "source.outgoingCalls")
|
||||
defer done()
|
||||
|
||||
return []protocol.CallHierarchyOutgoingCall{}, nil
|
||||
}
|
@ -96,6 +96,47 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) CallHierarchy(t *testing.T, spn span.Span, expectedCalls *tests.CallHierarchyResult) {
|
||||
mapper, err := r.data.Mapper(spn.URI())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
loc, err := mapper.Location(spn)
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", spn, err)
|
||||
}
|
||||
fh, err := r.view.Snapshot().GetFile(r.ctx, spn.URI())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
items, err := source.PrepareCallHierarchy(r.ctx, r.view.Snapshot(), fh, loc.Range.Start)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(items) == 0 {
|
||||
t.Errorf("expected call hierarchy item to be returned for identifier at %v\n", loc.Range)
|
||||
}
|
||||
|
||||
callLocation := protocol.Location{
|
||||
URI: items[0].URI,
|
||||
Range: items[0].Range,
|
||||
}
|
||||
if callLocation != loc {
|
||||
t.Errorf("expected source.PrepareCallHierarchy to return identifier at %v but got %v\n", loc, callLocation)
|
||||
}
|
||||
|
||||
// TODO: add span comparison tests for expectedCalls once call hierarchy is implemented
|
||||
incomingCalls, err := source.IncomingCalls(r.ctx, r.view.Snapshot(), fh, loc.Range.Start)
|
||||
if len(incomingCalls) != 0 {
|
||||
t.Errorf("expected no incoming calls but got %d", len(incomingCalls))
|
||||
}
|
||||
outgoingCalls, err := source.OutgoingCalls(r.ctx, r.view.Snapshot(), fh, loc.Range.Start)
|
||||
if len(outgoingCalls) != 0 {
|
||||
t.Errorf("expected no outgoing calls but got %d", len(outgoingCalls))
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []*source.Diagnostic) {
|
||||
fileID, got, err := source.FileDiagnostics(r.ctx, r.snapshot, uri)
|
||||
if err != nil {
|
||||
|
35
internal/lsp/testdata/lsp/primarymod/callhierarchy/callhierarchy.go
vendored
Normal file
35
internal/lsp/testdata/lsp/primarymod/callhierarchy/callhierarchy.go
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
func a() { //@mark(funcA, "a")
|
||||
d()
|
||||
}
|
||||
|
||||
func b() { //@mark(funcB, "b")
|
||||
d()
|
||||
}
|
||||
|
||||
func c() { //@mark(funcC, "c")
|
||||
d()
|
||||
}
|
||||
|
||||
func d() { //@mark(funcD, "d"),incomingcalls("d", funcA, funcB, funcC),outgoingcalls("d", funcE, funcF, funcG)
|
||||
e()
|
||||
f()
|
||||
g()
|
||||
}
|
||||
|
||||
func e() {} //@mark(funcE, "e")
|
||||
|
||||
func f() {} //@mark(funcF, "f")
|
||||
|
||||
func g() {} //@mark(funcG, "g")
|
||||
|
||||
func main() {
|
||||
a()
|
||||
b()
|
||||
c()
|
||||
}
|
1
internal/lsp/testdata/lsp/summary.txt.golden
vendored
1
internal/lsp/testdata/lsp/summary.txt.golden
vendored
@ -1,4 +1,5 @@
|
||||
-- summary --
|
||||
CallHierarchyCount = 1
|
||||
CodeLensCount = 4
|
||||
CompletionsCount = 241
|
||||
CompletionSnippetCount = 81
|
||||
|
@ -1,4 +1,5 @@
|
||||
-- summary --
|
||||
CallHierarchyCount = 0
|
||||
CodeLensCount = 0
|
||||
CompletionsCount = 0
|
||||
CompletionSnippetCount = 0
|
||||
|
@ -1,4 +1,5 @@
|
||||
-- summary --
|
||||
CallHierarchyCount = 0
|
||||
CodeLensCount = 0
|
||||
CompletionsCount = 0
|
||||
CompletionSnippetCount = 0
|
||||
|
@ -1,4 +1,5 @@
|
||||
-- summary --
|
||||
CallHierarchyCount = 0
|
||||
CodeLensCount = 0
|
||||
CompletionsCount = 0
|
||||
CompletionSnippetCount = 0
|
||||
|
@ -1,4 +1,5 @@
|
||||
-- summary --
|
||||
CallHierarchyCount = 0
|
||||
CodeLensCount = 2
|
||||
CompletionsCount = 0
|
||||
CompletionSnippetCount = 0
|
||||
|
@ -43,6 +43,7 @@ const (
|
||||
|
||||
var UpdateGolden = flag.Bool("golden", false, "Update golden files")
|
||||
|
||||
type CallHierarchy map[span.Span]*CallHierarchyResult
|
||||
type CodeLens map[span.URI][]protocol.CodeLens
|
||||
type Diagnostics map[span.URI][]*source.Diagnostic
|
||||
type CompletionItems map[token.Pos]*source.CompletionItem
|
||||
@ -74,6 +75,7 @@ type Links map[span.URI][]Link
|
||||
type Data struct {
|
||||
Config packages.Config
|
||||
Exported *packagestest.Exported
|
||||
CallHierarchy CallHierarchy
|
||||
CodeLens CodeLens
|
||||
Diagnostics Diagnostics
|
||||
CompletionItems CompletionItems
|
||||
@ -117,6 +119,7 @@ type Data struct {
|
||||
}
|
||||
|
||||
type Tests interface {
|
||||
CallHierarchy(*testing.T, span.Span, *CallHierarchyResult)
|
||||
CodeLens(*testing.T, span.URI, []protocol.CodeLens)
|
||||
Diagnostics(*testing.T, span.URI, []*source.Diagnostic)
|
||||
Completion(*testing.T, span.Span, Completion, CompletionItems)
|
||||
@ -197,6 +200,10 @@ type CompletionSnippet struct {
|
||||
PlaceholderSnippet string
|
||||
}
|
||||
|
||||
type CallHierarchyResult struct {
|
||||
IncomingCalls, OutgoingCalls []span.Span
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
Src span.Span
|
||||
Target string
|
||||
@ -274,6 +281,7 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) []*Data {
|
||||
var data []*Data
|
||||
for _, folder := range folders {
|
||||
datum := &Data{
|
||||
CallHierarchy: make(CallHierarchy),
|
||||
CodeLens: make(CodeLens),
|
||||
Diagnostics: make(Diagnostics),
|
||||
CompletionItems: make(CompletionItems),
|
||||
@ -425,6 +433,8 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) []*Data {
|
||||
"link": datum.collectLinks,
|
||||
"suggestedfix": datum.collectSuggestedFixes,
|
||||
"extractfunc": datum.collectFunctionExtractions,
|
||||
"incomingcalls": datum.collectIncomingCalls,
|
||||
"outgoingcalls": datum.collectOutgoingCalls,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -495,6 +505,16 @@ func Run(t *testing.T, tests Tests, data *Data) {
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("CallHierarchy", func(t *testing.T) {
|
||||
t.Helper()
|
||||
for spn, callHierarchyResult := range data.CallHierarchy {
|
||||
t.Run(SpanName(spn), func(t *testing.T) {
|
||||
t.Helper()
|
||||
tests.CallHierarchy(t, spn, callHierarchyResult)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Completion", func(t *testing.T) {
|
||||
t.Helper()
|
||||
eachCompletion(t, data.Completions, tests.Completion)
|
||||
@ -807,6 +827,7 @@ func checkData(t *testing.T, data *Data) {
|
||||
return count
|
||||
}
|
||||
|
||||
fmt.Fprintf(buf, "CallHierarchyCount = %v\n", len(data.CallHierarchy))
|
||||
fmt.Fprintf(buf, "CodeLensCount = %v\n", countCodeLens(data.CodeLens))
|
||||
fmt.Fprintf(buf, "CompletionsCount = %v\n", countCompletions(data.Completions))
|
||||
fmt.Fprintf(buf, "CompletionSnippetCount = %v\n", snippetCount)
|
||||
@ -1060,6 +1081,26 @@ func (data *Data) collectImplementations(src span.Span, targets []span.Span) {
|
||||
data.Implementations[src] = targets
|
||||
}
|
||||
|
||||
func (data *Data) collectIncomingCalls(src span.Span, calls []span.Span) {
|
||||
if data.CallHierarchy[src] != nil {
|
||||
data.CallHierarchy[src].IncomingCalls = calls
|
||||
} else {
|
||||
data.CallHierarchy[src] = &CallHierarchyResult{
|
||||
IncomingCalls: calls,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (data *Data) collectOutgoingCalls(src span.Span, calls []span.Span) {
|
||||
if data.CallHierarchy[src] != nil {
|
||||
data.CallHierarchy[src].OutgoingCalls = calls
|
||||
} else {
|
||||
data.CallHierarchy[src] = &CallHierarchyResult{
|
||||
OutgoingCalls: calls,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (data *Data) collectHoverDefinitions(src, target span.Span) {
|
||||
data.Definitions[src] = Definition{
|
||||
Src: src,
|
||||
|
Loading…
Reference in New Issue
Block a user