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