github.com/v2fly/tools@v0.100.0/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/v2fly/tools/internal/event" 14 "github.com/v2fly/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 decl.Name.Name == "_" { 36 continue 37 } 38 if obj := info.ObjectOf(decl.Name); obj != nil { 39 fs, err := funcSymbol(snapshot, pkg, decl, obj, q) 40 if err != nil { 41 return nil, err 42 } 43 // If function is a method, prepend the type of the method. 44 if fs.Kind == protocol.Method { 45 rtype := obj.Type().(*types.Signature).Recv().Type() 46 fs.Name = fmt.Sprintf("(%s).%s", types.TypeString(rtype, q), fs.Name) 47 } 48 symbols = append(symbols, fs) 49 } 50 case *ast.GenDecl: 51 for _, spec := range decl.Specs { 52 switch spec := spec.(type) { 53 case *ast.TypeSpec: 54 if spec.Name.Name == "_" { 55 continue 56 } 57 if obj := info.ObjectOf(spec.Name); obj != nil { 58 ts, err := typeSymbol(snapshot, pkg, info, spec, obj, q) 59 if err != nil { 60 return nil, err 61 } 62 symbols = append(symbols, ts) 63 symbolsToReceiver[obj.Type()] = len(symbols) - 1 64 } 65 case *ast.ValueSpec: 66 for _, name := range spec.Names { 67 if name.Name == "_" { 68 continue 69 } 70 if obj := info.ObjectOf(name); obj != nil { 71 vs, err := varSymbol(snapshot, pkg, decl, name, obj, q) 72 if err != nil { 73 return nil, err 74 } 75 symbols = append(symbols, vs) 76 } 77 } 78 } 79 } 80 } 81 } 82 return symbols, nil 83 } 84 85 func funcSymbol(snapshot Snapshot, pkg Package, decl *ast.FuncDecl, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) { 86 s := protocol.DocumentSymbol{ 87 Name: obj.Name(), 88 Kind: protocol.Function, 89 } 90 var err error 91 s.Range, err = nodeToProtocolRange(snapshot, pkg, decl) 92 if err != nil { 93 return protocol.DocumentSymbol{}, err 94 } 95 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, decl.Name) 96 if err != nil { 97 return protocol.DocumentSymbol{}, err 98 } 99 sig, _ := obj.Type().(*types.Signature) 100 if sig != nil { 101 if sig.Recv() != nil { 102 s.Kind = protocol.Method 103 } 104 s.Detail += "(" 105 for i := 0; i < sig.Params().Len(); i++ { 106 if i > 0 { 107 s.Detail += ", " 108 } 109 param := sig.Params().At(i) 110 label := types.TypeString(param.Type(), q) 111 if param.Name() != "" { 112 label = fmt.Sprintf("%s %s", param.Name(), label) 113 } 114 s.Detail += label 115 } 116 s.Detail += ")" 117 } 118 return s, nil 119 } 120 121 func typeSymbol(snapshot Snapshot, pkg Package, info *types.Info, spec *ast.TypeSpec, obj types.Object, qf types.Qualifier) (protocol.DocumentSymbol, error) { 122 s := protocol.DocumentSymbol{ 123 Name: obj.Name(), 124 } 125 s.Detail, _ = FormatType(obj.Type(), qf) 126 s.Kind = typeToKind(obj.Type()) 127 128 var err error 129 s.Range, err = nodeToProtocolRange(snapshot, pkg, spec) 130 if err != nil { 131 return protocol.DocumentSymbol{}, err 132 } 133 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, spec.Name) 134 if err != nil { 135 return protocol.DocumentSymbol{}, err 136 } 137 t, objIsStruct := obj.Type().Underlying().(*types.Struct) 138 st, specIsStruct := spec.Type.(*ast.StructType) 139 if objIsStruct && specIsStruct { 140 for i := 0; i < t.NumFields(); i++ { 141 f := t.Field(i) 142 child := protocol.DocumentSymbol{ 143 Name: f.Name(), 144 Kind: protocol.Field, 145 } 146 child.Detail, _ = FormatType(f.Type(), qf) 147 148 spanNode, selectionNode := nodesForStructField(i, st) 149 if span, err := nodeToProtocolRange(snapshot, pkg, spanNode); err == nil { 150 child.Range = span 151 } 152 if span, err := nodeToProtocolRange(snapshot, pkg, selectionNode); err == nil { 153 child.SelectionRange = span 154 } 155 s.Children = append(s.Children, child) 156 } 157 } 158 159 ti, objIsInterface := obj.Type().Underlying().(*types.Interface) 160 ai, specIsInterface := spec.Type.(*ast.InterfaceType) 161 if objIsInterface && specIsInterface { 162 for i := 0; i < ti.NumExplicitMethods(); i++ { 163 method := ti.ExplicitMethod(i) 164 child := protocol.DocumentSymbol{ 165 Name: method.Name(), 166 Kind: protocol.Method, 167 } 168 169 var spanNode, selectionNode ast.Node 170 Methods: 171 for _, f := range ai.Methods.List { 172 for _, id := range f.Names { 173 if id.Name == method.Name() { 174 spanNode, selectionNode = f, id 175 break Methods 176 } 177 } 178 } 179 child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode) 180 if err != nil { 181 return protocol.DocumentSymbol{}, err 182 } 183 child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode) 184 if err != nil { 185 return protocol.DocumentSymbol{}, err 186 } 187 s.Children = append(s.Children, child) 188 } 189 190 for i := 0; i < ti.NumEmbeddeds(); i++ { 191 embedded := ti.EmbeddedType(i) 192 nt, isNamed := embedded.(*types.Named) 193 if !isNamed { 194 continue 195 } 196 197 child := protocol.DocumentSymbol{ 198 Name: types.TypeString(embedded, qf), 199 } 200 child.Kind = typeToKind(embedded) 201 var spanNode, selectionNode ast.Node 202 Embeddeds: 203 for _, f := range ai.Methods.List { 204 if len(f.Names) > 0 { 205 continue 206 } 207 208 if t := info.TypeOf(f.Type); types.Identical(nt, t) { 209 spanNode, selectionNode = f, f.Type 210 break Embeddeds 211 } 212 } 213 child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode) 214 if err != nil { 215 return protocol.DocumentSymbol{}, err 216 } 217 child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode) 218 if err != nil { 219 return protocol.DocumentSymbol{}, err 220 } 221 s.Children = append(s.Children, child) 222 } 223 } 224 return s, nil 225 } 226 227 func nodesForStructField(i int, st *ast.StructType) (span, selection ast.Node) { 228 j := 0 229 for _, field := range st.Fields.List { 230 if len(field.Names) == 0 { 231 if i == j { 232 return field, field.Type 233 } 234 j++ 235 continue 236 } 237 for _, name := range field.Names { 238 if i == j { 239 return field, name 240 } 241 j++ 242 } 243 } 244 return nil, nil 245 } 246 247 func varSymbol(snapshot Snapshot, pkg Package, decl ast.Node, name *ast.Ident, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) { 248 s := protocol.DocumentSymbol{ 249 Name: obj.Name(), 250 Kind: protocol.Variable, 251 } 252 if _, ok := obj.(*types.Const); ok { 253 s.Kind = protocol.Constant 254 } 255 var err error 256 s.Range, err = nodeToProtocolRange(snapshot, pkg, decl) 257 if err != nil { 258 return protocol.DocumentSymbol{}, err 259 } 260 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, name) 261 if err != nil { 262 return protocol.DocumentSymbol{}, err 263 } 264 s.Detail = types.TypeString(obj.Type(), q) 265 return s, nil 266 }