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 / printf.go
1 // Copyright 2020 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         "go/ast"
9         "go/constant"
10         "go/types"
11         "strconv"
12         "strings"
13         "unicode/utf8"
14 )
15
16 // printfArgKind returns the expected objKind when completing a
17 // printf-like operand. call is the printf-like function call, and
18 // argIdx is the index of call.Args being completed.
19 func printfArgKind(info *types.Info, call *ast.CallExpr, argIdx int) objKind {
20         // Printf-like function name must end in "f".
21         fn := exprObj(info, call.Fun)
22         if fn == nil || !strings.HasSuffix(fn.Name(), "f") {
23                 return kindAny
24         }
25
26         sig, _ := fn.Type().(*types.Signature)
27         if sig == nil {
28                 return kindAny
29         }
30
31         // Must be variadic and take at least two params.
32         numParams := sig.Params().Len()
33         if !sig.Variadic() || numParams < 2 || argIdx < numParams-1 {
34                 return kindAny
35         }
36
37         // Param preceding variadic args must be a (format) string.
38         if !types.Identical(sig.Params().At(numParams-2).Type(), types.Typ[types.String]) {
39                 return kindAny
40         }
41
42         // Format string must be a constant.
43         strArg := info.Types[call.Args[numParams-2]].Value
44         if strArg == nil || strArg.Kind() != constant.String {
45                 return kindAny
46         }
47
48         return formatOperandKind(constant.StringVal(strArg), argIdx-(numParams-1)+1)
49 }
50
51 // formatOperandKind returns the objKind corresponding to format's
52 // operandIdx'th operand.
53 func formatOperandKind(format string, operandIdx int) objKind {
54         var (
55                 prevOperandIdx int
56                 kind           = kindAny
57         )
58         for {
59                 i := strings.Index(format, "%")
60                 if i == -1 {
61                         break
62                 }
63
64                 var operands []formatOperand
65                 format, operands = parsePrintfVerb(format[i+1:], prevOperandIdx)
66
67                 // Check if any this verb's operands correspond to our target
68                 // operandIdx.
69                 for _, v := range operands {
70                         if v.idx == operandIdx {
71                                 if kind == kindAny {
72                                         kind = v.kind
73                                 } else if v.kind != kindAny {
74                                         // If mulitple verbs refer to the same operand, take the
75                                         // intersection of their kinds.
76                                         kind &= v.kind
77                                 }
78                         }
79
80                         prevOperandIdx = v.idx
81                 }
82         }
83         return kind
84 }
85
86 type formatOperand struct {
87         // idx is the one-based printf operand index.
88         idx int
89         // kind is a mask of expected kinds of objects for this operand.
90         kind objKind
91 }
92
93 // parsePrintfVerb parses the leading printf verb in f. The opening
94 // "%" must already be trimmed from f. prevIdx is the previous
95 // operand's index, or zero if this is the first verb. The format
96 // string is returned with the leading verb removed. Multiple operands
97 // can be returned in the case of dynamic widths such as "%*.*f".
98 func parsePrintfVerb(f string, prevIdx int) (string, []formatOperand) {
99         var verbs []formatOperand
100
101         addVerb := func(k objKind) {
102                 verbs = append(verbs, formatOperand{
103                         idx:  prevIdx + 1,
104                         kind: k,
105                 })
106                 prevIdx++
107         }
108
109         for len(f) > 0 {
110                 // Trim first rune off of f so we are guaranteed to make progress.
111                 r, l := utf8.DecodeRuneInString(f)
112                 f = f[l:]
113
114                 // We care about three things:
115                 // 1. The verb, which maps directly to object kind.
116                 // 2. Explicit operand indices like "%[2]s".
117                 // 3. Dynamic widths using "*".
118                 switch r {
119                 case '%':
120                         return f, nil
121                 case '*':
122                         addVerb(kindInt)
123                         continue
124                 case '[':
125                         // Parse operand index as in "%[2]s".
126                         i := strings.Index(f, "]")
127                         if i == -1 {
128                                 return f, nil
129                         }
130
131                         idx, err := strconv.Atoi(f[:i])
132                         f = f[i+1:]
133                         if err != nil {
134                                 return f, nil
135                         }
136
137                         prevIdx = idx - 1
138                         continue
139                 case 'v', 'T':
140                         addVerb(kindAny)
141                 case 't':
142                         addVerb(kindBool)
143                 case 'c', 'd', 'o', 'O', 'U':
144                         addVerb(kindInt)
145                 case 'e', 'E', 'f', 'F', 'g', 'G':
146                         addVerb(kindFloat | kindComplex)
147                 case 'b':
148                         addVerb(kindInt | kindFloat | kindComplex | kindBytes)
149                 case 'q', 's':
150                         addVerb(kindString | kindBytes | kindStringer | kindError)
151                 case 'x', 'X':
152                         // Omit kindStringer and kindError though technically allowed.
153                         addVerb(kindString | kindBytes | kindInt | kindFloat | kindComplex)
154                 case 'p':
155                         addVerb(kindPtr | kindSlice)
156                 case 'w':
157                         addVerb(kindError)
158                 case '+', '-', '#', ' ', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
159                         // Flag or numeric width/precicision value.
160                         continue
161                 default:
162                         // Assume unrecognized rune is a custom fmt.Formatter verb.
163                         addVerb(kindAny)
164                 }
165
166                 if len(verbs) > 0 {
167                         break
168                 }
169         }
170
171         return f, verbs
172 }