github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/analysis/passes/printf/printf.go (about) 1 // 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 // Package printf defines an Analyzer that checks consistency 6 // of Printf format strings and arguments. 7 package printf 8 9 import ( 10 "bytes" 11 "fmt" 12 "go/ast" 13 "go/constant" 14 "go/token" 15 "go/types" 16 "reflect" 17 "regexp" 18 "sort" 19 "strconv" 20 "strings" 21 "unicode/utf8" 22 23 "golang.org/x/tools/go/analysis" 24 "golang.org/x/tools/go/analysis/passes/inspect" 25 "golang.org/x/tools/go/analysis/passes/internal/analysisutil" 26 "golang.org/x/tools/go/ast/inspector" 27 "golang.org/x/tools/go/types/typeutil" 28 "golang.org/x/tools/internal/typeparams" 29 ) 30 31 func init() { 32 Analyzer.Flags.Var(isPrint, "funcs", "comma-separated list of print function names to check") 33 } 34 35 var Analyzer = &analysis.Analyzer{ 36 Name: "printf", 37 Doc: Doc, 38 Requires: []*analysis.Analyzer{inspect.Analyzer}, 39 Run: run, 40 ResultType: reflect.TypeOf((*Result)(nil)), 41 FactTypes: []analysis.Fact{new(isWrapper)}, 42 } 43 44 const Doc = `check consistency of Printf format strings and arguments 45 46 The check applies to known functions (for example, those in package fmt) 47 as well as any detected wrappers of known functions. 48 49 A function that wants to avail itself of printf checking but is not 50 found by this analyzer's heuristics (for example, due to use of 51 dynamic calls) can insert a bogus call: 52 53 if false { 54 _ = fmt.Sprintf(format, args...) // enable printf checking 55 } 56 57 The -funcs flag specifies a comma-separated list of names of additional 58 known formatting functions or methods. If the name contains a period, 59 it must denote a specific function using one of the following forms: 60 61 dir/pkg.Function 62 dir/pkg.Type.Method 63 (*dir/pkg.Type).Method 64 65 Otherwise the name is interpreted as a case-insensitive unqualified 66 identifier such as "errorf". Either way, if a listed name ends in f, the 67 function is assumed to be Printf-like, taking a format string before the 68 argument list. Otherwise it is assumed to be Print-like, taking a list 69 of arguments with no format string. 70 ` 71 72 // Kind is a kind of fmt function behavior. 73 type Kind int 74 75 const ( 76 KindNone Kind = iota // not a fmt wrapper function 77 KindPrint // function behaves like fmt.Print 78 KindPrintf // function behaves like fmt.Printf 79 KindErrorf // function behaves like fmt.Errorf 80 ) 81 82 func (kind Kind) String() string { 83 switch kind { 84 case KindPrint: 85 return "print" 86 case KindPrintf: 87 return "printf" 88 case KindErrorf: 89 return "errorf" 90 } 91 return "" 92 } 93 94 // Result is the printf analyzer's result type. Clients may query the result 95 // to learn whether a function behaves like fmt.Print or fmt.Printf. 96 type Result struct { 97 funcs map[*types.Func]Kind 98 } 99 100 // Kind reports whether fn behaves like fmt.Print or fmt.Printf. 101 func (r *Result) Kind(fn *types.Func) Kind { 102 _, ok := isPrint[fn.FullName()] 103 if !ok { 104 // Next look up just "printf", for use with -printf.funcs. 105 _, ok = isPrint[strings.ToLower(fn.Name())] 106 } 107 if ok { 108 if strings.HasSuffix(fn.Name(), "f") { 109 return KindPrintf 110 } else { 111 return KindPrint 112 } 113 } 114 115 return r.funcs[fn] 116 } 117 118 // isWrapper is a fact indicating that a function is a print or printf wrapper. 119 type isWrapper struct{ Kind Kind } 120 121 func (f *isWrapper) AFact() {} 122 123 func (f *isWrapper) String() string { 124 switch f.Kind { 125 case KindPrintf: 126 return "printfWrapper" 127 case KindPrint: 128 return "printWrapper" 129 case KindErrorf: 130 return "errorfWrapper" 131 default: 132 return "unknownWrapper" 133 } 134 } 135 136 func run(pass *analysis.Pass) (interface{}, error) { 137 res := &Result{ 138 funcs: make(map[*types.Func]Kind), 139 } 140 findPrintfLike(pass, res) 141 checkCall(pass) 142 return res, nil 143 } 144 145 type printfWrapper struct { 146 obj *types.Func 147 fdecl *ast.FuncDecl 148 format *types.Var 149 args *types.Var 150 callers []printfCaller 151 failed bool // if true, not a printf wrapper 152 } 153 154 type printfCaller struct { 155 w *printfWrapper 156 call *ast.CallExpr 157 } 158 159 // maybePrintfWrapper decides whether decl (a declared function) may be a wrapper 160 // around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper 161 // function describing the declaration. Later processing will analyze the 162 // graph of potential printf wrappers to pick out the ones that are true wrappers. 163 // A function may be a Printf or Print wrapper if its last argument is ...interface{}. 164 // If the next-to-last argument is a string, then this may be a Printf wrapper. 165 // Otherwise it may be a Print wrapper. 166 func maybePrintfWrapper(info *types.Info, decl ast.Decl) *printfWrapper { 167 // Look for functions with final argument type ...interface{}. 168 fdecl, ok := decl.(*ast.FuncDecl) 169 if !ok || fdecl.Body == nil { 170 return nil 171 } 172 fn, ok := info.Defs[fdecl.Name].(*types.Func) 173 // Type information may be incomplete. 174 if !ok { 175 return nil 176 } 177 178 sig := fn.Type().(*types.Signature) 179 if !sig.Variadic() { 180 return nil // not variadic 181 } 182 183 params := sig.Params() 184 nparams := params.Len() // variadic => nonzero 185 186 args := params.At(nparams - 1) 187 iface, ok := args.Type().(*types.Slice).Elem().(*types.Interface) 188 if !ok || !iface.Empty() { 189 return nil // final (args) param is not ...interface{} 190 } 191 192 // Is second last param 'format string'? 193 var format *types.Var 194 if nparams >= 2 { 195 if p := params.At(nparams - 2); p.Type() == types.Typ[types.String] { 196 format = p 197 } 198 } 199 200 return &printfWrapper{ 201 obj: fn, 202 fdecl: fdecl, 203 format: format, 204 args: args, 205 } 206 } 207 208 // findPrintfLike scans the entire package to find printf-like functions. 209 func findPrintfLike(pass *analysis.Pass, res *Result) (interface{}, error) { 210 // Gather potential wrappers and call graph between them. 211 byObj := make(map[*types.Func]*printfWrapper) 212 var wrappers []*printfWrapper 213 for _, file := range pass.Files { 214 for _, decl := range file.Decls { 215 w := maybePrintfWrapper(pass.TypesInfo, decl) 216 if w == nil { 217 continue 218 } 219 byObj[w.obj] = w 220 wrappers = append(wrappers, w) 221 } 222 } 223 224 // Walk the graph to figure out which are really printf wrappers. 225 for _, w := range wrappers { 226 // Scan function for calls that could be to other printf-like functions. 227 ast.Inspect(w.fdecl.Body, func(n ast.Node) bool { 228 if w.failed { 229 return false 230 } 231 232 // TODO: Relax these checks; issue 26555. 233 if assign, ok := n.(*ast.AssignStmt); ok { 234 for _, lhs := range assign.Lhs { 235 if match(pass.TypesInfo, lhs, w.format) || 236 match(pass.TypesInfo, lhs, w.args) { 237 // Modifies the format 238 // string or args in 239 // some way, so not a 240 // simple wrapper. 241 w.failed = true 242 return false 243 } 244 } 245 } 246 if un, ok := n.(*ast.UnaryExpr); ok && un.Op == token.AND { 247 if match(pass.TypesInfo, un.X, w.format) || 248 match(pass.TypesInfo, un.X, w.args) { 249 // Taking the address of the 250 // format string or args, 251 // so not a simple wrapper. 252 w.failed = true 253 return false 254 } 255 } 256 257 call, ok := n.(*ast.CallExpr) 258 if !ok || len(call.Args) == 0 || !match(pass.TypesInfo, call.Args[len(call.Args)-1], w.args) { 259 return true 260 } 261 262 fn, kind := printfNameAndKind(pass, call) 263 if kind != 0 { 264 checkPrintfFwd(pass, w, call, kind, res) 265 return true 266 } 267 268 // If the call is to another function in this package, 269 // maybe we will find out it is printf-like later. 270 // Remember this call for later checking. 271 if fn != nil && fn.Pkg() == pass.Pkg && byObj[fn] != nil { 272 callee := byObj[fn] 273 callee.callers = append(callee.callers, printfCaller{w, call}) 274 } 275 276 return true 277 }) 278 } 279 return nil, nil 280 } 281 282 func match(info *types.Info, arg ast.Expr, param *types.Var) bool { 283 id, ok := arg.(*ast.Ident) 284 return ok && info.ObjectOf(id) == param 285 } 286 287 // checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly. 288 // It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...). 289 func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind Kind, res *Result) { 290 matched := kind == KindPrint || 291 kind != KindNone && len(call.Args) >= 2 && match(pass.TypesInfo, call.Args[len(call.Args)-2], w.format) 292 if !matched { 293 return 294 } 295 296 if !call.Ellipsis.IsValid() { 297 typ, ok := pass.TypesInfo.Types[call.Fun].Type.(*types.Signature) 298 if !ok { 299 return 300 } 301 if len(call.Args) > typ.Params().Len() { 302 // If we're passing more arguments than what the 303 // print/printf function can take, adding an ellipsis 304 // would break the program. For example: 305 // 306 // func foo(arg1 string, arg2 ...interface{} { 307 // fmt.Printf("%s %v", arg1, arg2) 308 // } 309 return 310 } 311 desc := "printf" 312 if kind == KindPrint { 313 desc = "print" 314 } 315 pass.ReportRangef(call, "missing ... in args forwarded to %s-like function", desc) 316 return 317 } 318 fn := w.obj 319 var fact isWrapper 320 if !pass.ImportObjectFact(fn, &fact) { 321 fact.Kind = kind 322 pass.ExportObjectFact(fn, &fact) 323 res.funcs[fn] = kind 324 for _, caller := range w.callers { 325 checkPrintfFwd(pass, caller.w, caller.call, kind, res) 326 } 327 } 328 } 329 330 // isPrint records the print functions. 331 // If a key ends in 'f' then it is assumed to be a formatted print. 332 // 333 // Keys are either values returned by (*types.Func).FullName, 334 // or case-insensitive identifiers such as "errorf". 335 // 336 // The -funcs flag adds to this set. 337 // 338 // The set below includes facts for many important standard library 339 // functions, even though the analysis is capable of deducing that, for 340 // example, fmt.Printf forwards to fmt.Fprintf. We avoid relying on the 341 // driver applying analyzers to standard packages because "go vet" does 342 // not do so with gccgo, and nor do some other build systems. 343 // TODO(adonovan): eliminate the redundant facts once this restriction 344 // is lifted. 345 var isPrint = stringSet{ 346 "fmt.Errorf": true, 347 "fmt.Fprint": true, 348 "fmt.Fprintf": true, 349 "fmt.Fprintln": true, 350 "fmt.Print": true, 351 "fmt.Printf": true, 352 "fmt.Println": true, 353 "fmt.Sprint": true, 354 "fmt.Sprintf": true, 355 "fmt.Sprintln": true, 356 357 "runtime/trace.Logf": true, 358 359 "log.Print": true, 360 "log.Printf": true, 361 "log.Println": true, 362 "log.Fatal": true, 363 "log.Fatalf": true, 364 "log.Fatalln": true, 365 "log.Panic": true, 366 "log.Panicf": true, 367 "log.Panicln": true, 368 "(*log.Logger).Fatal": true, 369 "(*log.Logger).Fatalf": true, 370 "(*log.Logger).Fatalln": true, 371 "(*log.Logger).Panic": true, 372 "(*log.Logger).Panicf": true, 373 "(*log.Logger).Panicln": true, 374 "(*log.Logger).Print": true, 375 "(*log.Logger).Printf": true, 376 "(*log.Logger).Println": true, 377 378 "(*testing.common).Error": true, 379 "(*testing.common).Errorf": true, 380 "(*testing.common).Fatal": true, 381 "(*testing.common).Fatalf": true, 382 "(*testing.common).Log": true, 383 "(*testing.common).Logf": true, 384 "(*testing.common).Skip": true, 385 "(*testing.common).Skipf": true, 386 // *testing.T and B are detected by induction, but testing.TB is 387 // an interface and the inference can't follow dynamic calls. 388 "(testing.TB).Error": true, 389 "(testing.TB).Errorf": true, 390 "(testing.TB).Fatal": true, 391 "(testing.TB).Fatalf": true, 392 "(testing.TB).Log": true, 393 "(testing.TB).Logf": true, 394 "(testing.TB).Skip": true, 395 "(testing.TB).Skipf": true, 396 } 397 398 // formatString returns the format string argument and its index within 399 // the given printf-like call expression. 400 // 401 // The last parameter before variadic arguments is assumed to be 402 // a format string. 403 // 404 // The first string literal or string constant is assumed to be a format string 405 // if the call's signature cannot be determined. 406 // 407 // If it cannot find any format string parameter, it returns ("", -1). 408 func formatString(pass *analysis.Pass, call *ast.CallExpr) (format string, idx int) { 409 typ := pass.TypesInfo.Types[call.Fun].Type 410 if typ != nil { 411 if sig, ok := typ.(*types.Signature); ok { 412 if !sig.Variadic() { 413 // Skip checking non-variadic functions. 414 return "", -1 415 } 416 idx := sig.Params().Len() - 2 417 if idx < 0 { 418 // Skip checking variadic functions without 419 // fixed arguments. 420 return "", -1 421 } 422 s, ok := stringConstantArg(pass, call, idx) 423 if !ok { 424 // The last argument before variadic args isn't a string. 425 return "", -1 426 } 427 return s, idx 428 } 429 } 430 431 // Cannot determine call's signature. Fall back to scanning for the first 432 // string constant in the call. 433 for idx := range call.Args { 434 if s, ok := stringConstantArg(pass, call, idx); ok { 435 return s, idx 436 } 437 if pass.TypesInfo.Types[call.Args[idx]].Type == types.Typ[types.String] { 438 // Skip checking a call with a non-constant format 439 // string argument, since its contents are unavailable 440 // for validation. 441 return "", -1 442 } 443 } 444 return "", -1 445 } 446 447 // stringConstantArg returns call's string constant argument at the index idx. 448 // 449 // ("", false) is returned if call's argument at the index idx isn't a string 450 // constant. 451 func stringConstantArg(pass *analysis.Pass, call *ast.CallExpr, idx int) (string, bool) { 452 if idx >= len(call.Args) { 453 return "", false 454 } 455 return stringConstantExpr(pass, call.Args[idx]) 456 } 457 458 // stringConstantExpr returns expression's string constant value. 459 // 460 // ("", false) is returned if expression isn't a string 461 // constant. 462 func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool) { 463 lit := pass.TypesInfo.Types[expr].Value 464 if lit != nil && lit.Kind() == constant.String { 465 return constant.StringVal(lit), true 466 } 467 return "", false 468 } 469 470 // checkCall triggers the print-specific checks if the call invokes a print function. 471 func checkCall(pass *analysis.Pass) { 472 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 473 nodeFilter := []ast.Node{ 474 (*ast.CallExpr)(nil), 475 } 476 inspect.Preorder(nodeFilter, func(n ast.Node) { 477 call := n.(*ast.CallExpr) 478 fn, kind := printfNameAndKind(pass, call) 479 switch kind { 480 case KindPrintf, KindErrorf: 481 checkPrintf(pass, kind, call, fn) 482 case KindPrint: 483 checkPrint(pass, call, fn) 484 } 485 }) 486 } 487 488 func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind Kind) { 489 fn, _ = typeutil.Callee(pass.TypesInfo, call).(*types.Func) 490 if fn == nil { 491 return nil, 0 492 } 493 494 _, ok := isPrint[fn.FullName()] 495 if !ok { 496 // Next look up just "printf", for use with -printf.funcs. 497 _, ok = isPrint[strings.ToLower(fn.Name())] 498 } 499 if ok { 500 if fn.FullName() == "fmt.Errorf" { 501 kind = KindErrorf 502 } else if strings.HasSuffix(fn.Name(), "f") { 503 kind = KindPrintf 504 } else { 505 kind = KindPrint 506 } 507 return fn, kind 508 } 509 510 var fact isWrapper 511 if pass.ImportObjectFact(fn, &fact) { 512 return fn, fact.Kind 513 } 514 515 return fn, KindNone 516 } 517 518 // isFormatter reports whether t could satisfy fmt.Formatter. 519 // The only interface method to look for is "Format(State, rune)". 520 func isFormatter(typ types.Type) bool { 521 // If the type is an interface, the value it holds might satisfy fmt.Formatter. 522 if _, ok := typ.Underlying().(*types.Interface); ok { 523 // Don't assume type parameters could be formatters. With the greater 524 // expressiveness of constraint interface syntax we expect more type safety 525 // when using type parameters. 526 if !typeparams.IsTypeParam(typ) { 527 return true 528 } 529 } 530 obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format") 531 fn, ok := obj.(*types.Func) 532 if !ok { 533 return false 534 } 535 sig := fn.Type().(*types.Signature) 536 return sig.Params().Len() == 2 && 537 sig.Results().Len() == 0 && 538 isNamed(sig.Params().At(0).Type(), "fmt", "State") && 539 types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune]) 540 } 541 542 func isNamed(T types.Type, pkgpath, name string) bool { 543 named, ok := T.(*types.Named) 544 return ok && named.Obj().Pkg().Path() == pkgpath && named.Obj().Name() == name 545 } 546 547 // formatState holds the parsed representation of a printf directive such as "%3.*[4]d". 548 // It is constructed by parsePrintfVerb. 549 type formatState struct { 550 verb rune // the format verb: 'd' for "%d" 551 format string // the full format directive from % through verb, "%.3d". 552 name string // Printf, Sprintf etc. 553 flags []byte // the list of # + etc. 554 argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call 555 firstArg int // Index of first argument after the format in the Printf call. 556 // Used only during parse. 557 pass *analysis.Pass 558 call *ast.CallExpr 559 argNum int // Which argument we're expecting to format now. 560 hasIndex bool // Whether the argument is indexed. 561 indexPending bool // Whether we have an indexed argument that has not resolved. 562 nbytes int // number of bytes of the format string consumed. 563 } 564 565 // checkPrintf checks a call to a formatted print routine such as Printf. 566 func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.Func) { 567 format, idx := formatString(pass, call) 568 if idx < 0 { 569 if false { 570 pass.Reportf(call.Lparen, "can't check non-constant format in call to %s", fn.FullName()) 571 } 572 return 573 } 574 575 firstArg := idx + 1 // Arguments are immediately after format string. 576 if !strings.Contains(format, "%") { 577 if len(call.Args) > firstArg { 578 pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.FullName()) 579 } 580 return 581 } 582 // Hard part: check formats against args. 583 argNum := firstArg 584 maxArgNum := firstArg 585 anyIndex := false 586 for i, w := 0, 0; i < len(format); i += w { 587 w = 1 588 if format[i] != '%' { 589 continue 590 } 591 state := parsePrintfVerb(pass, call, fn.FullName(), format[i:], firstArg, argNum) 592 if state == nil { 593 return 594 } 595 w = len(state.format) 596 if !okPrintfArg(pass, call, state) { // One error per format is enough. 597 return 598 } 599 if state.hasIndex { 600 anyIndex = true 601 } 602 if state.verb == 'w' { 603 switch kind { 604 case KindNone, KindPrint, KindPrintf: 605 pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name) 606 return 607 } 608 } 609 if len(state.argNums) > 0 { 610 // Continue with the next sequential argument. 611 argNum = state.argNums[len(state.argNums)-1] + 1 612 } 613 for _, n := range state.argNums { 614 if n >= maxArgNum { 615 maxArgNum = n + 1 616 } 617 } 618 } 619 // Dotdotdot is hard. 620 if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 { 621 return 622 } 623 // If any formats are indexed, extra arguments are ignored. 624 if anyIndex { 625 return 626 } 627 // There should be no leftover arguments. 628 if maxArgNum != len(call.Args) { 629 expect := maxArgNum - firstArg 630 numArgs := len(call.Args) - firstArg 631 pass.ReportRangef(call, "%s call needs %v but has %v", fn.FullName(), count(expect, "arg"), count(numArgs, "arg")) 632 } 633 } 634 635 // parseFlags accepts any printf flags. 636 func (s *formatState) parseFlags() { 637 for s.nbytes < len(s.format) { 638 switch c := s.format[s.nbytes]; c { 639 case '#', '0', '+', '-', ' ': 640 s.flags = append(s.flags, c) 641 s.nbytes++ 642 default: 643 return 644 } 645 } 646 } 647 648 // scanNum advances through a decimal number if present. 649 func (s *formatState) scanNum() { 650 for ; s.nbytes < len(s.format); s.nbytes++ { 651 c := s.format[s.nbytes] 652 if c < '0' || '9' < c { 653 return 654 } 655 } 656 } 657 658 // parseIndex scans an index expression. It returns false if there is a syntax error. 659 func (s *formatState) parseIndex() bool { 660 if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { 661 return true 662 } 663 // Argument index present. 664 s.nbytes++ // skip '[' 665 start := s.nbytes 666 s.scanNum() 667 ok := true 668 if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { 669 ok = false // syntax error is either missing "]" or invalid index. 670 s.nbytes = strings.Index(s.format[start:], "]") 671 if s.nbytes < 0 { 672 s.pass.ReportRangef(s.call, "%s format %s is missing closing ]", s.name, s.format) 673 return false 674 } 675 s.nbytes = s.nbytes + start 676 } 677 arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) 678 if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) { 679 s.pass.ReportRangef(s.call, "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes]) 680 return false 681 } 682 s.nbytes++ // skip ']' 683 arg := int(arg32) 684 arg += s.firstArg - 1 // We want to zero-index the actual arguments. 685 s.argNum = arg 686 s.hasIndex = true 687 s.indexPending = true 688 return true 689 } 690 691 // parseNum scans a width or precision (or *). It returns false if there's a bad index expression. 692 func (s *formatState) parseNum() bool { 693 if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { 694 if s.indexPending { // Absorb it. 695 s.indexPending = false 696 } 697 s.nbytes++ 698 s.argNums = append(s.argNums, s.argNum) 699 s.argNum++ 700 } else { 701 s.scanNum() 702 } 703 return true 704 } 705 706 // parsePrecision scans for a precision. It returns false if there's a bad index expression. 707 func (s *formatState) parsePrecision() bool { 708 // If there's a period, there may be a precision. 709 if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { 710 s.flags = append(s.flags, '.') // Treat precision as a flag. 711 s.nbytes++ 712 if !s.parseIndex() { 713 return false 714 } 715 if !s.parseNum() { 716 return false 717 } 718 } 719 return true 720 } 721 722 // parsePrintfVerb looks the formatting directive that begins the format string 723 // and returns a formatState that encodes what the directive wants, without looking 724 // at the actual arguments present in the call. The result is nil if there is an error. 725 func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState { 726 state := &formatState{ 727 format: format, 728 name: name, 729 flags: make([]byte, 0, 5), 730 argNum: argNum, 731 argNums: make([]int, 0, 1), 732 nbytes: 1, // There's guaranteed to be a percent sign. 733 firstArg: firstArg, 734 pass: pass, 735 call: call, 736 } 737 // There may be flags. 738 state.parseFlags() 739 // There may be an index. 740 if !state.parseIndex() { 741 return nil 742 } 743 // There may be a width. 744 if !state.parseNum() { 745 return nil 746 } 747 // There may be a precision. 748 if !state.parsePrecision() { 749 return nil 750 } 751 // Now a verb, possibly prefixed by an index (which we may already have). 752 if !state.indexPending && !state.parseIndex() { 753 return nil 754 } 755 if state.nbytes == len(state.format) { 756 pass.ReportRangef(call.Fun, "%s format %s is missing verb at end of string", name, state.format) 757 return nil 758 } 759 verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) 760 state.verb = verb 761 state.nbytes += w 762 if verb != '%' { 763 state.argNums = append(state.argNums, state.argNum) 764 } 765 state.format = state.format[:state.nbytes] 766 return state 767 } 768 769 // printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask. 770 type printfArgType int 771 772 const ( 773 argBool printfArgType = 1 << iota 774 argInt 775 argRune 776 argString 777 argFloat 778 argComplex 779 argPointer 780 argError 781 anyType printfArgType = ^0 782 ) 783 784 type printVerb struct { 785 verb rune // User may provide verb through Formatter; could be a rune. 786 flags string // known flags are all ASCII 787 typ printfArgType 788 } 789 790 // Common flag sets for printf verbs. 791 const ( 792 noFlag = "" 793 numFlag = " -+.0" 794 sharpNumFlag = " -+.0#" 795 allFlags = " -+.0#" 796 ) 797 798 // printVerbs identifies which flags are known to printf for each verb. 799 var printVerbs = []printVerb{ 800 // '-' is a width modifier, always valid. 801 // '.' is a precision for float, max width for strings. 802 // '+' is required sign for numbers, Go format for %v. 803 // '#' is alternate format for several verbs. 804 // ' ' is spacer for numbers 805 {'%', noFlag, 0}, 806 {'b', sharpNumFlag, argInt | argFloat | argComplex | argPointer}, 807 {'c', "-", argRune | argInt}, 808 {'d', numFlag, argInt | argPointer}, 809 {'e', sharpNumFlag, argFloat | argComplex}, 810 {'E', sharpNumFlag, argFloat | argComplex}, 811 {'f', sharpNumFlag, argFloat | argComplex}, 812 {'F', sharpNumFlag, argFloat | argComplex}, 813 {'g', sharpNumFlag, argFloat | argComplex}, 814 {'G', sharpNumFlag, argFloat | argComplex}, 815 {'o', sharpNumFlag, argInt | argPointer}, 816 {'O', sharpNumFlag, argInt | argPointer}, 817 {'p', "-#", argPointer}, 818 {'q', " -+.0#", argRune | argInt | argString}, 819 {'s', " -+.0", argString}, 820 {'t', "-", argBool}, 821 {'T', "-", anyType}, 822 {'U', "-#", argRune | argInt}, 823 {'v', allFlags, anyType}, 824 {'w', allFlags, argError}, 825 {'x', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex}, 826 {'X', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex}, 827 } 828 829 // okPrintfArg compares the formatState to the arguments actually present, 830 // reporting any discrepancies it can discern. If the final argument is ellipsissed, 831 // there's little it can do for that. 832 func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (ok bool) { 833 var v printVerb 834 found := false 835 // Linear scan is fast enough for a small list. 836 for _, v = range printVerbs { 837 if v.verb == state.verb { 838 found = true 839 break 840 } 841 } 842 843 // Could current arg implement fmt.Formatter? 844 // Skip check for the %w verb, which requires an error. 845 formatter := false 846 if v.typ != argError && state.argNum < len(call.Args) { 847 if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok { 848 formatter = isFormatter(tv.Type) 849 } 850 } 851 852 if !formatter { 853 if !found { 854 pass.ReportRangef(call, "%s format %s has unknown verb %c", state.name, state.format, state.verb) 855 return false 856 } 857 for _, flag := range state.flags { 858 // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11. 859 // See issues 23598 and 23605. 860 if flag == '0' { 861 continue 862 } 863 if !strings.ContainsRune(v.flags, rune(flag)) { 864 pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag) 865 return false 866 } 867 } 868 } 869 // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all 870 // but the final arg must be an integer. 871 trueArgs := 1 872 if state.verb == '%' { 873 trueArgs = 0 874 } 875 nargs := len(state.argNums) 876 for i := 0; i < nargs-trueArgs; i++ { 877 argNum := state.argNums[i] 878 if !argCanBeChecked(pass, call, i, state) { 879 return 880 } 881 arg := call.Args[argNum] 882 if reason, ok := matchArgType(pass, argInt, arg); !ok { 883 details := "" 884 if reason != "" { 885 details = " (" + reason + ")" 886 } 887 pass.ReportRangef(call, "%s format %s uses non-int %s%s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg), details) 888 return false 889 } 890 } 891 892 if state.verb == '%' || formatter { 893 return true 894 } 895 argNum := state.argNums[len(state.argNums)-1] 896 if !argCanBeChecked(pass, call, len(state.argNums)-1, state) { 897 return false 898 } 899 arg := call.Args[argNum] 900 if isFunctionValue(pass, arg) && state.verb != 'p' && state.verb != 'T' { 901 pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg)) 902 return false 903 } 904 if reason, ok := matchArgType(pass, v.typ, arg); !ok { 905 typeString := "" 906 if typ := pass.TypesInfo.Types[arg].Type; typ != nil { 907 typeString = typ.String() 908 } 909 details := "" 910 if reason != "" { 911 details = " (" + reason + ")" 912 } 913 pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s%s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details) 914 return false 915 } 916 if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) { 917 if methodName, ok := recursiveStringer(pass, arg); ok { 918 pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", state.name, state.format, analysisutil.Format(pass.Fset, arg), methodName) 919 return false 920 } 921 } 922 return true 923 } 924 925 // recursiveStringer reports whether the argument e is a potential 926 // recursive call to stringer or is an error, such as t and &t in these examples: 927 // 928 // func (t *T) String() string { printf("%s", t) } 929 // func (t T) Error() string { printf("%s", t) } 930 // func (t T) String() string { printf("%s", &t) } 931 func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) { 932 typ := pass.TypesInfo.Types[e].Type 933 934 // It's unlikely to be a recursive stringer if it has a Format method. 935 if isFormatter(typ) { 936 return "", false 937 } 938 939 // Does e allow e.String() or e.Error()? 940 strObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "String") 941 strMethod, strOk := strObj.(*types.Func) 942 errObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "Error") 943 errMethod, errOk := errObj.(*types.Func) 944 if !strOk && !errOk { 945 return "", false 946 } 947 948 // inScope returns true if e is in the scope of f. 949 inScope := func(e ast.Expr, f *types.Func) bool { 950 return f.Scope() != nil && f.Scope().Contains(e.Pos()) 951 } 952 953 // Is the expression e within the body of that String or Error method? 954 var method *types.Func 955 if strOk && strMethod.Pkg() == pass.Pkg && inScope(e, strMethod) { 956 method = strMethod 957 } else if errOk && errMethod.Pkg() == pass.Pkg && inScope(e, errMethod) { 958 method = errMethod 959 } else { 960 return "", false 961 } 962 963 sig := method.Type().(*types.Signature) 964 if !isStringer(sig) { 965 return "", false 966 } 967 968 // Is it the receiver r, or &r? 969 if u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.AND { 970 e = u.X // strip off & from &r 971 } 972 if id, ok := e.(*ast.Ident); ok { 973 if pass.TypesInfo.Uses[id] == sig.Recv() { 974 return method.FullName(), true 975 } 976 } 977 return "", false 978 } 979 980 // isStringer reports whether the method signature matches the String() definition in fmt.Stringer. 981 func isStringer(sig *types.Signature) bool { 982 return sig.Params().Len() == 0 && 983 sig.Results().Len() == 1 && 984 sig.Results().At(0).Type() == types.Typ[types.String] 985 } 986 987 // isFunctionValue reports whether the expression is a function as opposed to a function call. 988 // It is almost always a mistake to print a function value. 989 func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool { 990 if typ := pass.TypesInfo.Types[e].Type; typ != nil { 991 _, ok := typ.(*types.Signature) 992 return ok 993 } 994 return false 995 } 996 997 // argCanBeChecked reports whether the specified argument is statically present; 998 // it may be beyond the list of arguments or in a terminal slice... argument, which 999 // means we can't see it. 1000 func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool { 1001 argNum := state.argNums[formatArg] 1002 if argNum <= 0 { 1003 // Shouldn't happen, so catch it with prejudice. 1004 panic("negative arg num") 1005 } 1006 if argNum < len(call.Args)-1 { 1007 return true // Always OK. 1008 } 1009 if call.Ellipsis.IsValid() { 1010 return false // We just can't tell; there could be many more arguments. 1011 } 1012 if argNum < len(call.Args) { 1013 return true 1014 } 1015 // There are bad indexes in the format or there are fewer arguments than the format needs. 1016 // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi". 1017 arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed. 1018 pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg")) 1019 return false 1020 } 1021 1022 // printFormatRE is the regexp we match and report as a possible format string 1023 // in the first argument to unformatted prints like fmt.Print. 1024 // We exclude the space flag, so that printing a string like "x % y" is not reported as a format. 1025 var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE) 1026 1027 const ( 1028 flagsRE = `[+\-#]*` 1029 indexOptRE = `(\[[0-9]+\])?` 1030 numOptRE = `([0-9]+|` + indexOptRE + `\*)?` 1031 verbRE = `[bcdefgopqstvxEFGTUX]` 1032 ) 1033 1034 // checkPrint checks a call to an unformatted print routine such as Println. 1035 func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { 1036 firstArg := 0 1037 typ := pass.TypesInfo.Types[call.Fun].Type 1038 if typ == nil { 1039 // Skip checking functions with unknown type. 1040 return 1041 } 1042 if sig, ok := typ.(*types.Signature); ok { 1043 if !sig.Variadic() { 1044 // Skip checking non-variadic functions. 1045 return 1046 } 1047 params := sig.Params() 1048 firstArg = params.Len() - 1 1049 1050 typ := params.At(firstArg).Type() 1051 typ = typ.(*types.Slice).Elem() 1052 it, ok := typ.(*types.Interface) 1053 if !ok || !it.Empty() { 1054 // Skip variadic functions accepting non-interface{} args. 1055 return 1056 } 1057 } 1058 args := call.Args 1059 if len(args) <= firstArg { 1060 // Skip calls without variadic args. 1061 return 1062 } 1063 args = args[firstArg:] 1064 1065 if firstArg == 0 { 1066 if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { 1067 if x, ok := sel.X.(*ast.Ident); ok { 1068 if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { 1069 pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.FullName(), analysisutil.Format(pass.Fset, call.Args[0])) 1070 } 1071 } 1072 } 1073 } 1074 1075 arg := args[0] 1076 if s, ok := stringConstantExpr(pass, arg); ok { 1077 // Ignore trailing % character 1078 // The % in "abc 0.0%" couldn't be a formatting directive. 1079 s = strings.TrimSuffix(s, "%") 1080 if strings.Contains(s, "%") { 1081 m := printFormatRE.FindStringSubmatch(s) 1082 if m != nil { 1083 pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.FullName(), m[0]) 1084 } 1085 } 1086 } 1087 if strings.HasSuffix(fn.Name(), "ln") { 1088 // The last item, if a string, should not have a newline. 1089 arg = args[len(args)-1] 1090 if s, ok := stringConstantExpr(pass, arg); ok { 1091 if strings.HasSuffix(s, "\n") { 1092 pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName()) 1093 } 1094 } 1095 } 1096 for _, arg := range args { 1097 if isFunctionValue(pass, arg) { 1098 pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg)) 1099 } 1100 if methodName, ok := recursiveStringer(pass, arg); ok { 1101 pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName) 1102 } 1103 } 1104 } 1105 1106 // count(n, what) returns "1 what" or "N whats" 1107 // (assuming the plural of what is whats). 1108 func count(n int, what string) string { 1109 if n == 1 { 1110 return "1 " + what 1111 } 1112 return fmt.Sprintf("%d %ss", n, what) 1113 } 1114 1115 // stringSet is a set-of-nonempty-strings-valued flag. 1116 // Note: elements without a '.' get lower-cased. 1117 type stringSet map[string]bool 1118 1119 func (ss stringSet) String() string { 1120 var list []string 1121 for name := range ss { 1122 list = append(list, name) 1123 } 1124 sort.Strings(list) 1125 return strings.Join(list, ",") 1126 } 1127 1128 func (ss stringSet) Set(flag string) error { 1129 for _, name := range strings.Split(flag, ",") { 1130 if len(name) == 0 { 1131 return fmt.Errorf("empty string") 1132 } 1133 if !strings.Contains(name, ".") { 1134 name = strings.ToLower(name) 1135 } 1136 ss[name] = true 1137 } 1138 return nil 1139 }