1
0
mirror of https://github.com/golang/go synced 2024-11-19 00:34:40 -07:00
go/internal/lsp/source/symbols.go
Rebecca Stambler 41a94eb788 internal/lsp: add back distinction between var and const symbols
Change-Id: I59f87d4430c93438804cea7cc56a80f12bb42a00
Reviewed-on: https://go-review.googlesource.com/c/tools/+/169441
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-03-27 01:06:29 +00:00

135 lines
3.0 KiB
Go

// Copyright 2019 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"
"fmt"
"go/ast"
"go/token"
"go/types"
"golang.org/x/tools/internal/span"
)
type SymbolKind int
const (
PackageSymbol SymbolKind = iota
StructSymbol
VariableSymbol
ConstantSymbol
FunctionSymbol
MethodSymbol
)
type Symbol struct {
Name string
Detail string
Span span.Span
SelectionSpan span.Span
Kind SymbolKind
Children []Symbol
}
func DocumentSymbols(ctx context.Context, f File) []Symbol {
fset := f.GetFileSet(ctx)
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, info.ObjectOf(decl.Name), fset, q))
case *ast.GenDecl:
for _, spec := range decl.Specs {
switch spec := spec.(type) {
case *ast.TypeSpec:
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, info.ObjectOf(name), fset, q))
}
}
}
}
}
return symbols
}
func funcSymbol(decl *ast.FuncDecl, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
s := Symbol{
Name: obj.Name(),
Kind: FunctionSymbol,
}
if span, err := nodeSpan(decl, fset); err == nil {
s.Span = span
}
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 typeSymbol(spec *ast.TypeSpec, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
s := Symbol{
Name: obj.Name(),
Kind: StructSymbol,
}
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.Node, name *ast.Ident, obj types.Object, fset *token.FileSet, q types.Qualifier) Symbol {
s := Symbol{
Name: obj.Name(),
Kind: VariableSymbol,
}
if _, ok := obj.(*types.Const); ok {
s.Kind = ConstantSymbol
}
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
}
func nodeSpan(n ast.Node, fset *token.FileSet) (span.Span, error) {
r := span.NewRange(fset, n.Pos(), n.End())
return r.Span()
}