зеркало из https://github.com/golang/tools.git
internal/lsp: correctly report interface symbols
Updates golang/go#30915 Change-Id: I9c5faa615df506cf1d015a9eb48196fa9b0387ee Reviewed-on: https://go-review.googlesource.com/c/tools/+/169682 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Родитель
2898d834dc
Коммит
8f05a32dce
|
@ -14,6 +14,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -43,6 +44,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|||
const expectedDefinitionsCount = 16
|
||||
const expectedTypeDefinitionsCount = 2
|
||||
const expectedHighlightsCount = 2
|
||||
const expectedSymbolsCount = 1
|
||||
|
||||
files := packagestest.MustCopyFileTree(dir)
|
||||
for fragment, operation := range files {
|
||||
|
@ -87,6 +89,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|||
expectedDefinitions := make(definitions)
|
||||
expectedTypeDefinitions := make(definitions)
|
||||
expectedHighlights := make(highlights)
|
||||
expectedSymbols := make(symbols)
|
||||
|
||||
// Collect any data that needs to be used by subsequent tests.
|
||||
if err := exported.Expect(map[string]interface{}{
|
||||
|
@ -97,6 +100,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|||
"godef": expectedDefinitions.collect,
|
||||
"typdef": expectedTypeDefinitions.collect,
|
||||
"highlight": expectedHighlights.collect,
|
||||
"symbol": expectedSymbols.collect,
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -168,6 +172,16 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|||
}
|
||||
expectedHighlights.test(t, s)
|
||||
})
|
||||
|
||||
t.Run("Symbols", func(t *testing.T) {
|
||||
t.Helper()
|
||||
if goVersion111 { // TODO(rstambler): Remove this when we no longer support Go 1.10.
|
||||
if len(expectedSymbols) != expectedSymbolsCount {
|
||||
t.Errorf("got %v symbols expected %v", len(expectedSymbols), expectedSymbolsCount)
|
||||
}
|
||||
}
|
||||
expectedSymbols.test(t, s)
|
||||
})
|
||||
}
|
||||
|
||||
type diagnostics map[span.URI][]protocol.Diagnostic
|
||||
|
@ -176,6 +190,7 @@ type completions map[token.Position][]token.Pos
|
|||
type formats map[string]string
|
||||
type definitions map[protocol.Location]protocol.Location
|
||||
type highlights map[string][]protocol.Location
|
||||
type symbols map[span.URI][]protocol.DocumentSymbol
|
||||
|
||||
func (d diagnostics) test(t *testing.T, v source.View) int {
|
||||
count := 0
|
||||
|
@ -503,6 +518,70 @@ func (h highlights) test(t *testing.T, s *server) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s symbols) collect(e *packagestest.Exported, fset *token.FileSet, name string, rng span.Range, kind int64) {
|
||||
f := fset.File(rng.Start)
|
||||
if f == nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, err := e.FileContents(f.Name())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
spn, err := rng.Span()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
m := protocol.NewColumnMapper(spn.URI(), fset, f, content)
|
||||
prng, err := m.Range(spn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s[spn.URI()] = append(s[spn.URI()], protocol.DocumentSymbol{
|
||||
Name: name,
|
||||
Kind: protocol.SymbolKind(kind),
|
||||
SelectionRange: prng,
|
||||
})
|
||||
}
|
||||
|
||||
func (s symbols) test(t *testing.T, server *server) {
|
||||
for uri, expectedSymbols := range s {
|
||||
params := &protocol.DocumentSymbolParams{
|
||||
TextDocument: protocol.TextDocumentIdentifier{
|
||||
URI: string(uri),
|
||||
},
|
||||
}
|
||||
symbols, err := server.DocumentSymbol(context.Background(), params)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(symbols) != len(expectedSymbols) {
|
||||
t.Errorf("want %d symbols in %v, got %d", len(expectedSymbols), uri, len(symbols))
|
||||
continue
|
||||
}
|
||||
|
||||
sort.Slice(symbols, func(i, j int) bool { return symbols[i].Name < symbols[j].Name })
|
||||
sort.Slice(expectedSymbols, func(i, j int) bool { return expectedSymbols[i].Name < expectedSymbols[j].Name })
|
||||
for i, w := range expectedSymbols {
|
||||
g := symbols[i]
|
||||
if w.Name != g.Name {
|
||||
t.Errorf("%s: want symbol %q, got %q", uri, w.Name, g.Name)
|
||||
continue
|
||||
}
|
||||
if w.Kind != g.Kind {
|
||||
t.Errorf("%s: want kind %v for %s, got %v", uri, w.Kind, w.Name, g.Kind)
|
||||
}
|
||||
if w.SelectionRange != g.SelectionRange {
|
||||
t.Errorf("%s: want selection range %v for %s, got %v", uri, w.SelectionRange, w.Name, g.SelectionRange)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testLocation(e *packagestest.Exported, fset *token.FileSet, rng packagestest.Range) (span.Span, *protocol.ColumnMapper) {
|
||||
spn, err := span.NewRange(fset, rng.Start, rng.End).Span()
|
||||
if err != nil {
|
||||
|
|
|
@ -23,6 +23,7 @@ const (
|
|||
ConstantSymbol
|
||||
FunctionSymbol
|
||||
MethodSymbol
|
||||
InterfaceSymbol
|
||||
)
|
||||
|
||||
type Symbol struct {
|
||||
|
@ -100,6 +101,9 @@ func typeSymbol(spec *ast.TypeSpec, obj types.Object, fset *token.FileSet, q typ
|
|||
Name: obj.Name(),
|
||||
Kind: StructSymbol,
|
||||
}
|
||||
if types.IsInterface(obj.Type()) {
|
||||
s.Kind = InterfaceSymbol
|
||||
}
|
||||
if span, err := nodeSpan(spec, fset); err == nil {
|
||||
s.Span = span
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ func toProtocolSymbolKind(kind source.SymbolKind) protocol.SymbolKind {
|
|||
return protocol.Function
|
||||
case source.MethodSymbol:
|
||||
return protocol.Method
|
||||
case source.InterfaceSymbol:
|
||||
return protocol.Interface
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package main
|
||||
|
||||
var x = 42 //@symbol("x", "x", 13)
|
||||
|
||||
const y = 43 //@symbol("y", "y", 14)
|
||||
|
||||
type Foo struct { //@symbol("Foo", "Foo", 23)
|
||||
Quux
|
||||
Bar int
|
||||
baz string
|
||||
}
|
||||
|
||||
type Quux struct { //@symbol("Quux", "Quux", 23)
|
||||
X float64
|
||||
}
|
||||
|
||||
func (f Foo) Baz() string { //@symbol("Baz", "Baz", 6)
|
||||
return f.baz
|
||||
}
|
||||
|
||||
func main() { //@symbol("main", "main", 12)
|
||||
|
||||
}
|
||||
|
||||
type Stringer interface { //@symbol("Stringer", "Stringer", 11)
|
||||
String() string
|
||||
}
|
Загрузка…
Ссылка в новой задаче