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 / completion / literal.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/ast"
11         "go/token"
12         "go/types"
13         "strings"
14         "unicode"
15
16         "golang.org/x/tools/internal/event"
17         "golang.org/x/tools/internal/lsp/diff"
18         "golang.org/x/tools/internal/lsp/protocol"
19         "golang.org/x/tools/internal/lsp/snippet"
20         "golang.org/x/tools/internal/lsp/source"
21 )
22
23 // literal generates composite literal, function literal, and make()
24 // completion items.
25 func (c *completer) literal(ctx context.Context, literalType types.Type, imp *importInfo) {
26         if !c.opts.literal {
27                 return
28         }
29
30         expType := c.inference.objType
31
32         if c.inference.matchesVariadic(literalType) {
33                 // Don't offer literal slice candidates for variadic arguments.
34                 // For example, don't offer "[]interface{}{}" in "fmt.Print(<>)".
35                 return
36         }
37
38         // Avoid literal candidates if the expected type is an empty
39         // interface. It isn't very useful to suggest a literal candidate of
40         // every possible type.
41         if expType != nil && isEmptyInterface(expType) {
42                 return
43         }
44
45         // We handle unnamed literal completions explicitly before searching
46         // for candidates. Avoid named-type literal completions for
47         // unnamed-type expected type since that results in duplicate
48         // candidates. For example, in
49         //
50         // type mySlice []int
51         // var []int = <>
52         //
53         // don't offer "mySlice{}" since we have already added a candidate
54         // of "[]int{}".
55         if _, named := literalType.(*types.Named); named && expType != nil {
56                 if _, named := source.Deref(expType).(*types.Named); !named {
57                         return
58                 }
59         }
60
61         // Check if an object of type literalType would match our expected type.
62         cand := candidate{
63                 obj: c.fakeObj(literalType),
64         }
65
66         switch literalType.Underlying().(type) {
67         // These literal types are addressable (e.g. "&[]int{}"), others are
68         // not (e.g. can't do "&(func(){})").
69         case *types.Struct, *types.Array, *types.Slice, *types.Map:
70                 cand.addressable = true
71         }
72
73         if !c.matchingCandidate(&cand) {
74                 return
75         }
76
77         var (
78                 qf  = c.qf
79                 sel = enclosingSelector(c.path, c.pos)
80         )
81
82         // Don't qualify the type name if we are in a selector expression
83         // since the package name is already present.
84         if sel != nil {
85                 qf = func(_ *types.Package) string { return "" }
86         }
87
88         typeName := types.TypeString(literalType, qf)
89
90         // A type name of "[]int" doesn't work very will with the matcher
91         // since "[" isn't a valid identifier prefix. Here we strip off the
92         // slice (and array) prefix yielding just "int".
93         matchName := typeName
94         switch t := literalType.(type) {
95         case *types.Slice:
96                 matchName = types.TypeString(t.Elem(), qf)
97         case *types.Array:
98                 matchName = types.TypeString(t.Elem(), qf)
99         }
100
101         addlEdits, err := c.importEdits(imp)
102         if err != nil {
103                 event.Error(ctx, "error adding import for literal candidate", err)
104                 return
105         }
106
107         // If prefix matches the type name, client may want a composite literal.
108         if score := c.matcher.Score(matchName); score > 0 {
109                 if cand.takeAddress {
110                         if sel != nil {
111                                 // If we are in a selector we must place the "&" before the selector.
112                                 // For example, "foo.B<>" must complete to "&foo.Bar{}", not
113                                 // "foo.&Bar{}".
114                                 edits, err := prependEdit(c.snapshot.FileSet(), c.mapper, sel, "&")
115                                 if err != nil {
116                                         event.Error(ctx, "error making edit for literal pointer completion", err)
117                                         return
118                                 }
119                                 addlEdits = append(addlEdits, edits...)
120                         } else {
121                                 // Otherwise we can stick the "&" directly before the type name.
122                                 typeName = "&" + typeName
123                         }
124                 }
125
126                 switch t := literalType.Underlying().(type) {
127                 case *types.Struct, *types.Array, *types.Slice, *types.Map:
128                         c.compositeLiteral(t, typeName, float64(score), addlEdits)
129                 case *types.Signature:
130                         // Add a literal completion for a signature type that implements
131                         // an interface. For example, offer "http.HandlerFunc()" when
132                         // expected type is "http.Handler".
133                         if source.IsInterface(expType) {
134                                 c.basicLiteral(t, typeName, float64(score), addlEdits)
135                         }
136                 case *types.Basic:
137                         // Add a literal completion for basic types that implement our
138                         // expected interface (e.g. named string type http.Dir
139                         // implements http.FileSystem), or are identical to our expected
140                         // type (i.e. yielding a type conversion such as "float64()").
141                         if source.IsInterface(expType) || types.Identical(expType, literalType) {
142                                 c.basicLiteral(t, typeName, float64(score), addlEdits)
143                         }
144                 }
145         }
146
147         // If prefix matches "make", client may want a "make()"
148         // invocation. We also include the type name to allow for more
149         // flexible fuzzy matching.
150         if score := c.matcher.Score("make." + matchName); !cand.takeAddress && score > 0 {
151                 switch literalType.Underlying().(type) {
152                 case *types.Slice:
153                         // The second argument to "make()" for slices is required, so default to "0".
154                         c.makeCall(typeName, "0", float64(score), addlEdits)
155                 case *types.Map, *types.Chan:
156                         // Maps and channels don't require the second argument, so omit
157                         // to keep things simple for now.
158                         c.makeCall(typeName, "", float64(score), addlEdits)
159                 }
160         }
161
162         // If prefix matches "func", client may want a function literal.
163         if score := c.matcher.Score("func"); !cand.takeAddress && score > 0 && !source.IsInterface(expType) {
164                 switch t := literalType.Underlying().(type) {
165                 case *types.Signature:
166                         c.functionLiteral(ctx, t, float64(score))
167                 }
168         }
169 }
170
171 // prependEdit produces text edits that preprend the specified prefix
172 // to the specified node.
173 func prependEdit(fset *token.FileSet, m *protocol.ColumnMapper, node ast.Node, prefix string) ([]protocol.TextEdit, error) {
174         rng := source.NewMappedRange(fset, m, node.Pos(), node.Pos())
175         spn, err := rng.Span()
176         if err != nil {
177                 return nil, err
178         }
179         return source.ToProtocolEdits(m, []diff.TextEdit{{
180                 Span:    spn,
181                 NewText: prefix,
182         }})
183 }
184
185 // literalCandidateScore is the base score for literal candidates.
186 // Literal candidates match the expected type so they should be high
187 // scoring, but we want them ranked below lexical objects of the
188 // correct type, so scale down highScore.
189 const literalCandidateScore = highScore / 2
190
191 // functionLiteral adds a function literal completion item for the
192 // given signature.
193 func (c *completer) functionLiteral(ctx context.Context, sig *types.Signature, matchScore float64) {
194         snip := &snippet.Builder{}
195         snip.WriteText("func(")
196
197         // First we generate names for each param and keep a seen count so
198         // we know if we need to uniquify param names. For example,
199         // "func(int)" will become "func(i int)", but "func(int, int64)"
200         // will become "func(i1 int, i2 int64)".
201         var (
202                 paramNames     = make([]string, sig.Params().Len())
203                 paramNameCount = make(map[string]int)
204         )
205         for i := 0; i < sig.Params().Len(); i++ {
206                 var (
207                         p    = sig.Params().At(i)
208                         name = p.Name()
209                 )
210                 if name == "" {
211                         // If the param has no name in the signature, guess a name based
212                         // on the type. Use an empty qualifier to ignore the package.
213                         // For example, we want to name "http.Request" "r", not "hr".
214                         name = source.FormatVarType(ctx, c.snapshot, c.pkg, p, func(p *types.Package) string {
215                                 return ""
216                         })
217                         name = abbreviateTypeName(name)
218                 }
219                 paramNames[i] = name
220                 if name != "_" {
221                         paramNameCount[name]++
222                 }
223         }
224
225         for n, c := range paramNameCount {
226                 // Any names we saw more than once will need a unique suffix added
227                 // on. Reset the count to 1 to act as the suffix for the first
228                 // name.
229                 if c >= 2 {
230                         paramNameCount[n] = 1
231                 } else {
232                         delete(paramNameCount, n)
233                 }
234         }
235
236         for i := 0; i < sig.Params().Len(); i++ {
237                 if i > 0 {
238                         snip.WriteText(", ")
239                 }
240
241                 var (
242                         p    = sig.Params().At(i)
243                         name = paramNames[i]
244                 )
245
246                 // Uniquify names by adding on an incrementing numeric suffix.
247                 if idx, found := paramNameCount[name]; found {
248                         paramNameCount[name]++
249                         name = fmt.Sprintf("%s%d", name, idx)
250                 }
251
252                 if name != p.Name() && c.opts.placeholders {
253                         // If we didn't use the signature's param name verbatim then we
254                         // may have chosen a poor name. Give the user a placeholder so
255                         // they can easily fix the name.
256                         snip.WritePlaceholder(func(b *snippet.Builder) {
257                                 b.WriteText(name)
258                         })
259                 } else {
260                         snip.WriteText(name)
261                 }
262
263                 // If the following param's type is identical to this one, omit
264                 // this param's type string. For example, emit "i, j int" instead
265                 // of "i int, j int".
266                 if i == sig.Params().Len()-1 || !types.Identical(p.Type(), sig.Params().At(i+1).Type()) {
267                         snip.WriteText(" ")
268                         typeStr := source.FormatVarType(ctx, c.snapshot, c.pkg, p, c.qf)
269                         if sig.Variadic() && i == sig.Params().Len()-1 {
270                                 typeStr = strings.Replace(typeStr, "[]", "...", 1)
271                         }
272                         snip.WriteText(typeStr)
273                 }
274         }
275         snip.WriteText(")")
276
277         results := sig.Results()
278         if results.Len() > 0 {
279                 snip.WriteText(" ")
280         }
281
282         resultsNeedParens := results.Len() > 1 ||
283                 results.Len() == 1 && results.At(0).Name() != ""
284
285         if resultsNeedParens {
286                 snip.WriteText("(")
287         }
288         for i := 0; i < results.Len(); i++ {
289                 if i > 0 {
290                         snip.WriteText(", ")
291                 }
292                 r := results.At(i)
293                 if name := r.Name(); name != "" {
294                         snip.WriteText(name + " ")
295                 }
296                 snip.WriteText(source.FormatVarType(ctx, c.snapshot, c.pkg, r, c.qf))
297         }
298         if resultsNeedParens {
299                 snip.WriteText(")")
300         }
301
302         snip.WriteText(" {")
303         snip.WriteFinalTabstop()
304         snip.WriteText("}")
305
306         c.items = append(c.items, CompletionItem{
307                 Label:   "func(...) {}",
308                 Score:   matchScore * literalCandidateScore,
309                 Kind:    protocol.VariableCompletion,
310                 snippet: snip,
311         })
312 }
313
314 // abbreviateTypeName abbreviates type names into acronyms. For
315 // example, "fooBar" is abbreviated "fb". Care is taken to ignore
316 // non-identifier runes. For example, "[]int" becomes "i", and
317 // "struct { i int }" becomes "s".
318 func abbreviateTypeName(s string) string {
319         var (
320                 b            strings.Builder
321                 useNextUpper bool
322         )
323
324         // Trim off leading non-letters. We trim everything between "[" and
325         // "]" to handle array types like "[someConst]int".
326         var inBracket bool
327         s = strings.TrimFunc(s, func(r rune) bool {
328                 if inBracket {
329                         inBracket = r != ']'
330                         return true
331                 }
332
333                 if r == '[' {
334                         inBracket = true
335                 }
336
337                 return !unicode.IsLetter(r)
338         })
339
340         for i, r := range s {
341                 // Stop if we encounter a non-identifier rune.
342                 if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
343                         break
344                 }
345
346                 if i == 0 {
347                         b.WriteRune(unicode.ToLower(r))
348                 }
349
350                 if unicode.IsUpper(r) {
351                         if useNextUpper {
352                                 b.WriteRune(unicode.ToLower(r))
353                                 useNextUpper = false
354                         }
355                 } else {
356                         useNextUpper = true
357                 }
358         }
359
360         return b.String()
361 }
362
363 // compositeLiteral adds a composite literal completion item for the given typeName.
364 func (c *completer) compositeLiteral(T types.Type, typeName string, matchScore float64, edits []protocol.TextEdit) {
365         snip := &snippet.Builder{}
366         snip.WriteText(typeName + "{")
367         // Don't put the tab stop inside the composite literal curlies "{}"
368         // for structs that have no accessible fields.
369         if strct, ok := T.(*types.Struct); !ok || fieldsAccessible(strct, c.pkg.GetTypes()) {
370                 snip.WriteFinalTabstop()
371         }
372         snip.WriteText("}")
373
374         nonSnippet := typeName + "{}"
375
376         c.items = append(c.items, CompletionItem{
377                 Label:               nonSnippet,
378                 InsertText:          nonSnippet,
379                 Score:               matchScore * literalCandidateScore,
380                 Kind:                protocol.VariableCompletion,
381                 AdditionalTextEdits: edits,
382                 snippet:             snip,
383         })
384 }
385
386 // basicLiteral adds a literal completion item for the given basic
387 // type name typeName.
388 func (c *completer) basicLiteral(T types.Type, typeName string, matchScore float64, edits []protocol.TextEdit) {
389         snip := &snippet.Builder{}
390         snip.WriteText(typeName + "(")
391         snip.WriteFinalTabstop()
392         snip.WriteText(")")
393
394         nonSnippet := typeName + "()"
395
396         c.items = append(c.items, CompletionItem{
397                 Label:               nonSnippet,
398                 InsertText:          nonSnippet,
399                 Detail:              T.String(),
400                 Score:               matchScore * literalCandidateScore,
401                 Kind:                protocol.VariableCompletion,
402                 AdditionalTextEdits: edits,
403                 snippet:             snip,
404         })
405 }
406
407 // makeCall adds a completion item for a "make()" call given a specific type.
408 func (c *completer) makeCall(typeName string, secondArg string, matchScore float64, edits []protocol.TextEdit) {
409         // Keep it simple and don't add any placeholders for optional "make()" arguments.
410
411         snip := &snippet.Builder{}
412         snip.WriteText("make(" + typeName)
413         if secondArg != "" {
414                 snip.WriteText(", ")
415                 snip.WritePlaceholder(func(b *snippet.Builder) {
416                         if c.opts.placeholders {
417                                 b.WriteText(secondArg)
418                         }
419                 })
420         }
421         snip.WriteText(")")
422
423         var nonSnippet strings.Builder
424         nonSnippet.WriteString("make(" + typeName)
425         if secondArg != "" {
426                 nonSnippet.WriteString(", ")
427                 nonSnippet.WriteString(secondArg)
428         }
429         nonSnippet.WriteByte(')')
430
431         c.items = append(c.items, CompletionItem{
432                 Label:               nonSnippet.String(),
433                 InsertText:          nonSnippet.String(),
434                 Score:               matchScore * literalCandidateScore,
435                 Kind:                protocol.FunctionCompletion,
436                 AdditionalTextEdits: edits,
437                 snippet:             snip,
438         })
439 }