Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / source / signature_help.go
1 // Copyright 2018 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         "go/ast"
10         "go/token"
11         "go/types"
12
13         "golang.org/x/tools/go/ast/astutil"
14         "golang.org/x/tools/internal/event"
15         "golang.org/x/tools/internal/lsp/protocol"
16         errors "golang.org/x/xerrors"
17 )
18
19 func SignatureHelp(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (*protocol.SignatureInformation, int, error) {
20         ctx, done := event.Start(ctx, "source.SignatureHelp")
21         defer done()
22
23         pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
24         if err != nil {
25                 return nil, 0, errors.Errorf("getting file for SignatureHelp: %w", err)
26         }
27         spn, err := pgf.Mapper.PointSpan(pos)
28         if err != nil {
29                 return nil, 0, err
30         }
31         rng, err := spn.Range(pgf.Mapper.Converter)
32         if err != nil {
33                 return nil, 0, err
34         }
35         // Find a call expression surrounding the query position.
36         var callExpr *ast.CallExpr
37         path, _ := astutil.PathEnclosingInterval(pgf.File, rng.Start, rng.Start)
38         if path == nil {
39                 return nil, 0, errors.Errorf("cannot find node enclosing position")
40         }
41 FindCall:
42         for _, node := range path {
43                 switch node := node.(type) {
44                 case *ast.CallExpr:
45                         if rng.Start >= node.Lparen && rng.Start <= node.Rparen {
46                                 callExpr = node
47                                 break FindCall
48                         }
49                 case *ast.FuncLit, *ast.FuncType:
50                         // The user is within an anonymous function,
51                         // which may be the parameter to the *ast.CallExpr.
52                         // Don't show signature help in this case.
53                         return nil, 0, errors.Errorf("no signature help within a function declaration")
54                 }
55         }
56         if callExpr == nil || callExpr.Fun == nil {
57                 return nil, 0, errors.Errorf("cannot find an enclosing function")
58         }
59
60         qf := Qualifier(pgf.File, pkg.GetTypes(), pkg.GetTypesInfo())
61
62         // Get the object representing the function, if available.
63         // There is no object in certain cases such as calling a function returned by
64         // a function (e.g. "foo()()").
65         var obj types.Object
66         switch t := callExpr.Fun.(type) {
67         case *ast.Ident:
68                 obj = pkg.GetTypesInfo().ObjectOf(t)
69         case *ast.SelectorExpr:
70                 obj = pkg.GetTypesInfo().ObjectOf(t.Sel)
71         }
72
73         // Handle builtin functions separately.
74         if obj, ok := obj.(*types.Builtin); ok {
75                 return builtinSignature(ctx, snapshot, callExpr, obj.Name(), rng.Start)
76         }
77
78         // Get the type information for the function being called.
79         sigType := pkg.GetTypesInfo().TypeOf(callExpr.Fun)
80         if sigType == nil {
81                 return nil, 0, errors.Errorf("cannot get type for Fun %[1]T (%[1]v)", callExpr.Fun)
82         }
83
84         sig, _ := sigType.Underlying().(*types.Signature)
85         if sig == nil {
86                 return nil, 0, errors.Errorf("cannot find signature for Fun %[1]T (%[1]v)", callExpr.Fun)
87         }
88
89         activeParam := activeParameter(callExpr, sig.Params().Len(), sig.Variadic(), rng.Start)
90
91         var (
92                 name    string
93                 comment *ast.CommentGroup
94         )
95         if obj != nil {
96                 node, err := objToDecl(ctx, snapshot, pkg, obj)
97                 if err != nil {
98                         return nil, 0, err
99                 }
100                 rng, err := objToMappedRange(snapshot, pkg, obj)
101                 if err != nil {
102                         return nil, 0, err
103                 }
104                 decl := Declaration{
105                         obj:  obj,
106                         node: node,
107                 }
108                 decl.MappedRange = append(decl.MappedRange, rng)
109                 d, err := HoverInfo(ctx, pkg, decl.obj, decl.node)
110                 if err != nil {
111                         return nil, 0, err
112                 }
113                 name = obj.Name()
114                 comment = d.comment
115         } else {
116                 name = "func"
117         }
118         s := NewSignature(ctx, snapshot, pkg, sig, comment, qf)
119         paramInfo := make([]protocol.ParameterInformation, 0, len(s.params))
120         for _, p := range s.params {
121                 paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
122         }
123         return &protocol.SignatureInformation{
124                 Label:         name + s.Format(),
125                 Documentation: s.doc,
126                 Parameters:    paramInfo,
127         }, activeParam, nil
128 }
129
130 func builtinSignature(ctx context.Context, snapshot Snapshot, callExpr *ast.CallExpr, name string, pos token.Pos) (*protocol.SignatureInformation, int, error) {
131         sig, err := NewBuiltinSignature(ctx, snapshot, name)
132         if err != nil {
133                 return nil, 0, err
134         }
135         paramInfo := make([]protocol.ParameterInformation, 0, len(sig.params))
136         for _, p := range sig.params {
137                 paramInfo = append(paramInfo, protocol.ParameterInformation{Label: p})
138         }
139         activeParam := activeParameter(callExpr, len(sig.params), sig.variadic, pos)
140         return &protocol.SignatureInformation{
141                 Label:         sig.name + sig.Format(),
142                 Documentation: sig.doc,
143                 Parameters:    paramInfo,
144         }, activeParam, nil
145
146 }
147
148 func activeParameter(callExpr *ast.CallExpr, numParams int, variadic bool, pos token.Pos) (activeParam int) {
149         if len(callExpr.Args) == 0 {
150                 return 0
151         }
152         // First, check if the position is even in the range of the arguments.
153         start, end := callExpr.Lparen, callExpr.Rparen
154         if !(start <= pos && pos <= end) {
155                 return 0
156         }
157         for _, expr := range callExpr.Args {
158                 if start == token.NoPos {
159                         start = expr.Pos()
160                 }
161                 end = expr.End()
162                 if start <= pos && pos <= end {
163                         break
164                 }
165                 // Don't advance the active parameter for the last parameter of a variadic function.
166                 if !variadic || activeParam < numParams-1 {
167                         activeParam++
168                 }
169                 start = expr.Pos() + 1 // to account for commas
170         }
171         return activeParam
172 }