.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / internal / lsp / source / completion / format.go
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 completion
6
7 import (
8         "context"
9         "fmt"
10         "go/types"
11         "strings"
12
13         "golang.org/x/tools/internal/event"
14         "golang.org/x/tools/internal/imports"
15         "golang.org/x/tools/internal/lsp/debug/tag"
16         "golang.org/x/tools/internal/lsp/protocol"
17         "golang.org/x/tools/internal/lsp/snippet"
18         "golang.org/x/tools/internal/lsp/source"
19         "golang.org/x/tools/internal/span"
20         errors "golang.org/x/xerrors"
21 )
22
23 // item formats a candidate to a CompletionItem.
24 func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, error) {
25         obj := cand.obj
26
27         // if the object isn't a valid match against the surrounding, return early.
28         matchScore := c.matcher.Score(cand.name)
29         if matchScore <= 0 {
30                 return CompletionItem{}, errors.New("not a surrounding match")
31         }
32         cand.score *= float64(matchScore)
33
34         // Ignore deep candidates that wont be in the MaxDeepCompletions anyway.
35         if len(cand.path) != 0 && !c.deepState.isHighScore(cand.score) {
36                 return CompletionItem{}, errors.New("not a high scoring candidate")
37         }
38
39         // Handle builtin types separately.
40         if obj.Parent() == types.Universe {
41                 return c.formatBuiltin(ctx, cand)
42         }
43
44         var (
45                 label         = cand.name
46                 detail        = types.TypeString(obj.Type(), c.qf)
47                 insert        = label
48                 kind          = protocol.TextCompletion
49                 snip          *snippet.Builder
50                 protocolEdits []protocol.TextEdit
51         )
52         if obj.Type() == nil {
53                 detail = ""
54         }
55
56         // expandFuncCall mutates the completion label, detail, and snippet
57         // to that of an invocation of sig.
58         expandFuncCall := func(sig *types.Signature) {
59                 s := source.NewSignature(ctx, c.snapshot, c.pkg, sig, nil, c.qf)
60                 snip = c.functionCallSnippet(label, s.Params())
61                 detail = "func" + s.Format()
62         }
63
64         switch obj := obj.(type) {
65         case *types.TypeName:
66                 detail, kind = source.FormatType(obj.Type(), c.qf)
67         case *types.Const:
68                 kind = protocol.ConstantCompletion
69         case *types.Var:
70                 if _, ok := obj.Type().(*types.Struct); ok {
71                         detail = "struct{...}" // for anonymous structs
72                 } else if obj.IsField() {
73                         detail = source.FormatVarType(ctx, c.snapshot, c.pkg, obj, c.qf)
74                 }
75                 if obj.IsField() {
76                         kind = protocol.FieldCompletion
77                         snip = c.structFieldSnippet(cand, label, detail)
78                 } else {
79                         kind = protocol.VariableCompletion
80                 }
81                 if obj.Type() == nil {
82                         break
83                 }
84
85                 if sig, ok := obj.Type().Underlying().(*types.Signature); ok && cand.expandFuncCall {
86                         expandFuncCall(sig)
87                 }
88         case *types.Func:
89                 sig, ok := obj.Type().Underlying().(*types.Signature)
90                 if !ok {
91                         break
92                 }
93                 kind = protocol.FunctionCompletion
94                 if sig != nil && sig.Recv() != nil {
95                         kind = protocol.MethodCompletion
96                 }
97
98                 if cand.expandFuncCall {
99                         expandFuncCall(sig)
100                 }
101         case *types.PkgName:
102                 kind = protocol.ModuleCompletion
103                 detail = fmt.Sprintf("%q", obj.Imported().Path())
104         case *types.Label:
105                 kind = protocol.ConstantCompletion
106                 detail = "label"
107         }
108
109         // If this candidate needs an additional import statement,
110         // add the additional text edits needed.
111         if cand.imp != nil {
112                 addlEdits, err := c.importEdits(cand.imp)
113                 if err != nil {
114                         return CompletionItem{}, err
115                 }
116
117                 protocolEdits = append(protocolEdits, addlEdits...)
118                 if kind != protocol.ModuleCompletion {
119                         if detail != "" {
120                                 detail += " "
121                         }
122                         detail += fmt.Sprintf("(from %q)", cand.imp.importPath)
123                 }
124         }
125
126         var prefix, suffix string
127
128         // Prepend "&" or "*" operator as appropriate.
129         if cand.takeAddress {
130                 prefix = "&"
131         } else if cand.makePointer {
132                 prefix = "*"
133         } else if cand.dereference > 0 {
134                 prefix = strings.Repeat("*", cand.dereference)
135         }
136
137         // Include "*" and "&" prefixes in the label.
138         label = prefix + label
139
140         if cand.convertTo != nil {
141                 typeName := types.TypeString(cand.convertTo, c.qf)
142
143                 switch cand.convertTo.(type) {
144                 // We need extra parens when casting to these types. For example,
145                 // we need "(*int)(foo)", not "*int(foo)".
146                 case *types.Pointer, *types.Signature:
147                         typeName = "(" + typeName + ")"
148                 }
149
150                 prefix = typeName + "(" + prefix
151                 suffix = ")"
152         }
153
154         // Add variadic "..." if we are filling in a variadic param.
155         if cand.variadic {
156                 suffix += "..."
157         }
158
159         if prefix != "" {
160                 // If we are in a selector, add an edit to place prefix before selector.
161                 if sel := enclosingSelector(c.path, c.pos); sel != nil {
162                         edits, err := prependEdit(c.snapshot.FileSet(), c.mapper, sel, prefix)
163                         if err != nil {
164                                 return CompletionItem{}, err
165                         }
166                         protocolEdits = append(protocolEdits, edits...)
167                 } else {
168                         // If there is no selector, just stick the prefix at the start.
169                         insert = prefix + insert
170                         if snip != nil {
171                                 snip.PrependText(prefix)
172                         }
173                 }
174         }
175
176         if suffix != "" {
177                 insert += suffix
178                 if snip != nil {
179                         snip.WriteText(suffix)
180                 }
181         }
182
183         detail = strings.TrimPrefix(detail, "untyped ")
184         // override computed detail with provided detail, if something is provided.
185         if cand.detail != "" {
186                 detail = cand.detail
187         }
188         item := CompletionItem{
189                 Label:               label,
190                 InsertText:          insert,
191                 AdditionalTextEdits: protocolEdits,
192                 Detail:              detail,
193                 Kind:                kind,
194                 Score:               cand.score,
195                 Depth:               len(cand.path),
196                 snippet:             snip,
197                 obj:                 obj,
198         }
199         // If the user doesn't want documentation for completion items.
200         if !c.opts.documentation {
201                 return item, nil
202         }
203         pos := c.snapshot.FileSet().Position(obj.Pos())
204
205         // We ignore errors here, because some types, like "unsafe" or "error",
206         // may not have valid positions that we can use to get documentation.
207         if !pos.IsValid() {
208                 return item, nil
209         }
210         uri := span.URIFromPath(pos.Filename)
211
212         // Find the source file of the candidate, starting from a package
213         // that should have it in its dependencies.
214         searchPkg := c.pkg
215         if cand.imp != nil && cand.imp.pkg != nil {
216                 searchPkg = cand.imp.pkg
217         }
218
219         pgf, pkg, err := source.FindPosInPackage(c.snapshot, searchPkg, obj.Pos())
220         if err != nil {
221                 return item, nil
222         }
223
224         posToDecl, err := c.snapshot.PosToDecl(ctx, pgf)
225         if err != nil {
226                 return CompletionItem{}, err
227         }
228         decl := posToDecl[obj.Pos()]
229         if decl == nil {
230                 return item, nil
231         }
232
233         hover, err := source.HoverInfo(ctx, pkg, obj, decl)
234         if err != nil {
235                 event.Error(ctx, "failed to find Hover", err, tag.URI.Of(uri))
236                 return item, nil
237         }
238         item.Documentation = hover.Synopsis
239         if c.opts.fullDocumentation {
240                 item.Documentation = hover.FullDocumentation
241         }
242
243         return item, nil
244 }
245
246 // importEdits produces the text edits necessary to add the given import to the current file.
247 func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
248         if imp == nil {
249                 return nil, nil
250         }
251
252         pgf, err := c.pkg.File(span.URIFromPath(c.filename))
253         if err != nil {
254                 return nil, err
255         }
256
257         return source.ComputeOneImportFixEdits(c.snapshot, pgf, &imports.ImportFix{
258                 StmtInfo: imports.ImportInfo{
259                         ImportPath: imp.importPath,
260                         Name:       imp.name,
261                 },
262                 // IdentName is unused on this path and is difficult to get.
263                 FixType: imports.AddImport,
264         })
265 }
266
267 func (c *completer) formatBuiltin(ctx context.Context, cand candidate) (CompletionItem, error) {
268         obj := cand.obj
269         item := CompletionItem{
270                 Label:      obj.Name(),
271                 InsertText: obj.Name(),
272                 Score:      cand.score,
273         }
274         switch obj.(type) {
275         case *types.Const:
276                 item.Kind = protocol.ConstantCompletion
277         case *types.Builtin:
278                 item.Kind = protocol.FunctionCompletion
279                 sig, err := source.NewBuiltinSignature(ctx, c.snapshot, obj.Name())
280                 if err != nil {
281                         return CompletionItem{}, err
282                 }
283                 item.Detail = "func" + sig.Format()
284                 item.snippet = c.functionCallSnippet(obj.Name(), sig.Params())
285         case *types.TypeName:
286                 if types.IsInterface(obj.Type()) {
287                         item.Kind = protocol.InterfaceCompletion
288                 } else {
289                         item.Kind = protocol.ClassCompletion
290                 }
291         case *types.Nil:
292                 item.Kind = protocol.VariableCompletion
293         }
294         return item, nil
295 }