1
0
mirror of https://github.com/golang/go synced 2024-11-18 11:04:42 -07:00

internal/lsp: group document symbols and add more detail

This change uses go/types information to get the types for the
different symbols. It also groups the symbols according to their kinds,
though this doesn't seem to be reflected in the actual VSCode UI...

Updates golang/go#30915

Change-Id: I2caefe01f9834aaad6b9e81cd391d461405ef725
Reviewed-on: https://go-review.googlesource.com/c/tools/+/169438
Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
Rebecca Stambler 2019-03-26 17:38:40 -04:00
parent 3ad05305c9
commit c02eab13f0
2 changed files with 59 additions and 56 deletions

View File

@ -5,11 +5,11 @@
package source
import (
"bytes"
"context"
"fmt"
"go/ast"
"go/format"
"go/token"
"go/types"
"golang.org/x/tools/internal/span"
)
@ -26,31 +26,34 @@ const (
)
type Symbol struct {
Name string
Detail string
Span span.Span
Kind SymbolKind
Children []Symbol
Name string
Detail string
Span span.Span
SelectionSpan span.Span
Kind SymbolKind
Children []Symbol
}
func DocumentSymbols(ctx context.Context, f File) []Symbol {
var symbols []Symbol
fset := f.GetFileSet(ctx)
astFile := f.GetAST(ctx)
for _, decl := range astFile.Decls {
file := f.GetAST(ctx)
pkg := f.GetPackage(ctx)
info := pkg.GetTypesInfo()
q := qualifier(file, pkg.GetTypes(), info)
var symbols []Symbol
for _, decl := range file.Decls {
switch decl := decl.(type) {
case *ast.FuncDecl:
symbols = append(symbols, funcSymbol(decl, fset))
symbols = append(symbols, funcSymbol(decl, info.ObjectOf(decl.Name), fset, q))
case *ast.GenDecl:
for _, spec := range decl.Specs {
switch spec := spec.(type) {
case *ast.ImportSpec:
symbols = append(symbols, importSymbol(spec, fset))
case *ast.TypeSpec:
symbols = append(symbols, typeSymbol(spec, fset))
symbols = append(symbols, typeSymbol(spec, info.ObjectOf(spec.Name), fset, q))
case *ast.ValueSpec:
for _, name := range spec.Names {
symbols = append(symbols, varSymbol(decl, name, fset))
symbols = append(symbols, varSymbol(decl, name, info.ObjectOf(name), fset, q))
}
}
}
@ -59,67 +62,66 @@ func DocumentSymbols(ctx context.Context, f File) []Symbol {
return symbols
}
func funcSymbol(decl *ast.FuncDecl, fset *token.FileSet) Symbol {
func funcSymbol(decl *ast.FuncDecl, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
s := Symbol{
Name: decl.Name.String(),
Name: obj.Name(),
Kind: FunctionSymbol,
}
if decl.Recv != nil {
s.Kind = MethodSymbol
}
span, err := nodeSpan(decl, fset)
if err == nil {
if span, err := nodeSpan(decl, fset); err == nil {
s.Span = span
}
buf := &bytes.Buffer{}
if err := format.Node(buf, fset, decl); err == nil {
s.Detail = buf.String()
if span, err := nodeSpan(decl.Name, fset); err == nil {
s.SelectionSpan = span
}
sig, _ := obj.Type().(*types.Signature)
if sig != nil {
if sig.Recv() != nil {
s.Kind = MethodSymbol
}
s.Detail += "("
for i := 0; i < sig.Params().Len(); i++ {
if i > 0 {
s.Detail += ", "
}
param := sig.Params().At(i)
label := types.TypeString(param.Type(), q)
if param.Name() != "" {
label = fmt.Sprintf("%s %s", param.Name(), label)
}
s.Detail += label
}
s.Detail += ")"
}
return s
}
func importSymbol(spec *ast.ImportSpec, fset *token.FileSet) Symbol {
func typeSymbol(spec *ast.TypeSpec, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
s := Symbol{
Name: spec.Path.Value,
Kind: PackageSymbol,
Detail: "import " + spec.Path.Value,
}
span, err := nodeSpan(spec, fset)
if err == nil {
s.Span = span
}
return s
}
func typeSymbol(spec *ast.TypeSpec, fset *token.FileSet) Symbol {
s := Symbol{
Name: spec.Name.String(),
Name: obj.Name(),
Kind: StructSymbol,
}
span, err := nodeSpan(spec, fset)
if err == nil {
if span, err := nodeSpan(spec, fset); err == nil {
s.Span = span
}
if span, err := nodeSpan(spec.Name, fset); err == nil {
s.SelectionSpan = span
}
s.Detail, _ = formatType(obj.Type(), q)
return s
}
func varSymbol(decl *ast.GenDecl, name *ast.Ident, fset *token.FileSet) Symbol {
func varSymbol(decl ast.Node, name *ast.Ident, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
s := Symbol{
Name: name.Name,
Name: obj.Name(),
Kind: VariableSymbol,
}
if decl.Tok == token.CONST {
s.Kind = ConstantSymbol
}
span, err := nodeSpan(name, fset)
if err == nil {
if span, err := nodeSpan(decl, fset); err == nil {
s.Span = span
}
if span, err := nodeSpan(name, fset); err == nil {
s.SelectionSpan = span
}
s.Detail = types.TypeString(obj.Type(), q)
return s
}

View File

@ -5,9 +5,8 @@
package lsp
import (
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
)
func toProtocolDocumentSymbols(m *protocol.ColumnMapper, symbols []source.Symbol) []protocol.DocumentSymbol {
@ -21,6 +20,8 @@ func toProtocolDocumentSymbols(m *protocol.ColumnMapper, symbols []source.Symbol
}
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)