blob: 38d6f72419ba19fb0709249faed58ac85e6e8a5c [file] [log] [blame]
Robert Griesemer1b8b2c12015-06-04 12:54:58 -07001// Copyright 2010 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// This file contains the printf-checker.
6
7package main
8
9import (
10 "bytes"
11 "flag"
Russ Coxfc768da2017-10-29 15:18:52 -040012 "fmt"
Robert Griesemer1b8b2c12015-06-04 12:54:58 -070013 "go/ast"
Robert Griesemera7d2d482015-06-04 13:07:22 -070014 "go/constant"
Robert Griesemer1b8b2c12015-06-04 12:54:58 -070015 "go/token"
Robert Griesemera7d2d482015-06-04 13:07:22 -070016 "go/types"
Russ Coxfc768da2017-10-29 15:18:52 -040017 "regexp"
Robert Griesemer1b8b2c12015-06-04 12:54:58 -070018 "strconv"
19 "strings"
20 "unicode/utf8"
Robert Griesemer1b8b2c12015-06-04 12:54:58 -070021)
22
23var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
24
25func init() {
26 register("printf",
27 "check printf-like invocations",
28 checkFmtPrintfCall,
29 funcDecl, callExpr)
30}
31
32func initPrintFlags() {
33 if *printfuncs == "" {
34 return
35 }
36 for _, name := range strings.Split(*printfuncs, ",") {
37 if len(name) == 0 {
38 flag.Usage()
39 }
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +030040
41 // Backwards compatibility: skip optional first argument
42 // index after the colon.
Marvin Stengerd153df82017-10-05 15:50:11 +020043 if colon := strings.LastIndex(name, ":"); colon > 0 {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -070044 name = name[:colon]
45 }
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +030046
Russ Cox558eeb22017-12-13 14:45:50 -050047 isPrint[strings.ToLower(name)] = true
Robert Griesemer1b8b2c12015-06-04 12:54:58 -070048 }
49}
50
Russ Cox558eeb22017-12-13 14:45:50 -050051// TODO(rsc): Incorporate user-defined printf wrappers again.
52// The general plan is to allow vet of one package P to output
53// additional information to supply to later vets of packages
54// importing P. Then vet of P can record a list of printf wrappers
55// and the later vet using P.Printf will find it in the list and check it.
56// That's not ready for Go 1.10.
57// When that does happen, uncomment the user-defined printf
58// wrapper tests in testdata/print.go.
Robert Griesemer1b8b2c12015-06-04 12:54:58 -070059
Russ Cox558eeb22017-12-13 14:45:50 -050060// isPrint records the print functions.
61// If a key ends in 'f' then it is assumed to be a formatted print.
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +030062var isPrint = map[string]bool{
Russ Cox558eeb22017-12-13 14:45:50 -050063 "fmt.Errorf": true,
64 "fmt.Fprint": true,
65 "fmt.Fprintf": true,
66 "fmt.Fprintln": true,
67 "fmt.Print": true,
68 "fmt.Printf": true,
69 "fmt.Println": true,
70 "fmt.Sprint": true,
71 "fmt.Sprintf": true,
72 "fmt.Sprintln": true,
73 "log.Fatal": true,
74 "log.Fatalf": true,
75 "log.Fatalln": true,
76 "log.Logger.Fatal": true,
77 "log.Logger.Fatalf": true,
78 "log.Logger.Fatalln": true,
79 "log.Logger.Panic": true,
80 "log.Logger.Panicf": true,
81 "log.Logger.Panicln": true,
82 "log.Logger.Printf": true,
83 "log.Logger.Println": true,
84 "log.Panic": true,
85 "log.Panicf": true,
86 "log.Panicln": true,
87 "log.Print": true,
88 "log.Printf": true,
89 "log.Println": true,
90 "testing.B.Error": true,
91 "testing.B.Errorf": true,
92 "testing.B.Fatal": true,
93 "testing.B.Fatalf": true,
94 "testing.B.Log": true,
95 "testing.B.Logf": true,
96 "testing.B.Skip": true,
97 "testing.B.Skipf": true,
98 "testing.T.Error": true,
99 "testing.T.Errorf": true,
100 "testing.T.Fatal": true,
101 "testing.T.Fatalf": true,
102 "testing.T.Log": true,
103 "testing.T.Logf": true,
104 "testing.T.Skip": true,
105 "testing.T.Skipf": true,
106 "testing.TB.Error": true,
107 "testing.TB.Errorf": true,
108 "testing.TB.Fatal": true,
109 "testing.TB.Fatalf": true,
110 "testing.TB.Log": true,
111 "testing.TB.Logf": true,
112 "testing.TB.Skip": true,
113 "testing.TB.Skipf": true,
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700114}
115
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200116// formatString returns the format string argument and its index within
117// the given printf-like call expression.
118//
119// The last parameter before variadic arguments is assumed to be
120// a format string.
121//
122// The first string literal or string constant is assumed to be a format string
123// if the call's signature cannot be determined.
124//
Russ Coxfc768da2017-10-29 15:18:52 -0400125// If it cannot find any format string parameter, it returns ("", -1).
126func formatString(f *File, call *ast.CallExpr) (format string, idx int) {
Spencer Nelson867910e2016-03-02 15:29:30 -0500127 typ := f.pkg.types[call.Fun].Type
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200128 if typ != nil {
129 if sig, ok := typ.(*types.Signature); ok {
130 if !sig.Variadic() {
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300131 // Skip checking non-variadic functions.
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200132 return "", -1
133 }
134 idx := sig.Params().Len() - 2
135 if idx < 0 {
136 // Skip checking variadic functions without
137 // fixed arguments.
138 return "", -1
139 }
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300140 s, ok := stringConstantArg(f, call, idx)
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200141 if !ok {
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300142 // The last argument before variadic args isn't a string.
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200143 return "", -1
144 }
145 return s, idx
Spencer Nelson867910e2016-03-02 15:29:30 -0500146 }
147 }
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200148
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300149 // Cannot determine call's signature. Fall back to scanning for the first
150 // string constant in the call.
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200151 for idx := range call.Args {
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300152 if s, ok := stringConstantArg(f, call, idx); ok {
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200153 return s, idx
154 }
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300155 if f.pkg.types[call.Args[idx]].Type == types.Typ[types.String] {
156 // Skip checking a call with a non-constant format
157 // string argument, since its contents are unavailable
158 // for validation.
159 return "", -1
160 }
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200161 }
162 return "", -1
163}
164
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300165// stringConstantArg returns call's string constant argument at the index idx.
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200166//
167// ("", false) is returned if call's argument at the index idx isn't a string
Aliaksandr Valialkinee8ec422016-09-10 17:04:41 +0300168// constant.
169func stringConstantArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200170 if idx >= len(call.Args) {
171 return "", false
172 }
173 arg := call.Args[idx]
174 lit := f.pkg.types[arg].Value
175 if lit != nil && lit.Kind() == constant.String {
176 return constant.StringVal(lit), true
177 }
178 return "", false
Spencer Nelson867910e2016-03-02 15:29:30 -0500179}
180
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700181// checkCall triggers the print-specific checks if the call invokes a print function.
182func checkFmtPrintfCall(f *File, node ast.Node) {
Russ Cox558eeb22017-12-13 14:45:50 -0500183 if f.pkg.typesPkg == nil {
184 // This check now requires type information.
185 return
186 }
187
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700188 if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) {
189 // Remember we saw this.
Daniel Martí1f859172018-01-29 09:50:50 +0000190 if f.stringerPtrs == nil {
191 f.stringerPtrs = make(map[*ast.Object]bool)
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700192 }
193 if l := d.Recv.List; len(l) == 1 {
194 if n := l[0].Names; len(n) == 1 {
Daniel Martí1f859172018-01-29 09:50:50 +0000195 typ := f.pkg.types[l[0].Type]
196 _, ptrRecv := typ.Type.(*types.Pointer)
197 f.stringerPtrs[n[0].Obj] = ptrRecv
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700198 }
199 }
200 return
201 }
202
203 call, ok := node.(*ast.CallExpr)
204 if !ok {
205 return
206 }
Russ Cox558eeb22017-12-13 14:45:50 -0500207
208 // Construct name like pkg.Printf or pkg.Type.Printf for lookup.
209 var name string
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700210 switch x := call.Fun.(type) {
211 case *ast.Ident:
Russ Cox558eeb22017-12-13 14:45:50 -0500212 if fn, ok := f.pkg.uses[x].(*types.Func); ok {
213 var pkg string
214 if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg {
215 pkg = vcfg.ImportPath
216 } else {
217 pkg = fn.Pkg().Path()
218 }
219 name = pkg + "." + x.Name
220 break
221 }
222
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700223 case *ast.SelectorExpr:
Russ Cox558eeb22017-12-13 14:45:50 -0500224 // Check for "fmt.Printf".
225 if id, ok := x.X.(*ast.Ident); ok {
226 if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok {
227 name = pkgName.Imported().Path() + "." + x.Sel.Name
228 break
229 }
230 }
231
232 // Check for t.Logf where t is a *testing.T.
233 if sel := f.pkg.selectors[x]; sel != nil {
234 recv := sel.Recv()
235 if p, ok := recv.(*types.Pointer); ok {
236 recv = p.Elem()
237 }
238 if named, ok := recv.(*types.Named); ok {
239 obj := named.Obj()
240 var pkg string
241 if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg {
242 pkg = vcfg.ImportPath
243 } else {
244 pkg = obj.Pkg().Path()
245 }
246 name = pkg + "." + obj.Name() + "." + x.Sel.Name
247 break
248 }
249 }
250 }
251 if name == "" {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700252 return
253 }
254
Russ Cox558eeb22017-12-13 14:45:50 -0500255 shortName := name[strings.LastIndex(name, ".")+1:]
256
257 _, ok = isPrint[name]
258 if !ok {
259 // Next look up just "printf", for use with -printfuncs.
260 _, ok = isPrint[strings.ToLower(shortName)]
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700261 }
Russ Cox558eeb22017-12-13 14:45:50 -0500262 if ok {
263 if strings.HasSuffix(name, "f") {
264 f.checkPrintf(call, shortName)
265 } else {
266 f.checkPrint(call, shortName)
267 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700268 }
269}
270
271// isStringer returns true if the provided declaration is a "String() string"
272// method, an implementation of fmt.Stringer.
273func isStringer(f *File, d *ast.FuncDecl) bool {
274 return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil &&
275 len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 &&
276 f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String]
277}
278
Dhananjay Nakrani662d2532016-11-06 19:56:14 -0800279// isFormatter reports whether t satisfies fmt.Formatter.
280// Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt.
281func (f *File) isFormatter(t types.Type) bool {
282 return formatterType != nil && types.Implements(t, formatterType)
283}
284
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700285// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
286// It is constructed by parsePrintfVerb.
287type formatState struct {
288 verb rune // the format verb: 'd' for "%d"
289 format string // the full format directive from % through verb, "%.3d".
290 name string // Printf, Sprintf etc.
291 flags []byte // the list of # + etc.
292 argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700293 firstArg int // Index of first argument after the format in the Printf call.
294 // Used only during parse.
295 file *File
296 call *ast.CallExpr
297 argNum int // Which argument we're expecting to format now.
Daniel Martí14f80272018-01-29 10:35:39 +0000298 hasIndex bool // Whether the argument is indexed.
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700299 indexPending bool // Whether we have an indexed argument that has not resolved.
300 nbytes int // number of bytes of the format string consumed.
301}
302
303// checkPrintf checks a call to a formatted print routine such as Printf.
Spencer Nelson867910e2016-03-02 15:29:30 -0500304func (f *File) checkPrintf(call *ast.CallExpr, name string) {
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200305 format, idx := formatString(f, call)
Spencer Nelson867910e2016-03-02 15:29:30 -0500306 if idx < 0 {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700307 if *verbose {
308 f.Warn(call.Pos(), "can't check non-constant format in call to", name)
309 }
310 return
311 }
Aliaksandr Valialkinee1b90a2016-03-22 15:38:21 +0200312
Spencer Nelson867910e2016-03-02 15:29:30 -0500313 firstArg := idx + 1 // Arguments are immediately after format string.
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700314 if !strings.Contains(format, "%") {
315 if len(call.Args) > firstArg {
Russ Coxfc768da2017-10-29 15:18:52 -0400316 f.Badf(call.Pos(), "%s call has arguments but no formatting directives", name)
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700317 }
318 return
319 }
320 // Hard part: check formats against args.
321 argNum := firstArg
Aliaksandr Valialkinc9fbe0f2016-06-23 14:59:26 +0300322 maxArgNum := firstArg
Daniel Martí14f80272018-01-29 10:35:39 +0000323 anyIndex := false
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700324 for i, w := 0, 0; i < len(format); i += w {
325 w = 1
Daniel Martí38ad3302017-09-06 21:59:00 +0200326 if format[i] != '%' {
327 continue
328 }
329 state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum)
330 if state == nil {
331 return
332 }
333 w = len(state.format)
334 if !f.okPrintfArg(call, state) { // One error per format is enough.
335 return
336 }
Daniel Martí14f80272018-01-29 10:35:39 +0000337 if state.hasIndex {
338 anyIndex = true
339 }
Daniel Martí38ad3302017-09-06 21:59:00 +0200340 if len(state.argNums) > 0 {
341 // Continue with the next sequential argument.
342 argNum = state.argNums[len(state.argNums)-1] + 1
343 }
344 for _, n := range state.argNums {
345 if n >= maxArgNum {
346 maxArgNum = n + 1
Aliaksandr Valialkinc9fbe0f2016-06-23 14:59:26 +0300347 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700348 }
349 }
350 // Dotdotdot is hard.
Aliaksandr Valialkinc9fbe0f2016-06-23 14:59:26 +0300351 if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700352 return
353 }
Daniel Martí14f80272018-01-29 10:35:39 +0000354 // If any formats are indexed, extra arguments are ignored.
355 if anyIndex {
356 return
357 }
Aliaksandr Valialkinc9fbe0f2016-06-23 14:59:26 +0300358 // There should be no leftover arguments.
359 if maxArgNum != len(call.Args) {
360 expect := maxArgNum - firstArg
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700361 numArgs := len(call.Args) - firstArg
Russ Coxfc768da2017-10-29 15:18:52 -0400362 f.Badf(call.Pos(), "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg"))
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700363 }
364}
365
366// parseFlags accepts any printf flags.
367func (s *formatState) parseFlags() {
368 for s.nbytes < len(s.format) {
369 switch c := s.format[s.nbytes]; c {
370 case '#', '0', '+', '-', ' ':
371 s.flags = append(s.flags, c)
372 s.nbytes++
373 default:
374 return
375 }
376 }
377}
378
379// scanNum advances through a decimal number if present.
380func (s *formatState) scanNum() {
381 for ; s.nbytes < len(s.format); s.nbytes++ {
382 c := s.format[s.nbytes]
383 if c < '0' || '9' < c {
384 return
385 }
386 }
387}
388
389// parseIndex scans an index expression. It returns false if there is a syntax error.
390func (s *formatState) parseIndex() bool {
391 if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' {
392 return true
393 }
394 // Argument index present.
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700395 s.nbytes++ // skip '['
396 start := s.nbytes
397 s.scanNum()
Russ Coxfc768da2017-10-29 15:18:52 -0400398 ok := true
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700399 if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
Russ Coxfc768da2017-10-29 15:18:52 -0400400 ok = false
401 s.nbytes = strings.Index(s.format, "]")
402 if s.nbytes < 0 {
403 s.file.Badf(s.call.Pos(), "%s format %s is missing closing ]", s.name, s.format)
404 return false
Aliaksandr Valialkinc9fbe0f2016-06-23 14:59:26 +0300405 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700406 }
407 arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
Russ Coxfc768da2017-10-29 15:18:52 -0400408 if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) {
409 s.file.Badf(s.call.Pos(), "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes])
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700410 return false
411 }
412 s.nbytes++ // skip ']'
413 arg := int(arg32)
414 arg += s.firstArg - 1 // We want to zero-index the actual arguments.
415 s.argNum = arg
Daniel Martí14f80272018-01-29 10:35:39 +0000416 s.hasIndex = true
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700417 s.indexPending = true
418 return true
419}
420
421// parseNum scans a width or precision (or *). It returns false if there's a bad index expression.
422func (s *formatState) parseNum() bool {
423 if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' {
424 if s.indexPending { // Absorb it.
425 s.indexPending = false
426 }
427 s.nbytes++
428 s.argNums = append(s.argNums, s.argNum)
429 s.argNum++
430 } else {
431 s.scanNum()
432 }
433 return true
434}
435
436// parsePrecision scans for a precision. It returns false if there's a bad index expression.
437func (s *formatState) parsePrecision() bool {
438 // If there's a period, there may be a precision.
439 if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' {
440 s.flags = append(s.flags, '.') // Treat precision as a flag.
441 s.nbytes++
442 if !s.parseIndex() {
443 return false
444 }
445 if !s.parseNum() {
446 return false
447 }
448 }
449 return true
450}
451
452// parsePrintfVerb looks the formatting directive that begins the format string
453// and returns a formatState that encodes what the directive wants, without looking
454// at the actual arguments present in the call. The result is nil if there is an error.
455func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
456 state := &formatState{
457 format: format,
458 name: name,
459 flags: make([]byte, 0, 5),
460 argNum: argNum,
461 argNums: make([]int, 0, 1),
462 nbytes: 1, // There's guaranteed to be a percent sign.
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700463 firstArg: firstArg,
464 file: f,
465 call: call,
466 }
467 // There may be flags.
468 state.parseFlags()
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700469 // There may be an index.
470 if !state.parseIndex() {
471 return nil
472 }
473 // There may be a width.
474 if !state.parseNum() {
475 return nil
476 }
477 // There may be a precision.
478 if !state.parsePrecision() {
479 return nil
480 }
481 // Now a verb, possibly prefixed by an index (which we may already have).
Aliaksandr Valialkinc9fbe0f2016-06-23 14:59:26 +0300482 if !state.indexPending && !state.parseIndex() {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700483 return nil
484 }
485 if state.nbytes == len(state.format) {
Russ Coxfc768da2017-10-29 15:18:52 -0400486 f.Badf(call.Pos(), "%s format %s is missing verb at end of string", name, state.format)
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700487 return nil
488 }
489 verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
490 state.verb = verb
491 state.nbytes += w
492 if verb != '%' {
493 state.argNums = append(state.argNums, state.argNum)
494 }
495 state.format = state.format[:state.nbytes]
496 return state
497}
498
499// printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.
500type printfArgType int
501
502const (
503 argBool printfArgType = 1 << iota
504 argInt
505 argRune
506 argString
507 argFloat
508 argComplex
509 argPointer
510 anyType printfArgType = ^0
511)
512
513type printVerb struct {
514 verb rune // User may provide verb through Formatter; could be a rune.
515 flags string // known flags are all ASCII
516 typ printfArgType
517}
518
519// Common flag sets for printf verbs.
520const (
521 noFlag = ""
522 numFlag = " -+.0"
523 sharpNumFlag = " -+.0#"
524 allFlags = " -+.0#"
525)
526
527// printVerbs identifies which flags are known to printf for each verb.
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700528var printVerbs = []printVerb{
529 // '-' is a width modifier, always valid.
530 // '.' is a precision for float, max width for strings.
531 // '+' is required sign for numbers, Go format for %v.
532 // '#' is alternate format for several verbs.
533 // ' ' is spacer for numbers
534 {'%', noFlag, 0},
535 {'b', numFlag, argInt | argFloat | argComplex},
536 {'c', "-", argRune | argInt},
537 {'d', numFlag, argInt},
Alan Donovan7159ab42017-09-08 14:45:59 -0400538 {'e', sharpNumFlag, argFloat | argComplex},
539 {'E', sharpNumFlag, argFloat | argComplex},
540 {'f', sharpNumFlag, argFloat | argComplex},
541 {'F', sharpNumFlag, argFloat | argComplex},
542 {'g', sharpNumFlag, argFloat | argComplex},
543 {'G', sharpNumFlag, argFloat | argComplex},
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700544 {'o', sharpNumFlag, argInt},
545 {'p', "-#", argPointer},
546 {'q', " -+.0#", argRune | argInt | argString},
547 {'s', " -+.0", argString},
548 {'t', "-", argBool},
549 {'T', "-", anyType},
550 {'U', "-#", argRune | argInt},
551 {'v', allFlags, anyType},
552 {'x', sharpNumFlag, argRune | argInt | argString},
553 {'X', sharpNumFlag, argRune | argInt | argString},
554}
555
556// okPrintfArg compares the formatState to the arguments actually present,
557// reporting any discrepancies it can discern. If the final argument is ellipsissed,
558// there's little it can do for that.
559func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
560 var v printVerb
561 found := false
562 // Linear scan is fast enough for a small list.
563 for _, v = range printVerbs {
564 if v.verb == state.verb {
565 found = true
566 break
567 }
568 }
Dhananjay Nakrani662d2532016-11-06 19:56:14 -0800569
570 // Does current arg implement fmt.Formatter?
571 formatter := false
572 if state.argNum < len(call.Args) {
573 if tv, ok := f.pkg.types[call.Args[state.argNum]]; ok {
574 formatter = f.isFormatter(tv.Type)
575 }
576 }
577
Chris Hines51032702017-11-12 00:31:52 -0500578 if !formatter {
579 if !found {
580 f.Badf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb)
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700581 return false
582 }
Chris Hines51032702017-11-12 00:31:52 -0500583 for _, flag := range state.flags {
Rob Pike8c1f21d2018-01-30 13:49:48 +1100584 // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
585 // See issues 23598 and 23605.
586 if flag == '0' {
587 continue
588 }
Chris Hines51032702017-11-12 00:31:52 -0500589 if !strings.ContainsRune(v.flags, rune(flag)) {
590 f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag)
591 return false
592 }
593 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700594 }
595 // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all
596 // but the final arg must be an integer.
597 trueArgs := 1
598 if state.verb == '%' {
599 trueArgs = 0
600 }
601 nargs := len(state.argNums)
602 for i := 0; i < nargs-trueArgs; i++ {
603 argNum := state.argNums[i]
Daniel Martí38ad3302017-09-06 21:59:00 +0200604 if !f.argCanBeChecked(call, i, state) {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700605 return
606 }
607 arg := call.Args[argNum]
608 if !f.matchArgType(argInt, nil, arg) {
Russ Coxfc768da2017-10-29 15:18:52 -0400609 f.Badf(call.Pos(), "%s format %s uses non-int %s as argument of *", state.name, state.format, f.gofmt(arg))
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700610 return false
611 }
612 }
Dhananjay Nakrani662d2532016-11-06 19:56:14 -0800613 if state.verb == '%' || formatter {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700614 return true
615 }
616 argNum := state.argNums[len(state.argNums)-1]
Daniel Martí38ad3302017-09-06 21:59:00 +0200617 if !f.argCanBeChecked(call, len(state.argNums)-1, state) {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700618 return false
619 }
620 arg := call.Args[argNum]
Russ Cox0f89efa2016-01-29 10:16:24 -0500621 if f.isFunctionValue(arg) && state.verb != 'p' && state.verb != 'T' {
Russ Coxfc768da2017-10-29 15:18:52 -0400622 f.Badf(call.Pos(), "%s format %s arg %s is a func value, not called", state.name, state.format, f.gofmt(arg))
Russ Cox0f89efa2016-01-29 10:16:24 -0500623 return false
624 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700625 if !f.matchArgType(v.typ, nil, arg) {
626 typeString := ""
627 if typ := f.pkg.types[arg].Type; typ != nil {
628 typeString = typ.String()
629 }
Russ Coxfc768da2017-10-29 15:18:52 -0400630 f.Badf(call.Pos(), "%s format %s has arg %s of wrong type %s", state.name, state.format, f.gofmt(arg), typeString)
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700631 return false
632 }
633 if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) {
Russ Coxfc768da2017-10-29 15:18:52 -0400634 f.Badf(call.Pos(), "%s format %s with arg %s causes recursive String method call", state.name, state.format, f.gofmt(arg))
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700635 return false
636 }
637 return true
638}
639
640// recursiveStringer reports whether the provided argument is r or &r for the
641// fmt.Stringer receiver identifier r.
642func (f *File) recursiveStringer(e ast.Expr) bool {
Daniel Martí1f859172018-01-29 09:50:50 +0000643 if len(f.stringerPtrs) == 0 {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700644 return false
645 }
Daniel Martí1f859172018-01-29 09:50:50 +0000646 ptr := false
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700647 var obj *ast.Object
648 switch e := e.(type) {
649 case *ast.Ident:
650 obj = e.Obj
651 case *ast.UnaryExpr:
652 if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND {
653 obj = id.Obj
Daniel Martí1f859172018-01-29 09:50:50 +0000654 ptr = true
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700655 }
656 }
657
658 // It's unlikely to be a recursive stringer if it has a Format method.
659 if typ := f.pkg.types[e].Type; typ != nil {
Daniel Martíc0b248c2018-01-31 20:53:44 +0000660 if f.isFormatter(typ) {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700661 return false
662 }
663 }
664
665 // We compare the underlying Object, which checks that the identifier
666 // is the one we declared as the receiver for the String method in
667 // which this printf appears.
Daniel Martí1f859172018-01-29 09:50:50 +0000668 ptrRecv, exist := f.stringerPtrs[obj]
669 if !exist {
670 return false
671 }
672 // We also need to check that using &t when we declared String
673 // on (t *T) is ok; in such a case, the address is printed.
674 if ptr && ptrRecv {
675 return false
676 }
677 return true
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700678}
679
Rob Pike43a7a9c2015-08-31 14:36:36 -0700680// isFunctionValue reports whether the expression is a function as opposed to a function call.
681// It is almost always a mistake to print a function value.
682func (f *File) isFunctionValue(e ast.Expr) bool {
683 if typ := f.pkg.types[e].Type; typ != nil {
684 _, ok := typ.(*types.Signature)
685 return ok
686 }
687 return false
688}
689
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700690// argCanBeChecked reports whether the specified argument is statically present;
691// it may be beyond the list of arguments or in a terminal slice... argument, which
692// means we can't see it.
Daniel Martí38ad3302017-09-06 21:59:00 +0200693func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, state *formatState) bool {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700694 argNum := state.argNums[formatArg]
Russ Coxfc768da2017-10-29 15:18:52 -0400695 if argNum <= 0 {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700696 // Shouldn't happen, so catch it with prejudice.
697 panic("negative arg num")
698 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700699 if argNum < len(call.Args)-1 {
700 return true // Always OK.
701 }
702 if call.Ellipsis.IsValid() {
703 return false // We just can't tell; there could be many more arguments.
704 }
705 if argNum < len(call.Args) {
706 return true
707 }
708 // There are bad indexes in the format or there are fewer arguments than the format needs.
709 // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
710 arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
Russ Coxfc768da2017-10-29 15:18:52 -0400711 f.Badf(call.Pos(), "%s format %s reads arg #%d, but call has only %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700712 return false
713}
714
Russ Coxfc768da2017-10-29 15:18:52 -0400715// printFormatRE is the regexp we match and report as a possible format string
716// in the first argument to unformatted prints like fmt.Print.
717// We exclude the space flag, so that printing a string like "x % y" is not reported as a format.
718var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE)
719
720const (
721 flagsRE = `[+\-#]*`
722 indexOptRE = `(\[[0-9]+\])?`
723 numOptRE = `([0-9]+|` + indexOptRE + `\*)?`
Daniel Martí88599f12017-11-22 18:21:39 +0000724 verbRE = `[bcdefgopqstvxEFGUX]`
Russ Coxfc768da2017-10-29 15:18:52 -0400725)
726
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700727// checkPrint checks a call to an unformatted print routine such as Println.
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +0300728func (f *File) checkPrint(call *ast.CallExpr, name string) {
729 firstArg := 0
730 typ := f.pkg.types[call.Fun].Type
Aliaksandr Valialkindcc42c72016-05-24 13:53:44 +0300731 if typ == nil {
732 // Skip checking functions with unknown type.
733 return
734 }
735 if sig, ok := typ.(*types.Signature); ok {
736 if !sig.Variadic() {
737 // Skip checking non-variadic functions.
738 return
739 }
740 params := sig.Params()
741 firstArg = params.Len() - 1
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +0300742
Aliaksandr Valialkindcc42c72016-05-24 13:53:44 +0300743 typ := params.At(firstArg).Type()
744 typ = typ.(*types.Slice).Elem()
745 it, ok := typ.(*types.Interface)
746 if !ok || !it.Empty() {
747 // Skip variadic functions accepting non-interface{} args.
748 return
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700749 }
750 }
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +0300751 args := call.Args
752 if len(args) <= firstArg {
753 // Skip calls without variadic args.
754 return
755 }
756 args = args[firstArg:]
757
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +0300758 if firstArg == 0 {
Russ Coxfc768da2017-10-29 15:18:52 -0400759 if sel, ok := call.Args[0].(*ast.SelectorExpr); ok {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700760 if x, ok := sel.X.(*ast.Ident); ok {
761 if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
Russ Coxfc768da2017-10-29 15:18:52 -0400762 f.Badf(call.Pos(), "%s does not take io.Writer but has first arg %s", name, f.gofmt(call.Args[0]))
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700763 }
764 }
765 }
766 }
Russ Coxfc768da2017-10-29 15:18:52 -0400767
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +0300768 arg := args[0]
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700769 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
Josh Bleecher Snyder6ad76712016-07-07 17:40:37 -0700770 // Ignore trailing % character in lit.Value.
771 // The % in "abc 0.0%" couldn't be a formatting directive.
772 s := strings.TrimSuffix(lit.Value, `%"`)
773 if strings.Contains(s, "%") {
Russ Coxfc768da2017-10-29 15:18:52 -0400774 m := printFormatRE.FindStringSubmatch(s)
775 if m != nil {
776 f.Badf(call.Pos(), "%s call has possible formatting directive %s", name, m[0])
777 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700778 }
779 }
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +0300780 if strings.HasSuffix(name, "ln") {
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700781 // The last item, if a string, should not have a newline.
Aliaksandr Valialkind7ddee72016-04-05 18:42:07 +0300782 arg = args[len(args)-1]
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700783 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
Daniel Martí366681c2017-11-07 11:34:35 +0000784 str, _ := strconv.Unquote(lit.Value)
785 if strings.HasSuffix(str, "\n") {
786 f.Badf(call.Pos(), "%s arg list ends with redundant newline", name)
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700787 }
788 }
789 }
790 for _, arg := range args {
Rob Pike43a7a9c2015-08-31 14:36:36 -0700791 if f.isFunctionValue(arg) {
Russ Coxfc768da2017-10-29 15:18:52 -0400792 f.Badf(call.Pos(), "%s arg %s is a func value, not called", name, f.gofmt(arg))
Rob Pike43a7a9c2015-08-31 14:36:36 -0700793 }
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700794 if f.recursiveStringer(arg) {
Russ Coxfc768da2017-10-29 15:18:52 -0400795 f.Badf(call.Pos(), "%s arg %s causes recursive call to String method", name, f.gofmt(arg))
Robert Griesemer1b8b2c12015-06-04 12:54:58 -0700796 }
797 }
798}
Russ Coxfc768da2017-10-29 15:18:52 -0400799
800// count(n, what) returns "1 what" or "N whats"
801// (assuming the plural of what is whats).
802func count(n int, what string) string {
803 if n == 1 {
804 return "1 " + what
805 }
806 return fmt.Sprintf("%d %ss", n, what)
807}