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.
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") {
26 sig, _ := fn.Type().(*types.Signature)
31 // Must be variadic and take at least two params.
32 numParams := sig.Params().Len()
33 if !sig.Variadic() || numParams < 2 || argIdx < numParams-1 {
37 // Param preceding variadic args must be a (format) string.
38 if !types.Identical(sig.Params().At(numParams-2).Type(), types.Typ[types.String]) {
42 // Format string must be a constant.
43 strArg := info.Types[call.Args[numParams-2]].Value
44 if strArg == nil || strArg.Kind() != constant.String {
48 return formatOperandKind(constant.StringVal(strArg), argIdx-(numParams-1)+1)
51 // formatOperandKind returns the objKind corresponding to format's
52 // operandIdx'th operand.
53 func formatOperandKind(format string, operandIdx int) objKind {
59 i := strings.Index(format, "%")
64 var operands []formatOperand
65 format, operands = parsePrintfVerb(format[i+1:], prevOperandIdx)
67 // Check if any this verb's operands correspond to our target
69 for _, v := range operands {
70 if v.idx == operandIdx {
73 } else if v.kind != kindAny {
74 // If mulitple verbs refer to the same operand, take the
75 // intersection of their kinds.
80 prevOperandIdx = v.idx
86 type formatOperand struct {
87 // idx is the one-based printf operand index.
89 // kind is a mask of expected kinds of objects for this operand.
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
101 addVerb := func(k objKind) {
102 verbs = append(verbs, formatOperand{
110 // Trim first rune off of f so we are guaranteed to make progress.
111 r, l := utf8.DecodeRuneInString(f)
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 "*".
125 // Parse operand index as in "%[2]s".
126 i := strings.Index(f, "]")
131 idx, err := strconv.Atoi(f[:i])
143 case 'c', 'd', 'o', 'O', 'U':
145 case 'e', 'E', 'f', 'F', 'g', 'G':
146 addVerb(kindFloat | kindComplex)
148 addVerb(kindInt | kindFloat | kindComplex | kindBytes)
150 addVerb(kindString | kindBytes | kindStringer | kindError)
152 // Omit kindStringer and kindError though technically allowed.
153 addVerb(kindString | kindBytes | kindInt | kindFloat | kindComplex)
155 addVerb(kindPtr | kindSlice)
158 case '+', '-', '#', ' ', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
159 // Flag or numeric width/precicision value.
162 // Assume unrecognized rune is a custom fmt.Formatter verb.