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:
parent
3ad05305c9
commit
c02eab13f0
|
@ -5,11 +5,11 @@
|
||||||
package source
|
package source
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/format"
|
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
@ -26,31 +26,34 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Symbol struct {
|
type Symbol struct {
|
||||||
Name string
|
Name string
|
||||||
Detail string
|
Detail string
|
||||||
Span span.Span
|
Span span.Span
|
||||||
Kind SymbolKind
|
SelectionSpan span.Span
|
||||||
Children []Symbol
|
Kind SymbolKind
|
||||||
|
Children []Symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
func DocumentSymbols(ctx context.Context, f File) []Symbol {
|
func DocumentSymbols(ctx context.Context, f File) []Symbol {
|
||||||
var symbols []Symbol
|
|
||||||
fset := f.GetFileSet(ctx)
|
fset := f.GetFileSet(ctx)
|
||||||
astFile := f.GetAST(ctx)
|
file := f.GetAST(ctx)
|
||||||
for _, decl := range astFile.Decls {
|
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) {
|
switch decl := decl.(type) {
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
symbols = append(symbols, funcSymbol(decl, fset))
|
symbols = append(symbols, funcSymbol(decl, info.ObjectOf(decl.Name), fset, q))
|
||||||
case *ast.GenDecl:
|
case *ast.GenDecl:
|
||||||
for _, spec := range decl.Specs {
|
for _, spec := range decl.Specs {
|
||||||
switch spec := spec.(type) {
|
switch spec := spec.(type) {
|
||||||
case *ast.ImportSpec:
|
|
||||||
symbols = append(symbols, importSymbol(spec, fset))
|
|
||||||
case *ast.TypeSpec:
|
case *ast.TypeSpec:
|
||||||
symbols = append(symbols, typeSymbol(spec, fset))
|
symbols = append(symbols, typeSymbol(spec, info.ObjectOf(spec.Name), fset, q))
|
||||||
case *ast.ValueSpec:
|
case *ast.ValueSpec:
|
||||||
for _, name := range spec.Names {
|
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
|
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{
|
s := Symbol{
|
||||||
Name: decl.Name.String(),
|
Name: obj.Name(),
|
||||||
Kind: FunctionSymbol,
|
Kind: FunctionSymbol,
|
||||||
}
|
}
|
||||||
|
if span, err := nodeSpan(decl, fset); err == nil {
|
||||||
if decl.Recv != nil {
|
|
||||||
s.Kind = MethodSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
span, err := nodeSpan(decl, fset)
|
|
||||||
if err == nil {
|
|
||||||
s.Span = span
|
s.Span = span
|
||||||
}
|
}
|
||||||
buf := &bytes.Buffer{}
|
if span, err := nodeSpan(decl.Name, fset); err == nil {
|
||||||
if err := format.Node(buf, fset, decl); err == nil {
|
s.SelectionSpan = span
|
||||||
s.Detail = buf.String()
|
}
|
||||||
|
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
|
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{
|
s := Symbol{
|
||||||
Name: spec.Path.Value,
|
Name: obj.Name(),
|
||||||
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(),
|
|
||||||
Kind: StructSymbol,
|
Kind: StructSymbol,
|
||||||
}
|
}
|
||||||
span, err := nodeSpan(spec, fset)
|
if span, err := nodeSpan(spec, fset); err == nil {
|
||||||
if err == nil {
|
|
||||||
s.Span = span
|
s.Span = span
|
||||||
}
|
}
|
||||||
|
if span, err := nodeSpan(spec.Name, fset); err == nil {
|
||||||
|
s.SelectionSpan = span
|
||||||
|
}
|
||||||
|
s.Detail, _ = formatType(obj.Type(), q)
|
||||||
return s
|
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{
|
s := Symbol{
|
||||||
Name: name.Name,
|
Name: obj.Name(),
|
||||||
Kind: VariableSymbol,
|
Kind: VariableSymbol,
|
||||||
}
|
}
|
||||||
|
if span, err := nodeSpan(decl, fset); err == nil {
|
||||||
if decl.Tok == token.CONST {
|
|
||||||
s.Kind = ConstantSymbol
|
|
||||||
}
|
|
||||||
|
|
||||||
span, err := nodeSpan(name, fset)
|
|
||||||
if err == nil {
|
|
||||||
s.Span = span
|
s.Span = span
|
||||||
}
|
}
|
||||||
|
if span, err := nodeSpan(name, fset); err == nil {
|
||||||
|
s.SelectionSpan = span
|
||||||
|
}
|
||||||
|
s.Detail = types.TypeString(obj.Type(), q)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
package lsp
|
package lsp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
|
||||||
|
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toProtocolDocumentSymbols(m *protocol.ColumnMapper, symbols []source.Symbol) []protocol.DocumentSymbol {
|
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 {
|
if r, err := m.Range(s.Span); err == nil {
|
||||||
ps.Range = r
|
ps.Range = r
|
||||||
|
}
|
||||||
|
if r, err := m.Range(s.SelectionSpan); err == nil {
|
||||||
ps.SelectionRange = r
|
ps.SelectionRange = r
|
||||||
}
|
}
|
||||||
result = append(result, ps)
|
result = append(result, ps)
|
||||||
|
|
Loading…
Reference in New Issue