github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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 "github.com/powerman/golang-tools/go/analysis" 24 "github.com/powerman/golang-tools/go/analysis/passes/inspect" 25 "github.com/powerman/golang-tools/go/analysis/passes/internal/analysisutil" 26 "github.com/powerman/golang-tools/go/ast/inspector" 27 "github.com/powerman/golang-tools/go/types/typeutil" 28 "github.com/powerman/golang-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 // 346 var isPrint = stringSet{ 347 "fmt.Errorf": true, 348 "fmt.Fprint": true, 349 "fmt.Fprintf": true, 350 "fmt.Fprintln": true, 351 "fmt.Print": true, 352 "fmt.Printf": true, 353 "fmt.Println": true, 354 "fmt.Sprint": true, 355 "fmt.Sprintf": true, 356 "fmt.Sprintln": true, 357 358 "runtime/trace.Logf": true, 359 360 "log.Print": true, 361 "log.Printf": true, 362 "log.Println": true, 363 "log.Fatal": true, 364 "log.Fatalf": true, 365 "log.Fatalln": true, 366 "log.Panic": true, 367 "log.Panicf": true, 368 "log.Panicln": true, 369 "(*log.Logger).Fatal": true, 370 "(*log.Logger).Fatalf": true, 371 "(*log.Logger).Fatalln": true, 372 "(*log.Logger).Panic": true, 373 "(*log.Logger).Panicf": true, 374 "(*log.Logger).Panicln": true, 375 "(*log.Logger).Print": true, 376 "(*log.Logger).Printf": true, 377 "(*log.Logger).Println": true, 378 379 "(*testing.common).Error": true, 380 "(*testing.common).Errorf": true, 381 "(*testing.common).Fatal": true, 382 "(*testing.common).Fatalf": true, 383 "(*testing.common).Log": true, 384 "(*testing.common).Logf": true, 385 "(*testing.common).Skip": true, 386 "(*testing.common).Skipf": true, 387 // *testing.T and B are detected by induction, but testing.TB is 388 // an interface and the inference can't follow dynamic calls. 389 "(testing.TB).Error": true, 390 "(testing.TB).Errorf": true, 391 "(testing.TB).Fatal": true, 392 "(testing.TB).Fatalf": true, 393 "(testing.TB).Log": true, 394 "(testing.TB).Logf": true, 395 "(testing.TB).Skip": true, 396 "(testing.TB).Skipf": true, 397 } 398 399 // formatString returns the format string argument and its index within 400 // the given printf-like call expression. 401 // 402 // The last parameter before variadic arguments is assumed to be 403 // a format string. 404 // 405 // The first string literal or string constant is assumed to be a format string 406 // if the call's signature cannot be determined. 407 // 408 // If it cannot find any format string parameter, it returns ("", -1). 409 func formatString(pass *analysis.Pass, call *ast.CallExpr) (format string, idx int) { 410 typ := pass.TypesInfo.Types[call.Fun].Type 411 if typ != nil { 412 if sig, ok := typ.(*types.Signature); ok { 413 if !sig.Variadic() { 414 // Skip checking non-variadic functions. 415 return "", -1 416 } 417 idx := sig.Params().Len() - 2 418 if idx < 0 { 419 // Skip checking variadic functions without 420 // fixed arguments. 421 return "", -1 422 } 423 s, ok := stringConstantArg(pass, call, idx) 424 if !ok { 425 // The last argument before variadic args isn't a string. 426 return "", -1 427 } 428 return s, idx 429 } 430 } 431 432 // Cannot determine call's signature. Fall back to scanning for the first 433 // string constant in the call. 434 for idx := range call.Args { 435 if s, ok := stringConstantArg(pass, call, idx); ok { 436 return s, idx 437 } 438 if pass.TypesInfo.Types[call.Args[idx]].Type == types.Typ[types.String] { 439 // Skip checking a call with a non-constant format 440 // string argument, since its contents are unavailable 441 // for validation. 442 return "", -1 443 } 444 } 445 return "", -1 446 } 447 448 // stringConstantArg returns call's string constant argument at the index idx. 449 // 450 // ("", false) is returned if call's argument at the index idx isn't a string 451 // constant. 452 func stringConstantArg(pass *analysis.Pass, call *ast.CallExpr, idx int) (string, bool) { 453 if idx >= len(call.Args) { 454 return "", false 455 } 456 return stringConstantExpr(pass, call.Args[idx]) 457 } 458 459 // stringConstantExpr returns expression's string constant value. 460 // 461 // ("", false) is returned if expression isn't a string 462 // constant. 463 func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool) { 464 lit := pass.TypesInfo.Types[expr].Value 465 if lit != nil && lit.Kind() == constant.String { 466 return constant.StringVal(lit), true 467 } 468 return "", false 469 } 470 471 // checkCall triggers the print-specific checks if the call invokes a print function. 472 func checkCall(pass *analysis.Pass) { 473 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 474 nodeFilter := []ast.Node{ 475 (*ast.CallExpr)(nil), 476 } 477 inspect.Preorder(nodeFilter, func(n ast.Node) { 478 call := n.(*ast.CallExpr) 479 fn, kind := printfNameAndKind(pass, call) 480 switch kind { 481 case KindPrintf, KindErrorf: 482 checkPrintf(pass, kind, call, fn) 483 case KindPrint: 484 checkPrint(pass, call, fn) 485 } 486 }) 487 } 488 489 func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind Kind) { 490 fn, _ = typeutil.Callee(pass.TypesInfo, call).(*types.Func) 491 if fn == nil { 492 return nil, 0 493 } 494 495 _, ok := isPrint[fn.FullName()] 496 if !ok { 497 // Next look up just "printf", for use with -printf.funcs. 498 _, ok = isPrint[strings.ToLower(fn.Name())] 499 } 500 if ok { 501 if fn.FullName() == "fmt.Errorf" { 502 kind = KindErrorf 503 } else if strings.HasSuffix(fn.Name(), "f") { 504 kind = KindPrintf 505 } else { 506 kind = KindPrint 507 } 508 return fn, kind 509 } 510 511 var fact isWrapper 512 if pass.ImportObjectFact(fn, &fact) { 513 return fn, fact.Kind 514 } 515 516 return fn, KindNone 517 } 518 519 // isFormatter reports whether t could satisfy fmt.Formatter. 520 // The only interface method to look for is "Format(State, rune)". 521 func isFormatter(typ types.Type) bool { 522 // If the type is an interface, the value it holds might satisfy fmt.Formatter. 523 if _, ok := typ.Underlying().(*types.Interface); ok { 524 // Don't assume type parameters could be formatters. With the greater 525 // expressiveness of constraint interface syntax we expect more type safety 526 // when using type parameters. 527 if !typeparams.IsTypeParam(typ) { 528 return true 529 } 530 } 531 obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format") 532 fn, ok := obj.(*types.Func) 533 if !ok { 534 return false 535 } 536 sig := fn.Type().(*types.Signature) 537 return sig.Params().Len() == 2 && 538 sig.Results().Len() == 0 && 539 isNamed(sig.Params().At(0).Type(), "fmt", "State") && 540 types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune]) 541 } 542 543 func isNamed(T types.Type, pkgpath, name string) bool { 544 named, ok := T.(*types.Named) 545 return ok && named.Obj().Pkg().Path() == pkgpath && named.Obj().Name() == name 546 } 547 548 // formatState holds the parsed representation of a printf directive such as "%3.*[4]d". 549 // It is constructed by parsePrintfVerb. 550 type formatState struct { 551 verb rune // the format verb: 'd' for "%d" 552 format string // the full format directive from % through verb, "%.3d". 553 name string // Printf, Sprintf etc. 554 flags []byte // the list of # + etc. 555 argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call 556 firstArg int // Index of first argument after the format in the Printf call. 557 // Used only during parse. 558 pass *analysis.Pass 559 call *ast.CallExpr 560 argNum int // Which argument we're expecting to format now. 561 hasIndex bool // Whether the argument is indexed. 562 indexPending bool // Whether we have an indexed argument that has not resolved. 563 nbytes int // number of bytes of the format string consumed. 564 } 565 566 // checkPrintf checks a call to a formatted print routine such as Printf. 567 func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.Func) { 568 format, idx := formatString(pass, call) 569 if idx < 0 { 570 if false { 571 pass.Reportf(call.Lparen, "can't check non-constant format in call to %s", fn.FullName()) 572 } 573 return 574 } 575 576 firstArg := idx + 1 // Arguments are immediately after format string. 577 if !strings.Contains(format, "%") { 578 if len(call.Args) > firstArg { 579 pass.Reportf(call.Lparen, "%s call has arguments but no formatting directives", fn.FullName()) 580 } 581 return 582 } 583 // Hard part: check formats against args. 584 argNum := firstArg 585 maxArgNum := firstArg 586 anyIndex := false 587 anyW := false 588 for i, w := 0, 0; i < len(format); i += w { 589 w = 1 590 if format[i] != '%' { 591 continue 592 } 593 state := parsePrintfVerb(pass, call, fn.FullName(), format[i:], firstArg, argNum) 594 if state == nil { 595 return 596 } 597 w = len(state.format) 598 if !okPrintfArg(pass, call, state) { // One error per format is enough. 599 return 600 } 601 if state.hasIndex { 602 anyIndex = true 603 } 604 if state.verb == 'w' { 605 switch kind { 606 case KindNone, KindPrint, KindPrintf: 607 pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name) 608 return 609 } 610 if anyW { 611 pass.Reportf(call.Pos(), "%s call has more than one error-wrapping directive %%w", state.name) 612 return 613 } 614 anyW = true 615 } 616 if len(state.argNums) > 0 { 617 // Continue with the next sequential argument. 618 argNum = state.argNums[len(state.argNums)-1] + 1 619 } 620 for _, n := range state.argNums { 621 if n >= maxArgNum { 622 maxArgNum = n + 1 623 } 624 } 625 } 626 // Dotdotdot is hard. 627 if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 { 628 return 629 } 630 // If any formats are indexed, extra arguments are ignored. 631 if anyIndex { 632 return 633 } 634 // There should be no leftover arguments. 635 if maxArgNum != len(call.Args) { 636 expect := maxArgNum - firstArg 637 numArgs := len(call.Args) - firstArg 638 pass.ReportRangef(call, "%s call needs %v but has %v", fn.FullName(), count(expect, "arg"), count(numArgs, "arg")) 639 } 640 } 641 642 // parseFlags accepts any printf flags. 643 func (s *formatState) parseFlags() { 644 for s.nbytes < len(s.format) { 645 switch c := s.format[s.nbytes]; c { 646 case '#', '0', '+', '-', ' ': 647 s.flags = append(s.flags, c) 648 s.nbytes++ 649 default: 650 return 651 } 652 } 653 } 654 655 // scanNum advances through a decimal number if present. 656 func (s *formatState) scanNum() { 657 for ; s.nbytes < len(s.format); s.nbytes++ { 658 c := s.format[s.nbytes] 659 if c < '0' || '9' < c { 660 return 661 } 662 } 663 } 664 665 // parseIndex scans an index expression. It returns false if there is a syntax error. 666 func (s *formatState) parseIndex() bool { 667 if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { 668 return true 669 } 670 // Argument index present. 671 s.nbytes++ // skip '[' 672 start := s.nbytes 673 s.scanNum() 674 ok := true 675 if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { 676 ok = false 677 s.nbytes = strings.Index(s.format, "]") 678 if s.nbytes < 0 { 679 s.pass.ReportRangef(s.call, "%s format %s is missing closing ]", s.name, s.format) 680 return false 681 } 682 } 683 arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) 684 if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) { 685 s.pass.ReportRangef(s.call, "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes]) 686 return false 687 } 688 s.nbytes++ // skip ']' 689 arg := int(arg32) 690 arg += s.firstArg - 1 // We want to zero-index the actual arguments. 691 s.argNum = arg 692 s.hasIndex = true 693 s.indexPending = true 694 return true 695 } 696 697 // parseNum scans a width or precision (or *). It returns false if there's a bad index expression. 698 func (s *formatState) parseNum() bool { 699 if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { 700 if s.indexPending { // Absorb it. 701 s.indexPending = false 702 } 703 s.nbytes++ 704 s.argNums = append(s.argNums, s.argNum) 705 s.argNum++ 706 } else { 707 s.scanNum() 708 } 709 return true 710 } 711 712 // parsePrecision scans for a precision. It returns false if there's a bad index expression. 713 func (s *formatState) parsePrecision() bool { 714 // If there's a period, there may be a precision. 715 if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { 716 s.flags = append(s.flags, '.') // Treat precision as a flag. 717 s.nbytes++ 718 if !s.parseIndex() { 719 return false 720 } 721 if !s.parseNum() { 722 return false 723 } 724 } 725 return true 726 } 727 728 // parsePrintfVerb looks the formatting directive that begins the format string 729 // and returns a formatState that encodes what the directive wants, without looking 730 // at the actual arguments present in the call. The result is nil if there is an error. 731 func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState { 732 state := &formatState{ 733 format: format, 734 name: name, 735 flags: make([]byte, 0, 5), 736 argNum: argNum, 737 argNums: make([]int, 0, 1), 738 nbytes: 1, // There's guaranteed to be a percent sign. 739 firstArg: firstArg, 740 pass: pass, 741 call: call, 742 } 743 // There may be flags. 744 state.parseFlags() 745 // There may be an index. 746 if !state.parseIndex() { 747 return nil 748 } 749 // There may be a width. 750 if !state.parseNum() { 751 return nil 752 } 753 // There may be a precision. 754 if !state.parsePrecision() { 755 return nil 756 } 757 // Now a verb, possibly prefixed by an index (which we may already have). 758 if !state.indexPending && !state.parseIndex() { 759 return nil 760 } 761 if state.nbytes == len(state.format) { 762 pass.ReportRangef(call.Fun, "%s format %s is missing verb at end of string", name, state.format) 763 return nil 764 } 765 verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) 766 state.verb = verb 767 state.nbytes += w 768 if verb != '%' { 769 state.argNums = append(state.argNums, state.argNum) 770 } 771 state.format = state.format[:state.nbytes] 772 return state 773 } 774 775 // printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask. 776 type printfArgType int 777 778 const ( 779 argBool printfArgType = 1 << iota 780 argInt 781 argRune 782 argString 783 argFloat 784 argComplex 785 argPointer 786 argError 787 anyType printfArgType = ^0 788 ) 789 790 type printVerb struct { 791 verb rune // User may provide verb through Formatter; could be a rune. 792 flags string // known flags are all ASCII 793 typ printfArgType 794 } 795 796 // Common flag sets for printf verbs. 797 const ( 798 noFlag = "" 799 numFlag = " -+.0" 800 sharpNumFlag = " -+.0#" 801 allFlags = " -+.0#" 802 ) 803 804 // printVerbs identifies which flags are known to printf for each verb. 805 var printVerbs = []printVerb{ 806 // '-' is a width modifier, always valid. 807 // '.' is a precision for float, max width for strings. 808 // '+' is required sign for numbers, Go format for %v. 809 // '#' is alternate format for several verbs. 810 // ' ' is spacer for numbers 811 {'%', noFlag, 0}, 812 {'b', sharpNumFlag, argInt | argFloat | argComplex | argPointer}, 813 {'c', "-", argRune | argInt}, 814 {'d', numFlag, argInt | argPointer}, 815 {'e', sharpNumFlag, argFloat | argComplex}, 816 {'E', sharpNumFlag, argFloat | argComplex}, 817 {'f', sharpNumFlag, argFloat | argComplex}, 818 {'F', sharpNumFlag, argFloat | argComplex}, 819 {'g', sharpNumFlag, argFloat | argComplex}, 820 {'G', sharpNumFlag, argFloat | argComplex}, 821 {'o', sharpNumFlag, argInt | argPointer}, 822 {'O', sharpNumFlag, argInt | argPointer}, 823 {'p', "-#", argPointer}, 824 {'q', " -+.0#", argRune | argInt | argString}, 825 {'s', " -+.0", argString}, 826 {'t', "-", argBool}, 827 {'T', "-", anyType}, 828 {'U', "-#", argRune | argInt}, 829 {'v', allFlags, anyType}, 830 {'w', allFlags, argError}, 831 {'x', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex}, 832 {'X', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex}, 833 } 834 835 // okPrintfArg compares the formatState to the arguments actually present, 836 // reporting any discrepancies it can discern. If the final argument is ellipsissed, 837 // there's little it can do for that. 838 func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (ok bool) { 839 var v printVerb 840 found := false 841 // Linear scan is fast enough for a small list. 842 for _, v = range printVerbs { 843 if v.verb == state.verb { 844 found = true 845 break 846 } 847 } 848 849 // Could current arg implement fmt.Formatter? 850 // Skip check for the %w verb, which requires an error. 851 formatter := false 852 if v.typ != argError && state.argNum < len(call.Args) { 853 if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok { 854 formatter = isFormatter(tv.Type) 855 } 856 } 857 858 if !formatter { 859 if !found { 860 pass.ReportRangef(call, "%s format %s has unknown verb %c", state.name, state.format, state.verb) 861 return false 862 } 863 for _, flag := range state.flags { 864 // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11. 865 // See issues 23598 and 23605. 866 if flag == '0' { 867 continue 868 } 869 if !strings.ContainsRune(v.flags, rune(flag)) { 870 pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag) 871 return false 872 } 873 } 874 } 875 // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all 876 // but the final arg must be an integer. 877 trueArgs := 1 878 if state.verb == '%' { 879 trueArgs = 0 880 } 881 nargs := len(state.argNums) 882 for i := 0; i < nargs-trueArgs; i++ { 883 argNum := state.argNums[i] 884 if !argCanBeChecked(pass, call, i, state) { 885 return 886 } 887 arg := call.Args[argNum] 888 if reason, ok := matchArgType(pass, argInt, arg); !ok { 889 details := "" 890 if reason != "" { 891 details = " (" + reason + ")" 892 } 893 pass.ReportRangef(call, "%s format %s uses non-int %s%s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg), details) 894 return false 895 } 896 } 897 898 if state.verb == '%' || formatter { 899 return true 900 } 901 argNum := state.argNums[len(state.argNums)-1] 902 if !argCanBeChecked(pass, call, len(state.argNums)-1, state) { 903 return false 904 } 905 arg := call.Args[argNum] 906 if isFunctionValue(pass, arg) && state.verb != 'p' && state.verb != 'T' { 907 pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg)) 908 return false 909 } 910 if reason, ok := matchArgType(pass, v.typ, arg); !ok { 911 typeString := "" 912 if typ := pass.TypesInfo.Types[arg].Type; typ != nil { 913 typeString = typ.String() 914 } 915 details := "" 916 if reason != "" { 917 details = " (" + reason + ")" 918 } 919 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) 920 return false 921 } 922 if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) { 923 if methodName, ok := recursiveStringer(pass, arg); ok { 924 pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", state.name, state.format, analysisutil.Format(pass.Fset, arg), methodName) 925 return false 926 } 927 } 928 return true 929 } 930 931 // recursiveStringer reports whether the argument e is a potential 932 // recursive call to stringer or is an error, such as t and &t in these examples: 933 // 934 // func (t *T) String() string { printf("%s", t) } 935 // func (t T) Error() string { printf("%s", t) } 936 // func (t T) String() string { printf("%s", &t) } 937 func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) { 938 typ := pass.TypesInfo.Types[e].Type 939 940 // It's unlikely to be a recursive stringer if it has a Format method. 941 if isFormatter(typ) { 942 return "", false 943 } 944 945 // Does e allow e.String() or e.Error()? 946 strObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "String") 947 strMethod, strOk := strObj.(*types.Func) 948 errObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "Error") 949 errMethod, errOk := errObj.(*types.Func) 950 if !strOk && !errOk { 951 return "", false 952 } 953 954 // Is the expression e within the body of that String or Error method? 955 var method *types.Func 956 if strOk && strMethod.Pkg() == pass.Pkg && strMethod.Scope().Contains(e.Pos()) { 957 method = strMethod 958 } else if errOk && errMethod.Pkg() == pass.Pkg && errMethod.Scope().Contains(e.Pos()) { 959 method = errMethod 960 } else { 961 return "", false 962 } 963 964 sig := method.Type().(*types.Signature) 965 if !isStringer(sig) { 966 return "", false 967 } 968 969 // Is it the receiver r, or &r? 970 if u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.AND { 971 e = u.X // strip off & from &r 972 } 973 if id, ok := e.(*ast.Ident); ok { 974 if pass.TypesInfo.Uses[id] == sig.Recv() { 975 return method.FullName(), true 976 } 977 } 978 return "", false 979 } 980 981 // isStringer reports whether the method signature matches the String() definition in fmt.Stringer. 982 func isStringer(sig *types.Signature) bool { 983 return sig.Params().Len() == 0 && 984 sig.Results().Len() == 1 && 985 sig.Results().At(0).Type() == types.Typ[types.String] 986 } 987 988 // isFunctionValue reports whether the expression is a function as opposed to a function call. 989 // It is almost always a mistake to print a function value. 990 func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool { 991 if typ := pass.TypesInfo.Types[e].Type; typ != nil { 992 _, ok := typ.(*types.Signature) 993 return ok 994 } 995 return false 996 } 997 998 // argCanBeChecked reports whether the specified argument is statically present; 999 // it may be beyond the list of arguments or in a terminal slice... argument, which 1000 // means we can't see it. 1001 func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool { 1002 argNum := state.argNums[formatArg] 1003 if argNum <= 0 { 1004 // Shouldn't happen, so catch it with prejudice. 1005 panic("negative arg num") 1006 } 1007 if argNum < len(call.Args)-1 { 1008 return true // Always OK. 1009 } 1010 if call.Ellipsis.IsValid() { 1011 return false // We just can't tell; there could be many more arguments. 1012 } 1013 if argNum < len(call.Args) { 1014 return true 1015 } 1016 // There are bad indexes in the format or there are fewer arguments than the format needs. 1017 // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi". 1018 arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed. 1019 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")) 1020 return false 1021 } 1022 1023 // printFormatRE is the regexp we match and report as a possible format string 1024 // in the first argument to unformatted prints like fmt.Print. 1025 // We exclude the space flag, so that printing a string like "x % y" is not reported as a format. 1026 var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE) 1027 1028 const ( 1029 flagsRE = `[+\-#]*` 1030 indexOptRE = `(\[[0-9]+\])?` 1031 numOptRE = `([0-9]+|` + indexOptRE + `\*)?` 1032 verbRE = `[bcdefgopqstvxEFGTUX]` 1033 ) 1034 1035 // checkPrint checks a call to an unformatted print routine such as Println. 1036 func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { 1037 firstArg := 0 1038 typ := pass.TypesInfo.Types[call.Fun].Type 1039 if typ == nil { 1040 // Skip checking functions with unknown type. 1041 return 1042 } 1043 if sig, ok := typ.(*types.Signature); ok { 1044 if !sig.Variadic() { 1045 // Skip checking non-variadic functions. 1046 return 1047 } 1048 params := sig.Params() 1049 firstArg = params.Len() - 1 1050 1051 typ := params.At(firstArg).Type() 1052 typ = typ.(*types.Slice).Elem() 1053 it, ok := typ.(*types.Interface) 1054 if !ok || !it.Empty() { 1055 // Skip variadic functions accepting non-interface{} args. 1056 return 1057 } 1058 } 1059 args := call.Args 1060 if len(args) <= firstArg { 1061 // Skip calls without variadic args. 1062 return 1063 } 1064 args = args[firstArg:] 1065 1066 if firstArg == 0 { 1067 if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { 1068 if x, ok := sel.X.(*ast.Ident); ok { 1069 if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { 1070 pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.FullName(), analysisutil.Format(pass.Fset, call.Args[0])) 1071 } 1072 } 1073 } 1074 } 1075 1076 arg := args[0] 1077 if s, ok := stringConstantExpr(pass, arg); ok { 1078 // Ignore trailing % character 1079 // The % in "abc 0.0%" couldn't be a formatting directive. 1080 s = strings.TrimSuffix(s, "%") 1081 if strings.Contains(s, "%") { 1082 m := printFormatRE.FindStringSubmatch(s) 1083 if m != nil { 1084 pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.FullName(), m[0]) 1085 } 1086 } 1087 } 1088 if strings.HasSuffix(fn.Name(), "ln") { 1089 // The last item, if a string, should not have a newline. 1090 arg = args[len(args)-1] 1091 if s, ok := stringConstantExpr(pass, arg); ok { 1092 if strings.HasSuffix(s, "\n") { 1093 pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName()) 1094 } 1095 } 1096 } 1097 for _, arg := range args { 1098 if isFunctionValue(pass, arg) { 1099 pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg)) 1100 } 1101 if methodName, ok := recursiveStringer(pass, arg); ok { 1102 pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName) 1103 } 1104 } 1105 } 1106 1107 // count(n, what) returns "1 what" or "N whats" 1108 // (assuming the plural of what is whats). 1109 func count(n int, what string) string { 1110 if n == 1 { 1111 return "1 " + what 1112 } 1113 return fmt.Sprintf("%d %ss", n, what) 1114 } 1115 1116 // stringSet is a set-of-nonempty-strings-valued flag. 1117 // Note: elements without a '.' get lower-cased. 1118 type stringSet map[string]bool 1119 1120 func (ss stringSet) String() string { 1121 var list []string 1122 for name := range ss { 1123 list = append(list, name) 1124 } 1125 sort.Strings(list) 1126 return strings.Join(list, ",") 1127 } 1128 1129 func (ss stringSet) Set(flag string) error { 1130 for _, name := range strings.Split(flag, ",") { 1131 if len(name) == 0 { 1132 return fmt.Errorf("empty string") 1133 } 1134 if !strings.Contains(name, ".") { 1135 name = strings.ToLower(name) 1136 } 1137 ss[name] = true 1138 } 1139 return nil 1140 }