mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
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>
132 lines
3.0 KiB
Go
132 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 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()
|
|
}
|