mirror of https://github.com/golang/go.git
internal/lsp: switch to using protocol positions for document symbols
Change-Id: I8e550b753328b8e536bff3bb61b4ff4486fcd4f9 Reviewed-on: https://go-review.googlesource.com/c/tools/+/193722 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
bb4ee55d3d
commit
04840ef8f3
|
|
@ -9,47 +9,29 @@ import (
|
|||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/lsp/telemetry"
|
||||
"golang.org/x/tools/internal/span"
|
||||
"golang.org/x/tools/internal/telemetry/log"
|
||||
"golang.org/x/tools/internal/telemetry/tag"
|
||||
)
|
||||
|
||||
func (s *Server) documentHighlight(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.DocumentHighlight, error) {
|
||||
uri := span.NewURI(params.TextDocument.URI)
|
||||
view := s.session.ViewOf(uri)
|
||||
f, err := getGoFile(ctx, view, uri)
|
||||
rngs, err := source.Highlight(ctx, view, uri, params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
log.Error(ctx, "no highlight", err, telemetry.URI.Of(uri))
|
||||
}
|
||||
m, err := getMapper(ctx, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spn, err := m.PointSpan(params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spans, err := source.Highlight(ctx, f, rng.Start)
|
||||
if err != nil {
|
||||
log.Error(ctx, "no highlight", err, tag.Of("Span", spn))
|
||||
}
|
||||
return toProtocolHighlight(m, spans), nil
|
||||
return toProtocolHighlight(rngs), nil
|
||||
}
|
||||
|
||||
func toProtocolHighlight(m *protocol.ColumnMapper, spans []span.Span) []protocol.DocumentHighlight {
|
||||
result := make([]protocol.DocumentHighlight, 0, len(spans))
|
||||
func toProtocolHighlight(rngs []protocol.Range) []protocol.DocumentHighlight {
|
||||
result := make([]protocol.DocumentHighlight, 0, len(rngs))
|
||||
kind := protocol.Text
|
||||
for _, span := range spans {
|
||||
r, err := m.Range(span)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
h := protocol.DocumentHighlight{Kind: &kind, Range: r}
|
||||
result = append(result, h)
|
||||
for _, rng := range rngs {
|
||||
result = append(result, protocol.DocumentHighlight{
|
||||
Kind: &kind,
|
||||
Range: rng,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -678,7 +678,6 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sedits, err := source.FromProtocolEdits(m, edits)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
|
@ -791,30 +790,22 @@ func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
|||
}
|
||||
}
|
||||
|
||||
func (r *runner) diffSymbols(t *testing.T, uri span.URI, want []source.Symbol, got []protocol.DocumentSymbol) string {
|
||||
func (r *runner) diffSymbols(t *testing.T, uri span.URI, want []protocol.DocumentSymbol, got []protocol.DocumentSymbol) string {
|
||||
sort.Slice(want, func(i, j int) bool { return want[i].Name < want[j].Name })
|
||||
sort.Slice(got, func(i, j int) bool { return got[i].Name < got[j].Name })
|
||||
m, err := r.mapper(uri)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
return summarizeSymbols(-1, want, got, "different lengths got %v want %v", len(got), len(want))
|
||||
return summarizeSymbols(t, -1, want, got, "different lengths got %v want %v", len(got), len(want))
|
||||
}
|
||||
for i, w := range want {
|
||||
g := got[i]
|
||||
if w.Name != g.Name {
|
||||
return summarizeSymbols(i, want, got, "incorrect name got %v want %v", g.Name, w.Name)
|
||||
return summarizeSymbols(t, i, want, got, "incorrect name got %v want %v", g.Name, w.Name)
|
||||
}
|
||||
if wkind := toProtocolSymbolKind(w.Kind); wkind != g.Kind {
|
||||
return summarizeSymbols(i, want, got, "incorrect kind got %v want %v", g.Kind, wkind)
|
||||
if w.Kind != g.Kind {
|
||||
return summarizeSymbols(t, i, want, got, "incorrect kind got %v want %v", g.Kind, w.Kind)
|
||||
}
|
||||
spn, err := m.RangeSpan(g.SelectionRange)
|
||||
if err != nil {
|
||||
return summarizeSymbols(i, want, got, "%v", err)
|
||||
}
|
||||
if w.SelectionSpan != spn {
|
||||
return summarizeSymbols(i, want, got, "incorrect span got %v want %v", spn, w.SelectionSpan)
|
||||
if protocol.CompareRange(g.SelectionRange, w.SelectionRange) != 0 {
|
||||
return summarizeSymbols(t, i, want, got, "incorrect span got %v want %v", g.SelectionRange, w.SelectionRange)
|
||||
}
|
||||
if msg := r.diffSymbols(t, uri, w.Children, g.Children); msg != "" {
|
||||
return fmt.Sprintf("children of %s: %s", w.Name, msg)
|
||||
|
|
@ -823,7 +814,7 @@ func (r *runner) diffSymbols(t *testing.T, uri span.URI, want []source.Symbol, g
|
|||
return ""
|
||||
}
|
||||
|
||||
func summarizeSymbols(i int, want []source.Symbol, got []protocol.DocumentSymbol, reason string, args ...interface{}) string {
|
||||
func summarizeSymbols(t *testing.T, i int, want []protocol.DocumentSymbol, got []protocol.DocumentSymbol, reason string, args ...interface{}) string {
|
||||
msg := &bytes.Buffer{}
|
||||
fmt.Fprint(msg, "document symbols failed")
|
||||
if i >= 0 {
|
||||
|
|
@ -833,7 +824,7 @@ func summarizeSymbols(i int, want []source.Symbol, got []protocol.DocumentSymbol
|
|||
fmt.Fprintf(msg, reason, args...)
|
||||
fmt.Fprint(msg, ":\nexpected:\n")
|
||||
for _, s := range want {
|
||||
fmt.Fprintf(msg, " %v %v %v\n", s.Name, s.Kind, s.SelectionSpan)
|
||||
fmt.Fprintf(msg, " %v %v %v\n", s.Name, s.Kind, s.SelectionRange)
|
||||
}
|
||||
fmt.Fprintf(msg, "got:\n")
|
||||
for _, s := range got {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
|||
if !c.opts.Documentation {
|
||||
return item, nil
|
||||
}
|
||||
declRange, err := objToRange(c.ctx, c.view, obj)
|
||||
declRange, err := objToMappedRange(c.ctx, c.view, obj)
|
||||
if err != nil {
|
||||
return item, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,27 +4,16 @@
|
|||
|
||||
package source
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
namesSymbolKind [int(FieldSymbol) + 1]string
|
||||
namesDiagnosticSeverity [int(SeverityError) + 1]string
|
||||
namesCompletionItemKind [int(PackageCompletionItem) + 1]string
|
||||
)
|
||||
|
||||
func init() {
|
||||
namesSymbolKind[PackageSymbol] = "Package"
|
||||
namesSymbolKind[StructSymbol] = "Struct"
|
||||
namesSymbolKind[VariableSymbol] = "Variable"
|
||||
namesSymbolKind[ConstantSymbol] = "Constant"
|
||||
namesSymbolKind[FunctionSymbol] = "Function"
|
||||
namesSymbolKind[MethodSymbol] = "Method"
|
||||
namesSymbolKind[InterfaceSymbol] = "Interface"
|
||||
namesSymbolKind[NumberSymbol] = "Number"
|
||||
namesSymbolKind[StringSymbol] = "String"
|
||||
namesSymbolKind[BooleanSymbol] = "Boolean"
|
||||
namesSymbolKind[FieldSymbol] = "Field"
|
||||
|
||||
namesDiagnosticSeverity[SeverityWarning] = "Warning"
|
||||
namesDiagnosticSeverity[SeverityError] = "Error"
|
||||
|
||||
|
|
@ -62,14 +51,6 @@ func parseEnum(s string, names []string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func (e SymbolKind) Format(f fmt.State, c rune) {
|
||||
formatEnum(f, c, int(e), namesSymbolKind[:], "SymbolKind")
|
||||
}
|
||||
|
||||
func ParseSymbolKind(s string) SymbolKind {
|
||||
return SymbolKind(parseEnum(s, namesSymbolKind[:]))
|
||||
}
|
||||
|
||||
func (e DiagnosticSeverity) Format(f fmt.State, c rune) {
|
||||
formatEnum(f, c, int(e), namesDiagnosticSeverity[:], "DiagnosticSeverity")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,38 +7,45 @@ package source
|
|||
import (
|
||||
"context"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/span"
|
||||
"golang.org/x/tools/internal/telemetry/trace"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func Highlight(ctx context.Context, f GoFile, pos token.Pos) ([]span.Span, error) {
|
||||
func Highlight(ctx context.Context, view View, uri span.URI, pos protocol.Position) ([]protocol.Range, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.Highlight")
|
||||
defer done()
|
||||
|
||||
file, err := f.GetAST(ctx, ParseFull)
|
||||
if file == nil {
|
||||
file, _, m, err := fileToMapper(ctx, view, uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fset := f.FileSet()
|
||||
path, _ := astutil.PathEnclosingInterval(file, pos, pos)
|
||||
spn, err := m.PointSpan(pos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path, _ := astutil.PathEnclosingInterval(file, rng.Start, rng.Start)
|
||||
if len(path) == 0 {
|
||||
return nil, errors.Errorf("no enclosing position found for %s", fset.Position(pos))
|
||||
return nil, errors.Errorf("no enclosing position found for %s", pos)
|
||||
}
|
||||
id, ok := path[0].(*ast.Ident)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("%s is not an identifier", fset.Position(pos))
|
||||
return nil, errors.Errorf("%s is not an identifier", pos)
|
||||
}
|
||||
var result []span.Span
|
||||
var result []protocol.Range
|
||||
if id.Obj != nil {
|
||||
ast.Inspect(path[len(path)-1], func(n ast.Node) bool {
|
||||
if n, ok := n.(*ast.Ident); ok && n.Obj == id.Obj {
|
||||
s, err := nodeSpan(n, fset)
|
||||
rng, err := nodeToProtocolRange(ctx, view, n)
|
||||
if err == nil {
|
||||
result = append(result, s)
|
||||
result = append(result, rng)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ func identifier(ctx context.Context, view View, f GoFile, pkg Package, file *ast
|
|||
return nil, errors.Errorf("no declaration for %s", result.Name)
|
||||
}
|
||||
result.Declaration.node = decl
|
||||
if result.Declaration.mappedRange, err = nameToRange(ctx, view, decl.Pos(), result.Name); err != nil {
|
||||
if result.Declaration.mappedRange, err = nameToMappedRange(ctx, view, decl.Pos(), result.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
|
|
@ -165,7 +165,7 @@ func identifier(ctx context.Context, view View, f GoFile, pkg Package, file *ast
|
|||
}
|
||||
}
|
||||
|
||||
if result.Declaration.mappedRange, err = objToRange(ctx, view, result.Declaration.obj); err != nil {
|
||||
if result.Declaration.mappedRange, err = objToMappedRange(ctx, view, result.Declaration.obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.Declaration.node, err = objToNode(ctx, f.View(), pkg.GetTypes(), result.Declaration.obj, result.Declaration.mappedRange.spanRange); err != nil {
|
||||
|
|
@ -182,7 +182,7 @@ func identifier(ctx context.Context, view View, f GoFile, pkg Package, file *ast
|
|||
if hasErrorType(result.Type.Object) {
|
||||
return result, nil
|
||||
}
|
||||
if result.Type.mappedRange, err = objToRange(ctx, view, result.Type.Object); err != nil {
|
||||
if result.Type.mappedRange, err = objToMappedRange(ctx, view, result.Type.Object); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
@ -204,47 +204,6 @@ func hasErrorType(obj types.Object) bool {
|
|||
return types.IsInterface(obj.Type()) && obj.Pkg() == nil && obj.Name() == "error"
|
||||
}
|
||||
|
||||
func objToRange(ctx context.Context, view View, obj types.Object) (mappedRange, error) {
|
||||
if pkgName, ok := obj.(*types.PkgName); ok {
|
||||
// An imported Go package has a package-local, unqualified name.
|
||||
// When the name matches the imported package name, there is no
|
||||
// identifier in the import spec with the local package name.
|
||||
//
|
||||
// For example:
|
||||
// import "go/ast" // name "ast" matches package name
|
||||
// import a "go/ast" // name "a" does not match package name
|
||||
//
|
||||
// When the identifier does not appear in the source, have the range
|
||||
// of the object be the point at the beginning of the declaration.
|
||||
if pkgName.Imported().Name() == pkgName.Name() {
|
||||
return nameToRange(ctx, view, obj.Pos(), "")
|
||||
}
|
||||
}
|
||||
return nameToRange(ctx, view, obj.Pos(), obj.Name())
|
||||
}
|
||||
|
||||
func nameToRange(ctx context.Context, view View, pos token.Pos, name string) (mappedRange, error) {
|
||||
return posToRange(ctx, view, pos, pos+token.Pos(len(name)))
|
||||
}
|
||||
|
||||
func posToRange(ctx context.Context, view View, pos, end token.Pos) (mappedRange, error) {
|
||||
if !pos.IsValid() {
|
||||
return mappedRange{}, errors.Errorf("invalid position for %v", pos)
|
||||
}
|
||||
if !end.IsValid() {
|
||||
return mappedRange{}, errors.Errorf("invalid position for %v", end)
|
||||
}
|
||||
posn := view.Session().Cache().FileSet().Position(pos)
|
||||
_, m, err := cachedFileToMapper(ctx, view, span.FileURI(posn.Filename))
|
||||
if err != nil {
|
||||
return mappedRange{}, err
|
||||
}
|
||||
return mappedRange{
|
||||
m: m,
|
||||
spanRange: span.NewRange(view.Session().Cache().FileSet(), pos, end),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func objToNode(ctx context.Context, view View, originPkg *types.Package, obj types.Object, rng span.Range) (ast.Decl, error) {
|
||||
s, err := rng.Span()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ func getPkgNameIdentifier(ctx context.Context, ident *IdentifierInfo, pkgName *t
|
|||
wasImplicit: true,
|
||||
}
|
||||
var err error
|
||||
if decl.mappedRange, err = objToRange(ctx, ident.File.View(), decl.obj); err != nil {
|
||||
if decl.mappedRange, err = objToMappedRange(ctx, ident.File.View(), decl.obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if decl.node, err = objToNode(ctx, ident.File.View(), ident.pkg.GetTypes(), decl.obj, decl.mappedRange.spanRange); err != nil {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ FindCall:
|
|||
comment *ast.CommentGroup
|
||||
)
|
||||
if obj != nil {
|
||||
rng, err := objToRange(ctx, view, obj)
|
||||
rng, err := objToMappedRange(ctx, view, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", d.Src, err)
|
||||
}
|
||||
srcRng, err := spanToRange(r.data, d.Src)
|
||||
_, srcRng, err := spanToRange(r.data, d.Src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -529,7 +529,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
|||
t.Errorf("for %v got %q want %q", d.Src, hover, expectHover)
|
||||
}
|
||||
} else if !d.OnlyHover {
|
||||
if defRng, err := spanToRange(r.data, d.Def); err != nil {
|
||||
if _, defRng, err := spanToRange(r.data, d.Def); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if rng != defRng {
|
||||
t.Errorf("for %v got %v want %v", d.Src, rng, d.Def)
|
||||
|
|
@ -544,25 +544,24 @@ func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
|
|||
ctx := r.ctx
|
||||
for name, locations := range data {
|
||||
src := locations[0]
|
||||
f, err := r.view.GetFile(ctx, src.URI())
|
||||
m, srcRng, err := spanToRange(r.data, src)
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", src, err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
tok, err := f.(source.GoFile).GetToken(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get token for %s: %v", src.URI(), err)
|
||||
}
|
||||
pos := tok.Pos(src.Start().Offset())
|
||||
highlights, err := source.Highlight(ctx, f.(source.GoFile), pos)
|
||||
highlights, err := source.Highlight(ctx, r.view, src.URI(), srcRng.Start)
|
||||
if err != nil {
|
||||
t.Errorf("highlight failed for %s: %v", src.URI(), err)
|
||||
}
|
||||
if len(highlights) != len(locations) {
|
||||
t.Errorf("got %d highlights for %s, expected %d", len(highlights), name, len(locations))
|
||||
}
|
||||
for i, h := range highlights {
|
||||
if h != locations[i] {
|
||||
t.Errorf("want %v, got %v\n", locations[i], h)
|
||||
for i, got := range highlights {
|
||||
want, err := m.Range(locations[i])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("want %v, got %v\n", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -575,7 +574,7 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", src, err)
|
||||
}
|
||||
srcRng, err := spanToRange(r.data, src)
|
||||
_, srcRng, err := spanToRange(r.data, src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -624,7 +623,7 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", spn, err)
|
||||
}
|
||||
srcRng, err := spanToRange(r.data, spn)
|
||||
_, srcRng, err := spanToRange(r.data, spn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -704,7 +703,7 @@ func (r *runner) PrepareRename(t *testing.T, data tests.PrepareRenames) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srcRng, err := spanToRange(r.data, src)
|
||||
_, srcRng, err := spanToRange(r.data, src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -751,7 +750,7 @@ func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", uri, err)
|
||||
}
|
||||
symbols, err := source.DocumentSymbols(ctx, f.(source.GoFile))
|
||||
symbols, err := source.DocumentSymbols(ctx, r.view, f.(source.GoFile))
|
||||
if err != nil {
|
||||
t.Errorf("symbols failed for %s: %v", uri, err)
|
||||
}
|
||||
|
|
@ -759,37 +758,37 @@ func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
|||
t.Errorf("want %d top-level symbols in %v, got %d", len(expectedSymbols), uri, len(symbols))
|
||||
continue
|
||||
}
|
||||
if diff := r.diffSymbols(uri, expectedSymbols, symbols); diff != "" {
|
||||
if diff := r.diffSymbols(t, uri, expectedSymbols, symbols); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runner) diffSymbols(uri span.URI, want []source.Symbol, got []source.Symbol) string {
|
||||
func (r *runner) diffSymbols(t *testing.T, uri span.URI, want, got []protocol.DocumentSymbol) string {
|
||||
sort.Slice(want, func(i, j int) bool { return want[i].Name < want[j].Name })
|
||||
sort.Slice(got, func(i, j int) bool { return got[i].Name < got[j].Name })
|
||||
if len(got) != len(want) {
|
||||
return summarizeSymbols(-1, want, got, "different lengths got %v want %v", len(got), len(want))
|
||||
return summarizeSymbols(t, -1, want, got, "different lengths got %v want %v", len(got), len(want))
|
||||
}
|
||||
for i, w := range want {
|
||||
g := got[i]
|
||||
if w.Name != g.Name {
|
||||
return summarizeSymbols(i, want, got, "incorrect name got %v want %v", g.Name, w.Name)
|
||||
return summarizeSymbols(t, i, want, got, "incorrect name got %v want %v", g.Name, w.Name)
|
||||
}
|
||||
if w.Kind != g.Kind {
|
||||
return summarizeSymbols(i, want, got, "incorrect kind got %v want %v", g.Kind, w.Kind)
|
||||
return summarizeSymbols(t, i, want, got, "incorrect kind got %v want %v", g.Kind, w.Kind)
|
||||
}
|
||||
if w.SelectionSpan != g.SelectionSpan {
|
||||
return summarizeSymbols(i, want, got, "incorrect span got %v want %v", g.SelectionSpan, w.SelectionSpan)
|
||||
if protocol.CompareRange(w.SelectionRange, g.SelectionRange) != 0 {
|
||||
return summarizeSymbols(t, i, want, got, "incorrect span got %v want %v", g.SelectionRange, w.SelectionRange)
|
||||
}
|
||||
if msg := r.diffSymbols(uri, w.Children, g.Children); msg != "" {
|
||||
if msg := r.diffSymbols(t, uri, w.Children, g.Children); msg != "" {
|
||||
return fmt.Sprintf("children of %s: %s", w.Name, msg)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func summarizeSymbols(i int, want []source.Symbol, got []source.Symbol, reason string, args ...interface{}) string {
|
||||
func summarizeSymbols(t *testing.T, i int, want, got []protocol.DocumentSymbol, reason string, args ...interface{}) string {
|
||||
msg := &bytes.Buffer{}
|
||||
fmt.Fprint(msg, "document symbols failed")
|
||||
if i >= 0 {
|
||||
|
|
@ -799,11 +798,11 @@ func summarizeSymbols(i int, want []source.Symbol, got []source.Symbol, reason s
|
|||
fmt.Fprintf(msg, reason, args...)
|
||||
fmt.Fprint(msg, ":\nexpected:\n")
|
||||
for _, s := range want {
|
||||
fmt.Fprintf(msg, " %v %v %v\n", s.Name, s.Kind, s.SelectionSpan)
|
||||
fmt.Fprintf(msg, " %v %v %v\n", s.Name, s.Kind, s.SelectionRange)
|
||||
}
|
||||
fmt.Fprintf(msg, "got:\n")
|
||||
for _, s := range got {
|
||||
fmt.Fprintf(msg, " %v %v %v\n", s.Name, s.Kind, s.SelectionSpan)
|
||||
fmt.Fprintf(msg, " %v %v %v\n", s.Name, s.Kind, s.SelectionRange)
|
||||
}
|
||||
return msg.String()
|
||||
}
|
||||
|
|
@ -815,7 +814,7 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", spn, err)
|
||||
}
|
||||
rng, err := spanToRange(r.data, spn)
|
||||
_, rng, err := spanToRange(r.data, spn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -863,15 +862,15 @@ func (r *runner) Link(t *testing.T, data tests.Links) {
|
|||
// This is a pure LSP feature, no source level functionality to be tested.
|
||||
}
|
||||
|
||||
func spanToRange(data *tests.Data, span span.Span) (protocol.Range, error) {
|
||||
func spanToRange(data *tests.Data, span span.Span) (*protocol.ColumnMapper, protocol.Range, error) {
|
||||
contents, err := data.Exported.FileContents(span.URI().Filename())
|
||||
if err != nil {
|
||||
return protocol.Range{}, err
|
||||
return nil, protocol.Range{}, err
|
||||
}
|
||||
m := protocol.NewColumnMapper(span.URI(), span.URI().Filename(), data.Exported.ExpectFileSet, nil, contents)
|
||||
srcRng, err := m.Range(span)
|
||||
if err != nil {
|
||||
return protocol.Range{}, err
|
||||
return nil, protocol.Range{}, err
|
||||
}
|
||||
return srcRng, nil
|
||||
return m, srcRng, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,44 +8,16 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/span"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/telemetry/trace"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type SymbolKind int
|
||||
|
||||
const (
|
||||
PackageSymbol SymbolKind = iota
|
||||
StructSymbol
|
||||
VariableSymbol
|
||||
ConstantSymbol
|
||||
FunctionSymbol
|
||||
MethodSymbol
|
||||
InterfaceSymbol
|
||||
NumberSymbol
|
||||
StringSymbol
|
||||
BooleanSymbol
|
||||
FieldSymbol
|
||||
)
|
||||
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Detail string
|
||||
Span span.Span
|
||||
SelectionSpan span.Span
|
||||
Kind SymbolKind
|
||||
Children []Symbol
|
||||
}
|
||||
|
||||
func DocumentSymbols(ctx context.Context, f GoFile) ([]Symbol, error) {
|
||||
func DocumentSymbols(ctx context.Context, view View, f GoFile) ([]protocol.DocumentSymbol, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.DocumentSymbols")
|
||||
defer done()
|
||||
|
||||
fset := f.FileSet()
|
||||
file, err := f.GetAST(ctx, ParseFull)
|
||||
if file == nil {
|
||||
return nil, err
|
||||
|
|
@ -57,14 +29,14 @@ func DocumentSymbols(ctx context.Context, f GoFile) ([]Symbol, error) {
|
|||
info := pkg.GetTypesInfo()
|
||||
q := qualifier(file, pkg.GetTypes(), info)
|
||||
|
||||
methodsToReceiver := make(map[types.Type][]Symbol)
|
||||
methodsToReceiver := make(map[types.Type][]protocol.DocumentSymbol)
|
||||
symbolsToReceiver := make(map[types.Type]int)
|
||||
var symbols []Symbol
|
||||
var symbols []protocol.DocumentSymbol
|
||||
for _, decl := range file.Decls {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if obj := info.ObjectOf(decl.Name); obj != nil {
|
||||
if fs := funcSymbol(decl, obj, fset, q); fs.Kind == MethodSymbol {
|
||||
if fs := funcSymbol(ctx, view, decl, obj, q); fs.Kind == protocol.Method {
|
||||
// Store methods separately, as we want them to appear as children
|
||||
// of the corresponding type (which we may not have seen yet).
|
||||
rtype := obj.Type().(*types.Signature).Recv().Type()
|
||||
|
|
@ -78,14 +50,14 @@ func DocumentSymbols(ctx context.Context, f GoFile) ([]Symbol, error) {
|
|||
switch spec := spec.(type) {
|
||||
case *ast.TypeSpec:
|
||||
if obj := info.ObjectOf(spec.Name); obj != nil {
|
||||
ts := typeSymbol(info, spec, obj, fset, q)
|
||||
ts := typeSymbol(ctx, view, info, spec, obj, q)
|
||||
symbols = append(symbols, ts)
|
||||
symbolsToReceiver[obj.Type()] = len(symbols) - 1
|
||||
}
|
||||
case *ast.ValueSpec:
|
||||
for _, name := range spec.Names {
|
||||
if obj := info.ObjectOf(name); obj != nil {
|
||||
symbols = append(symbols, varSymbol(decl, name, obj, fset, q))
|
||||
symbols = append(symbols, varSymbol(ctx, view, decl, name, obj, q))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -109,21 +81,21 @@ func DocumentSymbols(ctx context.Context, f GoFile) ([]Symbol, error) {
|
|||
return symbols, nil
|
||||
}
|
||||
|
||||
func funcSymbol(decl *ast.FuncDecl, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
|
||||
s := Symbol{
|
||||
func funcSymbol(ctx context.Context, view View, decl *ast.FuncDecl, obj types.Object, q types.Qualifier) protocol.DocumentSymbol {
|
||||
s := protocol.DocumentSymbol{
|
||||
Name: obj.Name(),
|
||||
Kind: FunctionSymbol,
|
||||
Kind: protocol.Function,
|
||||
}
|
||||
if span, err := nodeSpan(decl, fset); err == nil {
|
||||
s.Span = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, decl); err == nil {
|
||||
s.Range = span
|
||||
}
|
||||
if span, err := nodeSpan(decl.Name, fset); err == nil {
|
||||
s.SelectionSpan = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, decl.Name); err == nil {
|
||||
s.SelectionRange = span
|
||||
}
|
||||
sig, _ := obj.Type().(*types.Signature)
|
||||
if sig != nil {
|
||||
if sig.Recv() != nil {
|
||||
s.Kind = MethodSymbol
|
||||
s.Kind = protocol.Method
|
||||
}
|
||||
s.Detail += "("
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
|
|
@ -142,16 +114,16 @@ func funcSymbol(decl *ast.FuncDecl, obj types.Object, fset *token.FileSet, q typ
|
|||
return s
|
||||
}
|
||||
|
||||
func setKind(s *Symbol, typ types.Type, q types.Qualifier) {
|
||||
func setKind(s *protocol.DocumentSymbol, typ types.Type, q types.Qualifier) {
|
||||
switch typ := typ.Underlying().(type) {
|
||||
case *types.Interface:
|
||||
s.Kind = InterfaceSymbol
|
||||
s.Kind = protocol.Interface
|
||||
case *types.Struct:
|
||||
s.Kind = StructSymbol
|
||||
s.Kind = protocol.Struct
|
||||
case *types.Signature:
|
||||
s.Kind = FunctionSymbol
|
||||
s.Kind = protocol.Function
|
||||
if typ.Recv() != nil {
|
||||
s.Kind = MethodSymbol
|
||||
s.Kind = protocol.Method
|
||||
}
|
||||
case *types.Named:
|
||||
setKind(s, typ.Underlying(), q)
|
||||
|
|
@ -159,45 +131,48 @@ func setKind(s *Symbol, typ types.Type, q types.Qualifier) {
|
|||
i := typ.Info()
|
||||
switch {
|
||||
case i&types.IsNumeric != 0:
|
||||
s.Kind = NumberSymbol
|
||||
s.Kind = protocol.Number
|
||||
case i&types.IsBoolean != 0:
|
||||
s.Kind = BooleanSymbol
|
||||
s.Kind = protocol.Boolean
|
||||
case i&types.IsString != 0:
|
||||
s.Kind = StringSymbol
|
||||
s.Kind = protocol.String
|
||||
}
|
||||
default:
|
||||
s.Kind = VariableSymbol
|
||||
s.Kind = protocol.Variable
|
||||
}
|
||||
}
|
||||
|
||||
func typeSymbol(info *types.Info, spec *ast.TypeSpec, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
|
||||
s := Symbol{Name: obj.Name()}
|
||||
func typeSymbol(ctx context.Context, view View, info *types.Info, spec *ast.TypeSpec, obj types.Object, q types.Qualifier) protocol.DocumentSymbol {
|
||||
s := protocol.DocumentSymbol{
|
||||
Name: obj.Name(),
|
||||
}
|
||||
s.Detail, _ = formatType(obj.Type(), q)
|
||||
setKind(&s, obj.Type(), q)
|
||||
|
||||
if span, err := nodeSpan(spec, fset); err == nil {
|
||||
s.Span = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, spec); err == nil {
|
||||
s.Range = span
|
||||
}
|
||||
if span, err := nodeSpan(spec.Name, fset); err == nil {
|
||||
s.SelectionSpan = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, spec.Name); err == nil {
|
||||
s.SelectionRange = span
|
||||
}
|
||||
|
||||
t, objIsStruct := obj.Type().Underlying().(*types.Struct)
|
||||
st, specIsStruct := spec.Type.(*ast.StructType)
|
||||
if objIsStruct && specIsStruct {
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
f := t.Field(i)
|
||||
child := Symbol{Name: f.Name(), Kind: FieldSymbol}
|
||||
child := protocol.DocumentSymbol{
|
||||
Name: f.Name(),
|
||||
Kind: protocol.Field,
|
||||
}
|
||||
child.Detail, _ = formatType(f.Type(), q)
|
||||
|
||||
spanNode, selectionNode := nodesForStructField(i, st)
|
||||
if span, err := nodeSpan(spanNode, fset); err == nil {
|
||||
child.Span = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, spanNode); err == nil {
|
||||
child.Range = span
|
||||
}
|
||||
if span, err := nodeSpan(selectionNode, fset); err == nil {
|
||||
child.SelectionSpan = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, selectionNode); err == nil {
|
||||
child.SelectionRange = span
|
||||
}
|
||||
|
||||
s.Children = append(s.Children, child)
|
||||
}
|
||||
}
|
||||
|
|
@ -207,9 +182,9 @@ func typeSymbol(info *types.Info, spec *ast.TypeSpec, obj types.Object, fset *to
|
|||
if objIsInterface && specIsInterface {
|
||||
for i := 0; i < ti.NumExplicitMethods(); i++ {
|
||||
method := ti.ExplicitMethod(i)
|
||||
child := Symbol{
|
||||
child := protocol.DocumentSymbol{
|
||||
Name: method.Name(),
|
||||
Kind: MethodSymbol,
|
||||
Kind: protocol.Method,
|
||||
}
|
||||
|
||||
var spanNode, selectionNode ast.Node
|
||||
|
|
@ -222,11 +197,11 @@ func typeSymbol(info *types.Info, spec *ast.TypeSpec, obj types.Object, fset *to
|
|||
}
|
||||
}
|
||||
}
|
||||
if span, err := nodeSpan(spanNode, fset); err == nil {
|
||||
child.Span = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, spanNode); err == nil {
|
||||
child.Range = span
|
||||
}
|
||||
if span, err := nodeSpan(selectionNode, fset); err == nil {
|
||||
child.SelectionSpan = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, selectionNode); err == nil {
|
||||
child.SelectionRange = span
|
||||
}
|
||||
s.Children = append(s.Children, child)
|
||||
}
|
||||
|
|
@ -238,7 +213,9 @@ func typeSymbol(info *types.Info, spec *ast.TypeSpec, obj types.Object, fset *to
|
|||
continue
|
||||
}
|
||||
|
||||
child := Symbol{Name: types.TypeString(embedded, q)}
|
||||
child := protocol.DocumentSymbol{
|
||||
Name: types.TypeString(embedded, q),
|
||||
}
|
||||
setKind(&child, embedded, q)
|
||||
var spanNode, selectionNode ast.Node
|
||||
Embeddeds:
|
||||
|
|
@ -252,12 +229,11 @@ func typeSymbol(info *types.Info, spec *ast.TypeSpec, obj types.Object, fset *to
|
|||
break Embeddeds
|
||||
}
|
||||
}
|
||||
|
||||
if span, err := nodeSpan(spanNode, fset); err == nil {
|
||||
child.Span = span
|
||||
if rng, err := nodeToProtocolRange(ctx, view, spanNode); err == nil {
|
||||
child.Range = rng
|
||||
}
|
||||
if span, err := nodeSpan(selectionNode, fset); err == nil {
|
||||
child.SelectionSpan = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, selectionNode); err == nil {
|
||||
child.SelectionRange = span
|
||||
}
|
||||
s.Children = append(s.Children, child)
|
||||
}
|
||||
|
|
@ -285,28 +261,20 @@ func nodesForStructField(i int, st *ast.StructType) (span, selection ast.Node) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func varSymbol(decl ast.Node, name *ast.Ident, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
|
||||
s := Symbol{
|
||||
func varSymbol(ctx context.Context, view View, decl ast.Node, name *ast.Ident, obj types.Object, q types.Qualifier) protocol.DocumentSymbol {
|
||||
s := protocol.DocumentSymbol{
|
||||
Name: obj.Name(),
|
||||
Kind: VariableSymbol,
|
||||
Kind: protocol.Variable,
|
||||
}
|
||||
if _, ok := obj.(*types.Const); ok {
|
||||
s.Kind = ConstantSymbol
|
||||
s.Kind = protocol.Constant
|
||||
}
|
||||
if span, err := nodeSpan(decl, fset); err == nil {
|
||||
s.Span = span
|
||||
if rng, err := nodeToProtocolRange(ctx, view, decl); err == nil {
|
||||
s.Range = rng
|
||||
}
|
||||
if span, err := nodeSpan(name, fset); err == nil {
|
||||
s.SelectionSpan = span
|
||||
if span, err := nodeToProtocolRange(ctx, view, name); err == nil {
|
||||
s.SelectionRange = span
|
||||
}
|
||||
s.Detail = types.TypeString(obj.Type(), q)
|
||||
return s
|
||||
}
|
||||
|
||||
func nodeSpan(n ast.Node, fset *token.FileSet) (span.Span, error) {
|
||||
if n == nil {
|
||||
return span.Span{}, errors.New("no span for nil node")
|
||||
}
|
||||
r := span.NewRange(fset, n.Pos(), n.End())
|
||||
return r.Span()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,6 +158,59 @@ func IsGenerated(ctx context.Context, view View, uri span.URI) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func nodeToProtocolRange(ctx context.Context, view View, n ast.Node) (protocol.Range, error) {
|
||||
mrng, err := nodeToMappedRange(ctx, view, n)
|
||||
if err != nil {
|
||||
return protocol.Range{}, err
|
||||
}
|
||||
return mrng.Range()
|
||||
}
|
||||
|
||||
func objToMappedRange(ctx context.Context, view View, obj types.Object) (mappedRange, error) {
|
||||
if pkgName, ok := obj.(*types.PkgName); ok {
|
||||
// An imported Go package has a package-local, unqualified name.
|
||||
// When the name matches the imported package name, there is no
|
||||
// identifier in the import spec with the local package name.
|
||||
//
|
||||
// For example:
|
||||
// import "go/ast" // name "ast" matches package name
|
||||
// import a "go/ast" // name "a" does not match package name
|
||||
//
|
||||
// When the identifier does not appear in the source, have the range
|
||||
// of the object be the point at the beginning of the declaration.
|
||||
if pkgName.Imported().Name() == pkgName.Name() {
|
||||
return nameToMappedRange(ctx, view, obj.Pos(), "")
|
||||
}
|
||||
}
|
||||
return nameToMappedRange(ctx, view, obj.Pos(), obj.Name())
|
||||
}
|
||||
|
||||
func nameToMappedRange(ctx context.Context, view View, pos token.Pos, name string) (mappedRange, error) {
|
||||
return posToRange(ctx, view, pos, pos+token.Pos(len(name)))
|
||||
}
|
||||
|
||||
func nodeToMappedRange(ctx context.Context, view View, n ast.Node) (mappedRange, error) {
|
||||
return posToRange(ctx, view, n.Pos(), n.End())
|
||||
}
|
||||
|
||||
func posToRange(ctx context.Context, view View, pos, end token.Pos) (mappedRange, error) {
|
||||
if !pos.IsValid() {
|
||||
return mappedRange{}, errors.Errorf("invalid position for %v", pos)
|
||||
}
|
||||
if !end.IsValid() {
|
||||
return mappedRange{}, errors.Errorf("invalid position for %v", end)
|
||||
}
|
||||
posn := view.Session().Cache().FileSet().Position(pos)
|
||||
_, m, err := cachedFileToMapper(ctx, view, span.FileURI(posn.Filename))
|
||||
if err != nil {
|
||||
return mappedRange{}, err
|
||||
}
|
||||
return mappedRange{
|
||||
m: m,
|
||||
spanRange: span.NewRange(view.Session().Cache().FileSet(), pos, end),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Matches cgo generated comment as well as the proposed standard:
|
||||
// https://golang.org/s/generatedcode
|
||||
var generatedRx = regexp.MustCompile(`// .*DO NOT EDIT\.?`)
|
||||
|
|
|
|||
|
|
@ -16,68 +16,12 @@ import (
|
|||
func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "lsp.Server.documentSymbol")
|
||||
defer done()
|
||||
|
||||
uri := span.NewURI(params.TextDocument.URI)
|
||||
view := s.session.ViewOf(uri)
|
||||
f, err := getGoFile(ctx, view, uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := getMapper(ctx, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
symbols, err := source.DocumentSymbols(ctx, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toProtocolDocumentSymbols(m, symbols), nil
|
||||
}
|
||||
|
||||
func toProtocolDocumentSymbols(m *protocol.ColumnMapper, symbols []source.Symbol) []protocol.DocumentSymbol {
|
||||
result := make([]protocol.DocumentSymbol, 0, len(symbols))
|
||||
for _, s := range symbols {
|
||||
ps := protocol.DocumentSymbol{
|
||||
Name: s.Name,
|
||||
Kind: toProtocolSymbolKind(s.Kind),
|
||||
Detail: s.Detail,
|
||||
Children: toProtocolDocumentSymbols(m, s.Children),
|
||||
}
|
||||
if r, err := m.Range(s.Span); err == nil {
|
||||
ps.Range = r
|
||||
}
|
||||
if r, err := m.Range(s.SelectionSpan); err == nil {
|
||||
ps.SelectionRange = r
|
||||
}
|
||||
result = append(result, ps)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func toProtocolSymbolKind(kind source.SymbolKind) protocol.SymbolKind {
|
||||
switch kind {
|
||||
case source.StructSymbol:
|
||||
return protocol.Struct
|
||||
case source.PackageSymbol:
|
||||
return protocol.Package
|
||||
case source.VariableSymbol:
|
||||
return protocol.Variable
|
||||
case source.ConstantSymbol:
|
||||
return protocol.Constant
|
||||
case source.FunctionSymbol:
|
||||
return protocol.Function
|
||||
case source.MethodSymbol:
|
||||
return protocol.Method
|
||||
case source.InterfaceSymbol:
|
||||
return protocol.Interface
|
||||
case source.NumberSymbol:
|
||||
return protocol.Number
|
||||
case source.StringSymbol:
|
||||
return protocol.String
|
||||
case source.BooleanSymbol:
|
||||
return protocol.Boolean
|
||||
case source.FieldSymbol:
|
||||
return protocol.Field
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
return source.DocumentSymbols(ctx, view, f)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ type Highlights map[string][]span.Span
|
|||
type References map[span.Span][]span.Span
|
||||
type Renames map[span.Span]string
|
||||
type PrepareRenames map[span.Span]*source.PrepareItem
|
||||
type Symbols map[span.URI][]source.Symbol
|
||||
type SymbolsChildren map[string][]source.Symbol
|
||||
type Symbols map[span.URI][]protocol.DocumentSymbol
|
||||
type SymbolsChildren map[string][]protocol.DocumentSymbol
|
||||
type Signatures map[span.Span]*source.SignatureInformation
|
||||
type Links map[span.URI][]Link
|
||||
|
||||
|
|
@ -642,10 +642,19 @@ func (data *Data) collectPrepareRenames(src span.Span, rng span.Range, placehold
|
|||
}
|
||||
|
||||
func (data *Data) collectSymbols(name string, spn span.Span, kind string, parentName string) {
|
||||
sym := source.Symbol{
|
||||
Name: name,
|
||||
Kind: source.ParseSymbolKind(kind),
|
||||
SelectionSpan: spn,
|
||||
contents, err := data.Exported.FileContents(spn.URI().Filename())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
m := protocol.NewColumnMapper(spn.URI(), spn.URI().Filename(), data.Exported.ExpectFileSet, nil, contents)
|
||||
rng, err := m.Range(spn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sym := protocol.DocumentSymbol{
|
||||
Name: name,
|
||||
Kind: protocol.ParseSymbolKind(kind),
|
||||
SelectionRange: rng,
|
||||
}
|
||||
if parentName == "" {
|
||||
data.Symbols[spn.URI()] = append(data.Symbols[spn.URI()], sym)
|
||||
|
|
|
|||
Loading…
Reference in New Issue