GoPLS Viewer

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