+++ /dev/null
-// 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/types"
-
- "golang.org/x/tools/internal/event"
- "golang.org/x/tools/internal/lsp/protocol"
- errors "golang.org/x/xerrors"
-)
-
-func DocumentSymbols(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.DocumentSymbol, error) {
- ctx, done := event.Start(ctx, "source.DocumentSymbols")
- defer done()
-
- pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
- if err != nil {
- return nil, errors.Errorf("getting file for DocumentSymbols: %w", err)
- }
-
- info := pkg.GetTypesInfo()
- q := Qualifier(pgf.File, pkg.GetTypes(), info)
-
- symbolsToReceiver := make(map[types.Type]int)
- var symbols []protocol.DocumentSymbol
- for _, decl := range pgf.File.Decls {
- switch decl := decl.(type) {
- case *ast.FuncDecl:
- if decl.Name.Name == "_" {
- continue
- }
- if obj := info.ObjectOf(decl.Name); obj != nil {
- fs, err := funcSymbol(snapshot, pkg, decl, obj, q)
- if err != nil {
- return nil, err
- }
- // If function is a method, prepend the type of the method.
- if fs.Kind == protocol.Method {
- rtype := obj.Type().(*types.Signature).Recv().Type()
- fs.Name = fmt.Sprintf("(%s).%s", types.TypeString(rtype, q), fs.Name)
- }
- symbols = append(symbols, fs)
- }
- case *ast.GenDecl:
- for _, spec := range decl.Specs {
- switch spec := spec.(type) {
- case *ast.TypeSpec:
- if spec.Name.Name == "_" {
- continue
- }
- if obj := info.ObjectOf(spec.Name); obj != nil {
- ts, err := typeSymbol(snapshot, pkg, info, spec, obj, q)
- if err != nil {
- return nil, err
- }
- symbols = append(symbols, ts)
- symbolsToReceiver[obj.Type()] = len(symbols) - 1
- }
- case *ast.ValueSpec:
- for _, name := range spec.Names {
- if name.Name == "_" {
- continue
- }
- if obj := info.ObjectOf(name); obj != nil {
- vs, err := varSymbol(snapshot, pkg, decl, name, obj, q)
- if err != nil {
- return nil, err
- }
- symbols = append(symbols, vs)
- }
- }
- }
- }
- }
- }
- return symbols, nil
-}
-
-func funcSymbol(snapshot Snapshot, pkg Package, decl *ast.FuncDecl, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) {
- s := protocol.DocumentSymbol{
- Name: obj.Name(),
- Kind: protocol.Function,
- }
- var err error
- s.Range, err = nodeToProtocolRange(snapshot, pkg, decl)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, decl.Name)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- sig, _ := obj.Type().(*types.Signature)
- if sig != nil {
- if sig.Recv() != nil {
- s.Kind = protocol.Method
- }
- 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, nil
-}
-
-func typeSymbol(snapshot Snapshot, pkg Package, info *types.Info, spec *ast.TypeSpec, obj types.Object, qf types.Qualifier) (protocol.DocumentSymbol, error) {
- s := protocol.DocumentSymbol{
- Name: obj.Name(),
- }
- s.Detail, _ = FormatType(obj.Type(), qf)
- s.Kind = typeToKind(obj.Type())
-
- var err error
- s.Range, err = nodeToProtocolRange(snapshot, pkg, spec)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, spec.Name)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- 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 := protocol.DocumentSymbol{
- Name: f.Name(),
- Kind: protocol.Field,
- }
- child.Detail, _ = FormatType(f.Type(), qf)
-
- spanNode, selectionNode := nodesForStructField(i, st)
- if span, err := nodeToProtocolRange(snapshot, pkg, spanNode); err == nil {
- child.Range = span
- }
- if span, err := nodeToProtocolRange(snapshot, pkg, selectionNode); err == nil {
- child.SelectionRange = span
- }
- s.Children = append(s.Children, child)
- }
- }
-
- ti, objIsInterface := obj.Type().Underlying().(*types.Interface)
- ai, specIsInterface := spec.Type.(*ast.InterfaceType)
- if objIsInterface && specIsInterface {
- for i := 0; i < ti.NumExplicitMethods(); i++ {
- method := ti.ExplicitMethod(i)
- child := protocol.DocumentSymbol{
- Name: method.Name(),
- Kind: protocol.Method,
- }
-
- var spanNode, selectionNode ast.Node
- Methods:
- for _, f := range ai.Methods.List {
- for _, id := range f.Names {
- if id.Name == method.Name() {
- spanNode, selectionNode = f, id
- break Methods
- }
- }
- }
- child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- s.Children = append(s.Children, child)
- }
-
- for i := 0; i < ti.NumEmbeddeds(); i++ {
- embedded := ti.EmbeddedType(i)
- nt, isNamed := embedded.(*types.Named)
- if !isNamed {
- continue
- }
-
- child := protocol.DocumentSymbol{
- Name: types.TypeString(embedded, qf),
- }
- child.Kind = typeToKind(embedded)
- var spanNode, selectionNode ast.Node
- Embeddeds:
- for _, f := range ai.Methods.List {
- if len(f.Names) > 0 {
- continue
- }
-
- if t := info.TypeOf(f.Type); types.Identical(nt, t) {
- spanNode, selectionNode = f, f.Type
- break Embeddeds
- }
- }
- child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- s.Children = append(s.Children, child)
- }
- }
- return s, nil
-}
-
-func nodesForStructField(i int, st *ast.StructType) (span, selection ast.Node) {
- j := 0
- for _, field := range st.Fields.List {
- if len(field.Names) == 0 {
- if i == j {
- return field, field.Type
- }
- j++
- continue
- }
- for _, name := range field.Names {
- if i == j {
- return field, name
- }
- j++
- }
- }
- return nil, nil
-}
-
-func varSymbol(snapshot Snapshot, pkg Package, decl ast.Node, name *ast.Ident, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) {
- s := protocol.DocumentSymbol{
- Name: obj.Name(),
- Kind: protocol.Variable,
- }
- if _, ok := obj.(*types.Const); ok {
- s.Kind = protocol.Constant
- }
- var err error
- s.Range, err = nodeToProtocolRange(snapshot, pkg, decl)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, name)
- if err != nil {
- return protocol.DocumentSymbol{}, err
- }
- s.Detail = types.TypeString(obj.Type(), q)
- return s, nil
-}