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

View as plain text