.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / source / symbols.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/source/symbols.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/source/symbols.go
new file mode 100644 (file)
index 0000000..16fb222
--- /dev/null
@@ -0,0 +1,266 @@
+// 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
+}