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