github.com/april1989/origin-go-tools@v0.0.32/internal/lsp/source/symbols.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package source 6 7 import ( 8 "context" 9 "fmt" 10 "go/ast" 11 "go/types" 12 13 "github.com/april1989/origin-go-tools/internal/event" 14 "github.com/april1989/origin-go-tools/internal/lsp/protocol" 15 errors "golang.org/x/xerrors" 16 ) 17 18 func DocumentSymbols(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.DocumentSymbol, error) { 19 ctx, done := event.Start(ctx, "source.DocumentSymbols") 20 defer done() 21 22 pkg, pgf, err := getParsedFile(ctx, snapshot, fh, NarrowestPackage) 23 if err != nil { 24 return nil, errors.Errorf("getting file for DocumentSymbols: %w", err) 25 } 26 27 info := pkg.GetTypesInfo() 28 q := qualifier(pgf.File, pkg.GetTypes(), info) 29 30 symbolsToReceiver := make(map[types.Type]int) 31 var symbols []protocol.DocumentSymbol 32 for _, decl := range pgf.File.Decls { 33 switch decl := decl.(type) { 34 case *ast.FuncDecl: 35 if obj := info.ObjectOf(decl.Name); obj != nil { 36 fs, err := funcSymbol(snapshot, pkg, decl, obj, q) 37 if err != nil { 38 return nil, err 39 } 40 // If function is a method, prepend the type of the method. 41 if fs.Kind == protocol.Method { 42 rtype := obj.Type().(*types.Signature).Recv().Type() 43 fs.Name = fmt.Sprintf("(%s).%s", types.TypeString(rtype, q), fs.Name) 44 } 45 symbols = append(symbols, fs) 46 } 47 case *ast.GenDecl: 48 for _, spec := range decl.Specs { 49 switch spec := spec.(type) { 50 case *ast.TypeSpec: 51 if obj := info.ObjectOf(spec.Name); obj != nil { 52 ts, err := typeSymbol(snapshot, pkg, info, spec, obj, q) 53 if err != nil { 54 return nil, err 55 } 56 symbols = append(symbols, ts) 57 symbolsToReceiver[obj.Type()] = len(symbols) - 1 58 } 59 case *ast.ValueSpec: 60 for _, name := range spec.Names { 61 if obj := info.ObjectOf(name); obj != nil { 62 vs, err := varSymbol(snapshot, pkg, decl, name, obj, q) 63 if err != nil { 64 return nil, err 65 } 66 symbols = append(symbols, vs) 67 } 68 } 69 } 70 } 71 } 72 } 73 return symbols, nil 74 } 75 76 func funcSymbol(snapshot Snapshot, pkg Package, decl *ast.FuncDecl, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) { 77 s := protocol.DocumentSymbol{ 78 Name: obj.Name(), 79 Kind: protocol.Function, 80 } 81 var err error 82 s.Range, err = nodeToProtocolRange(snapshot, pkg, decl) 83 if err != nil { 84 return protocol.DocumentSymbol{}, err 85 } 86 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, decl.Name) 87 if err != nil { 88 return protocol.DocumentSymbol{}, err 89 } 90 sig, _ := obj.Type().(*types.Signature) 91 if sig != nil { 92 if sig.Recv() != nil { 93 s.Kind = protocol.Method 94 } 95 s.Detail += "(" 96 for i := 0; i < sig.Params().Len(); i++ { 97 if i > 0 { 98 s.Detail += ", " 99 } 100 param := sig.Params().At(i) 101 label := types.TypeString(param.Type(), q) 102 if param.Name() != "" { 103 label = fmt.Sprintf("%s %s", param.Name(), label) 104 } 105 s.Detail += label 106 } 107 s.Detail += ")" 108 } 109 return s, nil 110 } 111 112 func typeSymbol(snapshot Snapshot, pkg Package, info *types.Info, spec *ast.TypeSpec, obj types.Object, qf types.Qualifier) (protocol.DocumentSymbol, error) { 113 s := protocol.DocumentSymbol{ 114 Name: obj.Name(), 115 } 116 s.Detail, _ = formatType(obj.Type(), qf) 117 s.Kind = typeToKind(obj.Type()) 118 119 var err error 120 s.Range, err = nodeToProtocolRange(snapshot, pkg, spec) 121 if err != nil { 122 return protocol.DocumentSymbol{}, err 123 } 124 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, spec.Name) 125 if err != nil { 126 return protocol.DocumentSymbol{}, err 127 } 128 t, objIsStruct := obj.Type().Underlying().(*types.Struct) 129 st, specIsStruct := spec.Type.(*ast.StructType) 130 if objIsStruct && specIsStruct { 131 for i := 0; i < t.NumFields(); i++ { 132 f := t.Field(i) 133 child := protocol.DocumentSymbol{ 134 Name: f.Name(), 135 Kind: protocol.Field, 136 } 137 child.Detail, _ = formatType(f.Type(), qf) 138 139 spanNode, selectionNode := nodesForStructField(i, st) 140 if span, err := nodeToProtocolRange(snapshot, pkg, spanNode); err == nil { 141 child.Range = span 142 } 143 if span, err := nodeToProtocolRange(snapshot, pkg, selectionNode); err == nil { 144 child.SelectionRange = span 145 } 146 s.Children = append(s.Children, child) 147 } 148 } 149 150 ti, objIsInterface := obj.Type().Underlying().(*types.Interface) 151 ai, specIsInterface := spec.Type.(*ast.InterfaceType) 152 if objIsInterface && specIsInterface { 153 for i := 0; i < ti.NumExplicitMethods(); i++ { 154 method := ti.ExplicitMethod(i) 155 child := protocol.DocumentSymbol{ 156 Name: method.Name(), 157 Kind: protocol.Method, 158 } 159 160 var spanNode, selectionNode ast.Node 161 Methods: 162 for _, f := range ai.Methods.List { 163 for _, id := range f.Names { 164 if id.Name == method.Name() { 165 spanNode, selectionNode = f, id 166 break Methods 167 } 168 } 169 } 170 child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode) 171 if err != nil { 172 return protocol.DocumentSymbol{}, err 173 } 174 child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode) 175 if err != nil { 176 return protocol.DocumentSymbol{}, err 177 } 178 s.Children = append(s.Children, child) 179 } 180 181 for i := 0; i < ti.NumEmbeddeds(); i++ { 182 embedded := ti.EmbeddedType(i) 183 nt, isNamed := embedded.(*types.Named) 184 if !isNamed { 185 continue 186 } 187 188 child := protocol.DocumentSymbol{ 189 Name: types.TypeString(embedded, qf), 190 } 191 child.Kind = typeToKind(embedded) 192 var spanNode, selectionNode ast.Node 193 Embeddeds: 194 for _, f := range ai.Methods.List { 195 if len(f.Names) > 0 { 196 continue 197 } 198 199 if t := info.TypeOf(f.Type); types.Identical(nt, t) { 200 spanNode, selectionNode = f, f.Type 201 break Embeddeds 202 } 203 } 204 child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode) 205 if err != nil { 206 return protocol.DocumentSymbol{}, err 207 } 208 child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode) 209 if err != nil { 210 return protocol.DocumentSymbol{}, err 211 } 212 s.Children = append(s.Children, child) 213 } 214 } 215 return s, nil 216 } 217 218 func nodesForStructField(i int, st *ast.StructType) (span, selection ast.Node) { 219 j := 0 220 for _, field := range st.Fields.List { 221 if len(field.Names) == 0 { 222 if i == j { 223 return field, field.Type 224 } 225 j++ 226 continue 227 } 228 for _, name := range field.Names { 229 if i == j { 230 return field, name 231 } 232 j++ 233 } 234 } 235 return nil, nil 236 } 237 238 func varSymbol(snapshot Snapshot, pkg Package, decl ast.Node, name *ast.Ident, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) { 239 s := protocol.DocumentSymbol{ 240 Name: obj.Name(), 241 Kind: protocol.Variable, 242 } 243 if _, ok := obj.(*types.Const); ok { 244 s.Kind = protocol.Constant 245 } 246 var err error 247 s.Range, err = nodeToProtocolRange(snapshot, pkg, decl) 248 if err != nil { 249 return protocol.DocumentSymbol{}, err 250 } 251 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, name) 252 if err != nil { 253 return protocol.DocumentSymbol{}, err 254 } 255 s.Detail = types.TypeString(obj.Type(), q) 256 return s, nil 257 }