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