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.
5 // Package printf defines an Analyzer that checks consistency
6 // of Printf format strings and arguments.
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"
31 Analyzer.Flags.Var(isPrint, "funcs", "comma-separated list of print function names to check")
34 var Analyzer = &analysis.Analyzer{
37 Requires: []*analysis.Analyzer{inspect.Analyzer},
39 ResultType: reflect.TypeOf((*Result)(nil)),
40 FactTypes: []analysis.Fact{new(isWrapper)},
43 const Doc = `check consistency of Printf format strings and arguments
45 The check applies to known functions (for example, those in package fmt)
46 as well as any detected wrappers of known functions.
48 A function that wants to avail itself of printf checking but is not
49 found by this analyzer's heuristics (for example, due to use of
50 dynamic calls) can insert a bogus call:
53 _ = fmt.Sprintf(format, args...) // enable printf checking
56 The -funcs flag specifies a comma-separated list of names of additional
57 known formatting functions or methods. If the name contains a period,
58 it must denote a specific function using one of the following forms:
62 (*dir/pkg.Type).Method
64 Otherwise the name is interpreted as a case-insensitive unqualified
65 identifier such as "errorf". Either way, if a listed name ends in f, the
66 function is assumed to be Printf-like, taking a format string before the
67 argument list. Otherwise it is assumed to be Print-like, taking a list
68 of arguments with no format string.
71 // Kind is a kind of fmt function behavior.
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
81 func (kind Kind) String() string {
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.
96 funcs map[*types.Func]Kind
99 // Kind reports whether fn behaves like fmt.Print or fmt.Printf.
100 func (r *Result) Kind(fn *types.Func) Kind {
101 _, ok := isPrint[fn.FullName()]
103 // Next look up just "printf", for use with -printf.funcs.
104 _, ok = isPrint[strings.ToLower(fn.Name())]
107 if strings.HasSuffix(fn.Name(), "f") {
117 // isWrapper is a fact indicating that a function is a print or printf wrapper.
118 type isWrapper struct{ Kind Kind }
120 func (f *isWrapper) AFact() {}
122 func (f *isWrapper) String() string {
125 return "printfWrapper"
127 return "printWrapper"
129 return "errorfWrapper"
131 return "unknownWrapper"
135 func run(pass *analysis.Pass) (interface{}, error) {
137 funcs: make(map[*types.Func]Kind),
139 findPrintfLike(pass, res)
144 type printfWrapper struct {
149 callers []printfCaller
150 failed bool // if true, not a printf wrapper
153 type printfCaller struct {
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.
165 func 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 {
171 fn, ok := info.Defs[fdecl.Name].(*types.Func)
172 // Type information may be incomplete.
177 sig := fn.Type().(*types.Signature)
179 return nil // not variadic
182 params := sig.Params()
183 nparams := params.Len() // variadic => nonzero
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{}
191 // Is second last param 'format string'?
192 var format *types.Var
194 if p := params.At(nparams - 2); p.Type() == types.Typ[types.String] {
199 return &printfWrapper{
207 // findPrintfLike scans the entire package to find printf-like functions.
208 func 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)
219 wrappers = append(wrappers, w)
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 {
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
238 // some way, so not a
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.
256 call, ok := n.(*ast.CallExpr)
257 if !ok || len(call.Args) == 0 || !match(pass.TypesInfo, call.Args[len(call.Args)-1], w.args) {
261 fn, kind := printfNameAndKind(pass, call)
263 checkPrintfFwd(pass, w, call, kind, res)
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 {
272 callee.callers = append(callee.callers, printfCaller{w, call})
281 func match(info *types.Info, arg ast.Expr, param *types.Var) bool {
282 id, ok := arg.(*ast.Ident)
283 return ok && info.ObjectOf(id) == param
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...).
288 func 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)
295 if !call.Ellipsis.IsValid() {
296 typ, ok := pass.TypesInfo.Types[call.Fun].Type.(*types.Signature)
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:
305 // func foo(arg1 string, arg2 ...interface{} {
306 // fmt.Printf("%s %v", arg1, arg2)
311 if kind == KindPrint {
314 pass.ReportRangef(call, "missing ... in args forwarded to %s-like function", desc)
319 if !pass.ImportObjectFact(fn, &fact) {
321 pass.ExportObjectFact(fn, &fact)
323 for _, caller := range w.callers {
324 checkPrintfFwd(pass, caller.w, caller.call, kind, res)
329 // isPrint records the print functions.
330 // If a key ends in 'f' then it is assumed to be a formatted print.
332 // Keys are either values returned by (*types.Func).FullName,
333 // or case-insensitive identifiers such as "errorf".
335 // The -funcs flag adds to this set.
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
345 var isPrint = stringSet{
349 "fmt.Fprintln": true,
355 "fmt.Sprintln": true,
357 "runtime/trace.Logf": 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,
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,
398 // formatString returns the format string argument and its index within
399 // the given printf-like call expression.
401 // The last parameter before variadic arguments is assumed to be
404 // The first string literal or string constant is assumed to be a format string
405 // if the call's signature cannot be determined.
407 // If it cannot find any format string parameter, it returns ("", -1).
408 func formatString(pass *analysis.Pass, call *ast.CallExpr) (format string, idx int) {
409 typ := pass.TypesInfo.Types[call.Fun].Type
411 if sig, ok := typ.(*types.Signature); ok {
413 // Skip checking non-variadic functions.
416 idx := sig.Params().Len() - 2
418 // Skip checking variadic functions without
422 s, ok := stringConstantArg(pass, call, idx)
424 // The last argument before variadic args isn't a string.
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 {
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
447 // stringConstantArg returns call's string constant argument at the index idx.
449 // ("", false) is returned if call's argument at the index idx isn't a string
451 func stringConstantArg(pass *analysis.Pass, call *ast.CallExpr, idx int) (string, bool) {
452 if idx >= len(call.Args) {
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
463 // checkCall triggers the print-specific checks if the call invokes a print function.
464 func checkCall(pass *analysis.Pass) {
465 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
466 nodeFilter := []ast.Node{
467 (*ast.CallExpr)(nil),
469 inspect.Preorder(nodeFilter, func(n ast.Node) {
470 call := n.(*ast.CallExpr)
471 fn, kind := printfNameAndKind(pass, call)
473 case KindPrintf, KindErrorf:
474 checkPrintf(pass, kind, call, fn)
476 checkPrint(pass, call, fn)
481 func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind Kind) {
482 fn, _ = typeutil.Callee(pass.TypesInfo, call).(*types.Func)
487 _, ok := isPrint[fn.FullName()]
489 // Next look up just "printf", for use with -printf.funcs.
490 _, ok = isPrint[strings.ToLower(fn.Name())]
493 if fn.Name() == "Errorf" {
495 } else if strings.HasSuffix(fn.Name(), "f") {
504 if pass.ImportObjectFact(fn, &fact) {
511 // isFormatter reports whether t could satisfy fmt.Formatter.
512 // The only interface method to look for is "Format(State, rune)".
513 func 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 {
518 obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format")
519 fn, ok := obj.(*types.Func)
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])
530 func 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
535 // formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
536 // It is constructed by parsePrintfVerb.
537 type 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.
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.
553 // checkPrintf checks a call to a formatted print routine such as Printf.
554 func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.Func) {
555 format, idx := formatString(pass, call)
558 pass.Reportf(call.Lparen, "can't check non-constant format in call to %s", fn.Name())
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())
570 // Hard part: check formats against args.
572 maxArgNum := firstArg
575 for i, w := 0, 0; i < len(format); i += w {
577 if format[i] != '%' {
580 state := parsePrintfVerb(pass, call, fn.Name(), format[i:], firstArg, argNum)
584 w = len(state.format)
585 if !okPrintfArg(pass, call, state) { // One error per format is enough.
591 if state.verb == 'w' {
592 if kind != KindErrorf {
593 pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w", state.name)
597 pass.Reportf(call.Pos(), "%s call has more than one error-wrapping directive %%w", state.name)
602 if len(state.argNums) > 0 {
603 // Continue with the next sequential argument.
604 argNum = state.argNums[len(state.argNums)-1] + 1
606 for _, n := range state.argNums {
612 // Dotdotdot is hard.
613 if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
616 // If any formats are indexed, extra arguments are ignored.
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"))
628 // parseFlags accepts any printf flags.
629 func (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)
641 // scanNum advances through a decimal number if present.
642 func (s *formatState) scanNum() {
643 for ; s.nbytes < len(s.format); s.nbytes++ {
644 c := s.format[s.nbytes]
645 if c < '0' || '9' < c {
651 // parseIndex scans an index expression. It returns false if there is a syntax error.
652 func (s *formatState) parseIndex() bool {
653 if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' {
656 // Argument index present.
657 s.nbytes++ // skip '['
661 if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
663 s.nbytes = strings.Index(s.format, "]")
665 s.pass.ReportRangef(s.call, "%s format %s is missing closing ]", s.name, s.format)
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])
674 s.nbytes++ // skip ']'
676 arg += s.firstArg - 1 // We want to zero-index the actual arguments.
679 s.indexPending = true
683 // parseNum scans a width or precision (or *). It returns false if there's a bad index expression.
684 func (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
690 s.argNums = append(s.argNums, s.argNum)
698 // parsePrecision scans for a precision. It returns false if there's a bad index expression.
699 func (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.
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.
717 func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
718 state := &formatState{
721 flags: make([]byte, 0, 5),
723 argNums: make([]int, 0, 1),
724 nbytes: 1, // There's guaranteed to be a percent sign.
729 // There may be flags.
731 // There may be an index.
732 if !state.parseIndex() {
735 // There may be a width.
736 if !state.parseNum() {
739 // There may be a precision.
740 if !state.parsePrecision() {
743 // Now a verb, possibly prefixed by an index (which we may already have).
744 if !state.indexPending && !state.parseIndex() {
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)
751 verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
755 state.argNums = append(state.argNums, state.argNum)
757 state.format = state.format[:state.nbytes]
761 // printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.
762 type printfArgType int
765 argBool printfArgType = 1 << iota
773 anyType printfArgType = ^0
776 type printVerb struct {
777 verb rune // User may provide verb through Formatter; could be a rune.
778 flags string // known flags are all ASCII
782 // Common flag sets for printf verbs.
786 sharpNumFlag = " -+.0#"
790 // printVerbs identifies which flags are known to printf for each verb.
791 var 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
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},
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},
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.
824 func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (ok bool) {
827 // Linear scan is fast enough for a small list.
828 for _, v = range printVerbs {
829 if v.verb == state.verb {
835 // Could current arg implement fmt.Formatter?
837 if state.argNum < len(call.Args) {
838 if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok {
839 formatter = isFormatter(tv.Type)
845 pass.ReportRangef(call, "%s format %s has unknown verb %c", state.name, state.format, state.verb)
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.
854 if !strings.ContainsRune(v.flags, rune(flag)) {
855 pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag)
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.
863 if state.verb == '%' {
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) {
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))
879 if state.verb == '%' || formatter {
882 argNum := state.argNums[len(state.argNums)-1]
883 if !argCanBeChecked(pass, call, len(state.argNums)-1, state) {
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))
891 if !matchArgType(pass, v.typ, nil, arg) {
893 if typ := pass.TypesInfo.Types[arg].Type; typ != nil {
894 typeString = typ.String()
896 pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString)
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)
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:
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) }
914 func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) {
915 typ := pass.TypesInfo.Types[e].Type
917 // It's unlikely to be a recursive stringer if it has a Format method.
918 if isFormatter(typ) {
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 {
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()) {
935 } else if errOk && errMethod.Pkg() == pass.Pkg && errMethod.Scope().Contains(e.Pos()) {
941 sig := method.Type().(*types.Signature)
942 if !isStringer(sig) {
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
950 if id, ok := e.(*ast.Ident); ok {
951 if pass.TypesInfo.Uses[id] == sig.Recv() {
952 return method.Name(), true
958 // isStringer reports whether the method signature matches the String() definition in fmt.Stringer.
959 func 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]
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.
967 func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
968 if typ := pass.TypesInfo.Types[e].Type; typ != nil {
969 _, ok := typ.(*types.Signature)
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.
978 func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool {
979 argNum := state.argNums[formatArg]
981 // Shouldn't happen, so catch it with prejudice.
982 panic("negative arg num")
984 if argNum < len(call.Args)-1 {
985 return true // Always OK.
987 if call.Ellipsis.IsValid() {
988 return false // We just can't tell; there could be many more arguments.
990 if argNum < len(call.Args) {
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"))
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.
1003 var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE)
1007 indexOptRE = `(\[[0-9]+\])?`
1008 numOptRE = `([0-9]+|` + indexOptRE + `\*)?`
1009 verbRE = `[bcdefgopqstvxEFGTUX]`
1012 // checkPrint checks a call to an unformatted print routine such as Println.
1013 func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
1015 typ := pass.TypesInfo.Types[call.Fun].Type
1017 // Skip checking functions with unknown type.
1020 if sig, ok := typ.(*types.Signature); ok {
1021 if !sig.Variadic() {
1022 // Skip checking non-variadic functions.
1025 params := sig.Params()
1026 firstArg = params.Len() - 1
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.
1037 if len(args) <= firstArg {
1038 // Skip calls without variadic args.
1041 args = args[firstArg:]
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]))
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)
1061 pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.Name(), m[0])
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())
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))
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)
1085 // count(n, what) returns "1 what" or "N whats"
1086 // (assuming the plural of what is whats).
1087 func count(n int, what string) string {
1091 return fmt.Sprintf("%d %ss", n, what)
1094 // stringSet is a set-of-nonempty-strings-valued flag.
1095 // Note: elements without a '.' get lower-cased.
1096 type stringSet map[string]bool
1098 func (ss stringSet) String() string {
1100 for name := range ss {
1101 list = append(list, name)
1104 return strings.Join(list, ",")
1107 func (ss stringSet) Set(flag string) error {
1108 for _, name := range strings.Split(flag, ",") {
1110 return fmt.Errorf("empty string")
1112 if !strings.Contains(name, ".") {
1113 name = strings.ToLower(name)