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.FullName()) 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.FullName()) 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.FullName(), 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 switch kind { 593 case KindNone, KindPrint: 594 pass.Reportf(call.Pos(), "%s does not support error-wrapping directive %%w", state.name) 595 return 596 case KindPrintf: 597 pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w, which is only supported for functions backed by fmt.Errorf", state.name) 598 return 599 } 600 if anyW { 601 pass.Reportf(call.Pos(), "%s call has more than one error-wrapping directive %%w", state.name) 602 return 603 } 604 anyW = true 605 } 606 if len(state.argNums) > 0 { 607 // Continue with the next sequential argument. 608 argNum = state.argNums[len(state.argNums)-1] + 1 609 } 610 for _, n := range state.argNums { 611 if n >= maxArgNum { 612 maxArgNum = n + 1 613 } 614 } 615 } 616 // Dotdotdot is hard. 617 if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 { 618 return 619 } 620 // If any formats are indexed, extra arguments are ignored. 621 if anyIndex { 622 return 623 } 624 // There should be no leftover arguments. 625 if maxArgNum != len(call.Args) { 626 expect := maxArgNum - firstArg 627 numArgs := len(call.Args) - firstArg 628 pass.ReportRangef(call, "%s call needs %v but has %v", fn.FullName(), count(expect, "arg"), count(numArgs, "arg")) 629 } 630} 631 632// parseFlags accepts any printf flags. 633func (s *formatState) parseFlags() { 634 for s.nbytes < len(s.format) { 635 switch c := s.format[s.nbytes]; c { 636 case '#', '0', '+', '-', ' ': 637 s.flags = append(s.flags, c) 638 s.nbytes++ 639 default: 640 return 641 } 642 } 643} 644 645// scanNum advances through a decimal number if present. 646func (s *formatState) scanNum() { 647 for ; s.nbytes < len(s.format); s.nbytes++ { 648 c := s.format[s.nbytes] 649 if c < '0' || '9' < c { 650 return 651 } 652 } 653} 654 655// parseIndex scans an index expression. It returns false if there is a syntax error. 656func (s *formatState) parseIndex() bool { 657 if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' { 658 return true 659 } 660 // Argument index present. 661 s.nbytes++ // skip '[' 662 start := s.nbytes 663 s.scanNum() 664 ok := true 665 if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' { 666 ok = false 667 s.nbytes = strings.Index(s.format, "]") 668 if s.nbytes < 0 { 669 s.pass.ReportRangef(s.call, "%s format %s is missing closing ]", s.name, s.format) 670 return false 671 } 672 } 673 arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32) 674 if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) { 675 s.pass.ReportRangef(s.call, "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes]) 676 return false 677 } 678 s.nbytes++ // skip ']' 679 arg := int(arg32) 680 arg += s.firstArg - 1 // We want to zero-index the actual arguments. 681 s.argNum = arg 682 s.hasIndex = true 683 s.indexPending = true 684 return true 685} 686 687// parseNum scans a width or precision (or *). It returns false if there's a bad index expression. 688func (s *formatState) parseNum() bool { 689 if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' { 690 if s.indexPending { // Absorb it. 691 s.indexPending = false 692 } 693 s.nbytes++ 694 s.argNums = append(s.argNums, s.argNum) 695 s.argNum++ 696 } else { 697 s.scanNum() 698 } 699 return true 700} 701 702// parsePrecision scans for a precision. It returns false if there's a bad index expression. 703func (s *formatState) parsePrecision() bool { 704 // If there's a period, there may be a precision. 705 if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' { 706 s.flags = append(s.flags, '.') // Treat precision as a flag. 707 s.nbytes++ 708 if !s.parseIndex() { 709 return false 710 } 711 if !s.parseNum() { 712 return false 713 } 714 } 715 return true 716} 717 718// parsePrintfVerb looks the formatting directive that begins the format string 719// and returns a formatState that encodes what the directive wants, without looking 720// at the actual arguments present in the call. The result is nil if there is an error. 721func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState { 722 state := &formatState{ 723 format: format, 724 name: name, 725 flags: make([]byte, 0, 5), 726 argNum: argNum, 727 argNums: make([]int, 0, 1), 728 nbytes: 1, // There's guaranteed to be a percent sign. 729 firstArg: firstArg, 730 pass: pass, 731 call: call, 732 } 733 // There may be flags. 734 state.parseFlags() 735 // There may be an index. 736 if !state.parseIndex() { 737 return nil 738 } 739 // There may be a width. 740 if !state.parseNum() { 741 return nil 742 } 743 // There may be a precision. 744 if !state.parsePrecision() { 745 return nil 746 } 747 // Now a verb, possibly prefixed by an index (which we may already have). 748 if !state.indexPending && !state.parseIndex() { 749 return nil 750 } 751 if state.nbytes == len(state.format) { 752 pass.ReportRangef(call.Fun, "%s format %s is missing verb at end of string", name, state.format) 753 return nil 754 } 755 verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:]) 756 state.verb = verb 757 state.nbytes += w 758 if verb != '%' { 759 state.argNums = append(state.argNums, state.argNum) 760 } 761 state.format = state.format[:state.nbytes] 762 return state 763} 764 765// printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask. 766type printfArgType int 767 768const ( 769 argBool printfArgType = 1 << iota 770 argInt 771 argRune 772 argString 773 argFloat 774 argComplex 775 argPointer 776 argError 777 anyType printfArgType = ^0 778) 779 780type printVerb struct { 781 verb rune // User may provide verb through Formatter; could be a rune. 782 flags string // known flags are all ASCII 783 typ printfArgType 784} 785 786// Common flag sets for printf verbs. 787const ( 788 noFlag = "" 789 numFlag = " -+.0" 790 sharpNumFlag = " -+.0#" 791 allFlags = " -+.0#" 792) 793 794// printVerbs identifies which flags are known to printf for each verb. 795var printVerbs = []printVerb{ 796 // '-' is a width modifier, always valid. 797 // '.' is a precision for float, max width for strings. 798 // '+' is required sign for numbers, Go format for %v. 799 // '#' is alternate format for several verbs. 800 // ' ' is spacer for numbers 801 {'%', noFlag, 0}, 802 {'b', sharpNumFlag, argInt | argFloat | argComplex | argPointer}, 803 {'c', "-", argRune | argInt}, 804 {'d', numFlag, argInt | argPointer}, 805 {'e', sharpNumFlag, argFloat | argComplex}, 806 {'E', sharpNumFlag, argFloat | argComplex}, 807 {'f', sharpNumFlag, argFloat | argComplex}, 808 {'F', sharpNumFlag, argFloat | argComplex}, 809 {'g', sharpNumFlag, argFloat | argComplex}, 810 {'G', sharpNumFlag, argFloat | argComplex}, 811 {'o', sharpNumFlag, argInt | argPointer}, 812 {'O', sharpNumFlag, argInt | argPointer}, 813 {'p', "-#", argPointer}, 814 {'q', " -+.0#", argRune | argInt | argString}, 815 {'s', " -+.0", argString}, 816 {'t', "-", argBool}, 817 {'T', "-", anyType}, 818 {'U', "-#", argRune | argInt}, 819 {'v', allFlags, anyType}, 820 {'w', allFlags, argError}, 821 {'x', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex}, 822 {'X', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex}, 823} 824 825// okPrintfArg compares the formatState to the arguments actually present, 826// reporting any discrepancies it can discern. If the final argument is ellipsissed, 827// there's little it can do for that. 828func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (ok bool) { 829 var v printVerb 830 found := false 831 // Linear scan is fast enough for a small list. 832 for _, v = range printVerbs { 833 if v.verb == state.verb { 834 found = true 835 break 836 } 837 } 838 839 // Could current arg implement fmt.Formatter? 840 formatter := false 841 if state.argNum < len(call.Args) { 842 if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok { 843 formatter = isFormatter(tv.Type) 844 } 845 } 846 847 if !formatter { 848 if !found { 849 pass.ReportRangef(call, "%s format %s has unknown verb %c", state.name, state.format, state.verb) 850 return false 851 } 852 for _, flag := range state.flags { 853 // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11. 854 // See issues 23598 and 23605. 855 if flag == '0' { 856 continue 857 } 858 if !strings.ContainsRune(v.flags, rune(flag)) { 859 pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag) 860 return false 861 } 862 } 863 } 864 // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all 865 // but the final arg must be an integer. 866 trueArgs := 1 867 if state.verb == '%' { 868 trueArgs = 0 869 } 870 nargs := len(state.argNums) 871 for i := 0; i < nargs-trueArgs; i++ { 872 argNum := state.argNums[i] 873 if !argCanBeChecked(pass, call, i, state) { 874 return 875 } 876 arg := call.Args[argNum] 877 if !matchArgType(pass, argInt, nil, arg) { 878 pass.ReportRangef(call, "%s format %s uses non-int %s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg)) 879 return false 880 } 881 } 882 883 if state.verb == '%' || formatter { 884 return true 885 } 886 argNum := state.argNums[len(state.argNums)-1] 887 if !argCanBeChecked(pass, call, len(state.argNums)-1, state) { 888 return false 889 } 890 arg := call.Args[argNum] 891 if isFunctionValue(pass, arg) && state.verb != 'p' && state.verb != 'T' { 892 pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg)) 893 return false 894 } 895 if !matchArgType(pass, v.typ, nil, arg) { 896 typeString := "" 897 if typ := pass.TypesInfo.Types[arg].Type; typ != nil { 898 typeString = typ.String() 899 } 900 pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString) 901 return false 902 } 903 if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) { 904 if methodName, ok := recursiveStringer(pass, arg); ok { 905 pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", state.name, state.format, analysisutil.Format(pass.Fset, arg), methodName) 906 return false 907 } 908 } 909 return true 910} 911 912// recursiveStringer reports whether the argument e is a potential 913// recursive call to stringer or is an error, such as t and &t in these examples: 914// 915// func (t *T) String() string { printf("%s", t) } 916// func (t T) Error() string { printf("%s", t) } 917// func (t T) String() string { printf("%s", &t) } 918func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) { 919 typ := pass.TypesInfo.Types[e].Type 920 921 // It's unlikely to be a recursive stringer if it has a Format method. 922 if isFormatter(typ) { 923 return "", false 924 } 925 926 // Does e allow e.String() or e.Error()? 927 strObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "String") 928 strMethod, strOk := strObj.(*types.Func) 929 errObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "Error") 930 errMethod, errOk := errObj.(*types.Func) 931 if !strOk && !errOk { 932 return "", false 933 } 934 935 // Is the expression e within the body of that String or Error method? 936 var method *types.Func 937 if strOk && strMethod.Pkg() == pass.Pkg && strMethod.Scope().Contains(e.Pos()) { 938 method = strMethod 939 } else if errOk && errMethod.Pkg() == pass.Pkg && errMethod.Scope().Contains(e.Pos()) { 940 method = errMethod 941 } else { 942 return "", false 943 } 944 945 sig := method.Type().(*types.Signature) 946 if !isStringer(sig) { 947 return "", false 948 } 949 950 // Is it the receiver r, or &r? 951 if u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.AND { 952 e = u.X // strip off & from &r 953 } 954 if id, ok := e.(*ast.Ident); ok { 955 if pass.TypesInfo.Uses[id] == sig.Recv() { 956 return method.FullName(), true 957 } 958 } 959 return "", false 960} 961 962// isStringer reports whether the method signature matches the String() definition in fmt.Stringer. 963func isStringer(sig *types.Signature) bool { 964 return sig.Params().Len() == 0 && 965 sig.Results().Len() == 1 && 966 sig.Results().At(0).Type() == types.Typ[types.String] 967} 968 969// isFunctionValue reports whether the expression is a function as opposed to a function call. 970// It is almost always a mistake to print a function value. 971func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool { 972 if typ := pass.TypesInfo.Types[e].Type; typ != nil { 973 _, ok := typ.(*types.Signature) 974 return ok 975 } 976 return false 977} 978 979// argCanBeChecked reports whether the specified argument is statically present; 980// it may be beyond the list of arguments or in a terminal slice... argument, which 981// means we can't see it. 982func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool { 983 argNum := state.argNums[formatArg] 984 if argNum <= 0 { 985 // Shouldn't happen, so catch it with prejudice. 986 panic("negative arg num") 987 } 988 if argNum < len(call.Args)-1 { 989 return true // Always OK. 990 } 991 if call.Ellipsis.IsValid() { 992 return false // We just can't tell; there could be many more arguments. 993 } 994 if argNum < len(call.Args) { 995 return true 996 } 997 // There are bad indexes in the format or there are fewer arguments than the format needs. 998 // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi". 999 arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed. 1000 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")) 1001 return false 1002} 1003 1004// printFormatRE is the regexp we match and report as a possible format string 1005// in the first argument to unformatted prints like fmt.Print. 1006// We exclude the space flag, so that printing a string like "x % y" is not reported as a format. 1007var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE) 1008 1009const ( 1010 flagsRE = `[+\-#]*` 1011 indexOptRE = `(\[[0-9]+\])?` 1012 numOptRE = `([0-9]+|` + indexOptRE + `\*)?` 1013 verbRE = `[bcdefgopqstvxEFGTUX]` 1014) 1015 1016// checkPrint checks a call to an unformatted print routine such as Println. 1017func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) { 1018 firstArg := 0 1019 typ := pass.TypesInfo.Types[call.Fun].Type 1020 if typ == nil { 1021 // Skip checking functions with unknown type. 1022 return 1023 } 1024 if sig, ok := typ.(*types.Signature); ok { 1025 if !sig.Variadic() { 1026 // Skip checking non-variadic functions. 1027 return 1028 } 1029 params := sig.Params() 1030 firstArg = params.Len() - 1 1031 1032 typ := params.At(firstArg).Type() 1033 typ = typ.(*types.Slice).Elem() 1034 it, ok := typ.(*types.Interface) 1035 if !ok || !it.Empty() { 1036 // Skip variadic functions accepting non-interface{} args. 1037 return 1038 } 1039 } 1040 args := call.Args 1041 if len(args) <= firstArg { 1042 // Skip calls without variadic args. 1043 return 1044 } 1045 args = args[firstArg:] 1046 1047 if firstArg == 0 { 1048 if sel, ok := call.Args[0].(*ast.SelectorExpr); ok { 1049 if x, ok := sel.X.(*ast.Ident); ok { 1050 if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") { 1051 pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.FullName(), analysisutil.Format(pass.Fset, call.Args[0])) 1052 } 1053 } 1054 } 1055 } 1056 1057 arg := args[0] 1058 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { 1059 // Ignore trailing % character in lit.Value. 1060 // The % in "abc 0.0%" couldn't be a formatting directive. 1061 s := strings.TrimSuffix(lit.Value, `%"`) 1062 if strings.Contains(s, "%") { 1063 m := printFormatRE.FindStringSubmatch(s) 1064 if m != nil { 1065 pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.FullName(), m[0]) 1066 } 1067 } 1068 } 1069 if strings.HasSuffix(fn.Name(), "ln") { 1070 // The last item, if a string, should not have a newline. 1071 arg = args[len(args)-1] 1072 if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { 1073 str, _ := strconv.Unquote(lit.Value) 1074 if strings.HasSuffix(str, "\n") { 1075 pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.FullName()) 1076 } 1077 } 1078 } 1079 for _, arg := range args { 1080 if isFunctionValue(pass, arg) { 1081 pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg)) 1082 } 1083 if methodName, ok := recursiveStringer(pass, arg); ok { 1084 pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName) 1085 } 1086 } 1087} 1088 1089// count(n, what) returns "1 what" or "N whats" 1090// (assuming the plural of what is whats). 1091func count(n int, what string) string { 1092 if n == 1 { 1093 return "1 " + what 1094 } 1095 return fmt.Sprintf("%d %ss", n, what) 1096} 1097 1098// stringSet is a set-of-nonempty-strings-valued flag. 1099// Note: elements without a '.' get lower-cased. 1100type stringSet map[string]bool 1101 1102func (ss stringSet) String() string { 1103 var list []string 1104 for name := range ss { 1105 list = append(list, name) 1106 } 1107 sort.Strings(list) 1108 return strings.Join(list, ",") 1109} 1110 1111func (ss stringSet) Set(flag string) error { 1112 for _, name := range strings.Split(flag, ",") { 1113 if len(name) == 0 { 1114 return fmt.Errorf("empty string") 1115 } 1116 if !strings.Contains(name, ".") { 1117 name = strings.ToLower(name) 1118 } 1119 ss[name] = true 1120 } 1121 return nil 1122} 1123