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.
13 "golang.org/x/tools/internal/event"
14 "golang.org/x/tools/internal/lsp/protocol"
15 errors "golang.org/x/xerrors"
18 func DocumentSymbols(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.DocumentSymbol, error) {
19 ctx, done := event.Start(ctx, "source.DocumentSymbols")
22 pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
24 return nil, errors.Errorf("getting file for DocumentSymbols: %w", err)
27 info := pkg.GetTypesInfo()
28 q := Qualifier(pgf.File, pkg.GetTypes(), info)
30 symbolsToReceiver := make(map[types.Type]int)
31 var symbols []protocol.DocumentSymbol
32 for _, decl := range pgf.File.Decls {
33 switch decl := decl.(type) {
35 if decl.Name.Name == "_" {
38 if obj := info.ObjectOf(decl.Name); obj != nil {
39 fs, err := funcSymbol(snapshot, pkg, decl, obj, q)
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)
48 symbols = append(symbols, fs)
51 for _, spec := range decl.Specs {
52 switch spec := spec.(type) {
54 if spec.Name.Name == "_" {
57 if obj := info.ObjectOf(spec.Name); obj != nil {
58 ts, err := typeSymbol(snapshot, pkg, info, spec, obj, q)
62 symbols = append(symbols, ts)
63 symbolsToReceiver[obj.Type()] = len(symbols) - 1
66 for _, name := range spec.Names {
70 if obj := info.ObjectOf(name); obj != nil {
71 vs, err := varSymbol(snapshot, pkg, decl, name, obj, q)
75 symbols = append(symbols, vs)
85 func funcSymbol(snapshot Snapshot, pkg Package, decl *ast.FuncDecl, obj types.Object, q types.Qualifier) (protocol.DocumentSymbol, error) {
86 s := protocol.DocumentSymbol{
88 Kind: protocol.Function,
91 s.Range, err = nodeToProtocolRange(snapshot, pkg, decl)
93 return protocol.DocumentSymbol{}, err
95 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, decl.Name)
97 return protocol.DocumentSymbol{}, err
99 sig, _ := obj.Type().(*types.Signature)
101 if sig.Recv() != nil {
102 s.Kind = protocol.Method
105 for i := 0; i < sig.Params().Len(); i++ {
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)
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{
125 s.Detail, _ = FormatType(obj.Type(), qf)
126 s.Kind = typeToKind(obj.Type())
129 s.Range, err = nodeToProtocolRange(snapshot, pkg, spec)
131 return protocol.DocumentSymbol{}, err
133 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, spec.Name)
135 return protocol.DocumentSymbol{}, err
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++ {
142 child := protocol.DocumentSymbol{
144 Kind: protocol.Field,
146 child.Detail, _ = FormatType(f.Type(), qf)
148 spanNode, selectionNode := nodesForStructField(i, st)
149 if span, err := nodeToProtocolRange(snapshot, pkg, spanNode); err == nil {
152 if span, err := nodeToProtocolRange(snapshot, pkg, selectionNode); err == nil {
153 child.SelectionRange = span
155 s.Children = append(s.Children, child)
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{
166 Kind: protocol.Method,
169 var spanNode, selectionNode ast.Node
171 for _, f := range ai.Methods.List {
172 for _, id := range f.Names {
173 if id.Name == method.Name() {
174 spanNode, selectionNode = f, id
179 child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode)
181 return protocol.DocumentSymbol{}, err
183 child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode)
185 return protocol.DocumentSymbol{}, err
187 s.Children = append(s.Children, child)
190 for i := 0; i < ti.NumEmbeddeds(); i++ {
191 embedded := ti.EmbeddedType(i)
192 nt, isNamed := embedded.(*types.Named)
197 child := protocol.DocumentSymbol{
198 Name: types.TypeString(embedded, qf),
200 child.Kind = typeToKind(embedded)
201 var spanNode, selectionNode ast.Node
203 for _, f := range ai.Methods.List {
204 if len(f.Names) > 0 {
208 if t := info.TypeOf(f.Type); types.Identical(nt, t) {
209 spanNode, selectionNode = f, f.Type
213 child.Range, err = nodeToProtocolRange(snapshot, pkg, spanNode)
215 return protocol.DocumentSymbol{}, err
217 child.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, selectionNode)
219 return protocol.DocumentSymbol{}, err
221 s.Children = append(s.Children, child)
227 func nodesForStructField(i int, st *ast.StructType) (span, selection ast.Node) {
229 for _, field := range st.Fields.List {
230 if len(field.Names) == 0 {
232 return field, field.Type
237 for _, name := range field.Names {
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{
250 Kind: protocol.Variable,
252 if _, ok := obj.(*types.Const); ok {
253 s.Kind = protocol.Constant
256 s.Range, err = nodeToProtocolRange(snapshot, pkg, decl)
258 return protocol.DocumentSymbol{}, err
260 s.SelectionRange, err = nodeToProtocolRange(snapshot, pkg, name)
262 return protocol.DocumentSymbol{}, err
264 s.Detail = types.TypeString(obj.Type(), q)