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  }