...

Source file src/golang.org/x/tools/go/analysis/passes/printf/printf.go

Documentation: golang.org/x/tools/go/analysis/passes/printf

     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.
     7  package printf
     8  
     9  import (
    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  
    31  func init() {
    32  	Analyzer.Flags.Var(isPrint, "funcs", "comma-separated list of print function names to check")
    33  }
    34  
    35  var Analyzer = &analysis.Analyzer{
    36  	Name:       "printf",
    37  	Doc:        Doc,
    38  	Requires:   []*analysis.Analyzer{inspect.Analyzer},
    39  	Run:        run,
    40  	ResultType: reflect.TypeOf((*Result)(nil)),
    41  	FactTypes:  []analysis.Fact{new(isWrapper)},
    42  }
    43  
    44  const Doc = `check consistency of Printf format strings and arguments
    45  
    46  The check applies to known functions (for example, those in package fmt)
    47  as well as any detected wrappers of known functions.
    48  
    49  A function that wants to avail itself of printf checking but is not
    50  found by this analyzer's heuristics (for example, due to use of
    51  dynamic calls) can insert a bogus call:
    52  
    53  	if false {
    54  		_ = fmt.Sprintf(format, args...) // enable printf checking
    55  	}
    56  
    57  The -funcs flag specifies a comma-separated list of names of additional
    58  known formatting functions or methods. If the name contains a period,
    59  it 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  
    65  Otherwise the name is interpreted as a case-insensitive unqualified
    66  identifier such as "errorf". Either way, if a listed name ends in f, the
    67  function is assumed to be Printf-like, taking a format string before the
    68  argument list. Otherwise it is assumed to be Print-like, taking a list
    69  of arguments with no format string.
    70  `
    71  
    72  // Kind is a kind of fmt function behavior.
    73  type Kind int
    74  
    75  const (
    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  
    82  func (kind Kind) String() 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.
    96  type Result struct {
    97  	funcs map[*types.Func]Kind
    98  }
    99  
   100  // Kind reports whether fn behaves like fmt.Print or fmt.Printf.
   101  func (r *Result) Kind(fn *types.Func) Kind {
   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.
   119  type isWrapper struct{ Kind Kind }
   120  
   121  func (f *isWrapper) AFact() {}
   122  
   123  func (f *isWrapper) String() 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  
   136  func run(pass *analysis.Pass) (interface{}, error) {
   137  	res := &Result{
   138  		funcs: make(map[*types.Func]Kind),
   139  	}
   140  	findPrintfLike(pass, res)
   141  	checkCall(pass)
   142  	return res, nil
   143  }
   144  
   145  type 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  
   154  type 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.
   166  func maybePrintfWrapper(info *types.Info, decl ast.Decl) *printfWrapper {
   167  	// Look for functions with final argument type ...interface{}.
   168  	fdecl, ok := decl.(*ast.FuncDecl)
   169  	if !ok || fdecl.Body == nil {
   170  		return nil
   171  	}
   172  	fn, ok := 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  	iface, ok := 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  		format: format,
   204  		args:   args,
   205  	}
   206  }
   207  
   208  // findPrintfLike scans the entire package to find printf-like functions.
   209  func findPrintfLike(pass *analysis.Pass, res *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.TypesInfo, decl)
   216  			if w == nil {
   217  				continue
   218  			}
   219  			byObj[w.obj] = w
   220  			wrappers = append(wrappers, w)
   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.Node) bool {
   228  			if w.failed {
   229  				return false
   230  			}
   231  
   232  			// TODO: Relax these checks; issue 26555.
   233  			if assign, ok := n.(*ast.AssignStmt); ok {
   234  				for _, lhs := range assign.Lhs {
   235  					if match(pass.TypesInfo, lhs, w.format) ||
   236  						match(pass.TypesInfo, lhs, w.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 un, ok := n.(*ast.UnaryExpr); ok && un.Op == token.AND {
   247  				if match(pass.TypesInfo, un.X, w.format) ||
   248  					match(pass.TypesInfo, un.X, w.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  			call, ok := n.(*ast.CallExpr)
   258  			if !ok || len(call.Args) == 0 || !match(pass.TypesInfo, call.Args[len(call.Args)-1], w.args) {
   259  				return true
   260  			}
   261  
   262  			fn, kind := printfNameAndKind(pass, call)
   263  			if kind != 0 {
   264  				checkPrintfFwd(pass, w, call, kind, res)
   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.callers, printfCaller{w, call})
   274  			}
   275  
   276  			return true
   277  		})
   278  	}
   279  	return nil, nil
   280  }
   281  
   282  func match(info *types.Info, arg ast.Expr, param *types.Var) bool {
   283  	id, ok := 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...).
   289  func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind Kind, res *Result) {
   290  	matched := kind == KindPrint ||
   291  		kind != KindNone && len(call.Args) >= 2 && match(pass.TypesInfo, call.Args[len(call.Args)-2], w.format)
   292  	if !matched {
   293  		return
   294  	}
   295  
   296  	if !call.Ellipsis.IsValid() {
   297  		typ, ok := 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(pass, caller.w, caller.call, kind, res)
   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.
   345  var 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).
   408  func formatString(pass *analysis.Pass, call *ast.CallExpr) (format string, idx int) {
   409  	typ := pass.TypesInfo.Types[call.Fun].Type
   410  	if typ != nil {
   411  		if sig, ok := typ.(*types.Signature); ok {
   412  			if !sig.Variadic() {
   413  				// Skip checking non-variadic functions.
   414  				return "", -1
   415  			}
   416  			idx := sig.Params().Len() - 2
   417  			if idx < 0 {
   418  				// Skip checking variadic functions without
   419  				// fixed arguments.
   420  				return "", -1
   421  			}
   422  			s, ok := stringConstantArg(pass, call, idx)
   423  			if !ok {
   424  				// The last argument before variadic args isn't a string.
   425  				return "", -1
   426  			}
   427  			return s, idx
   428  		}
   429  	}
   430  
   431  	// Cannot determine call's signature. Fall back to scanning for the first
   432  	// string constant in the call.
   433  	for idx := range call.Args {
   434  		if s, ok := stringConstantArg(pass, call, idx); ok {
   435  			return s, idx
   436  		}
   437  		if pass.TypesInfo.Types[call.Args[idx]].Type == types.Typ[types.String] {
   438  			// Skip checking a call with a non-constant format
   439  			// string argument, since its contents are unavailable
   440  			// for validation.
   441  			return "", -1
   442  		}
   443  	}
   444  	return "", -1
   445  }
   446  
   447  // stringConstantArg returns call's string constant argument at the index idx.
   448  //
   449  // ("", false) is returned if call's argument at the index idx isn't a string
   450  // constant.
   451  func stringConstantArg(pass *analysis.Pass, call *ast.CallExpr, idx int) (string, bool) {
   452  	if idx >= len(call.Args) {
   453  		return "", false
   454  	}
   455  	return stringConstantExpr(pass, call.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.
   462  func stringConstantExpr(pass *analysis.Pass, expr ast.Expr) (string, bool) {
   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.
   471  func 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  		fn, kind := printfNameAndKind(pass, call)
   479  		switch kind {
   480  		case KindPrintf, KindErrorf:
   481  			checkPrintf(pass, kind, call, fn)
   482  		case KindPrint:
   483  			checkPrint(pass, call, fn)
   484  		}
   485  	})
   486  }
   487  
   488  func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind Kind) {
   489  	fn, _ = typeutil.Callee(pass.TypesInfo, call).(*types.Func)
   490  	if fn == nil {
   491  		return nil, 0
   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 fn, kind
   508  	}
   509  
   510  	var fact isWrapper
   511  	if pass.ImportObjectFact(fn, &fact) {
   512  		return fn, fact.Kind
   513  	}
   514  
   515  	return fn, KindNone
   516  }
   517  
   518  // isFormatter reports whether t could satisfy fmt.Formatter.
   519  // The only interface method to look for is "Format(State, rune)".
   520  func isFormatter(typ types.Type) bool {
   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(typ, false, nil, "Format")
   531  	fn, ok := 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  
   542  func isNamed(T types.Type, pkgpath, name string) bool {
   543  	named, ok := 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.
   549  type 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.
   566  func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.Func) {
   567  	format, idx := formatString(pass, call)
   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 i, w := 0, 0; i < len(format); i += w {
   587  		w = 1
   588  		if format[i] != '%' {
   589  			continue
   590  		}
   591  		state := parsePrintfVerb(pass, call, fn.FullName(), format[i:], firstArg, argNum)
   592  		if state == nil {
   593  			return
   594  		}
   595  		w = len(state.format)
   596  		if !okPrintfArg(pass, call, state) { // 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 KindNone, KindPrint, KindPrintf:
   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.
   636  func (s *formatState) parseFlags() {
   637  	for s.nbytes < len(s.format) {
   638  		switch c := s.format[s.nbytes]; c {
   639  		case '#', '0', '+', '-', ' ':
   640  			s.flags = append(s.flags, c)
   641  			s.nbytes++
   642  		default:
   643  			return
   644  		}
   645  	}
   646  }
   647  
   648  // scanNum advances through a decimal number if present.
   649  func (s *formatState) scanNum() {
   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.
   659  func (s *formatState) parseIndex() 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.name, s.format)
   673  			return false
   674  		}
   675  		s.nbytes = s.nbytes + start
   676  	}
   677  	arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
   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.name, s.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.
   692  func (s *formatState) parseNum() 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.argNums, s.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.
   707  func (s *formatState) parsePrecision() 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.
   725  func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
   726  	state := &formatState{
   727  		format:   format,
   728  		name:     name,
   729  		flags:    make([]byte, 0, 5),
   730  		argNum:   argNum,
   731  		argNums:  make([]int, 0, 1),
   732  		nbytes:   1, // There's guaranteed to be a percent sign.
   733  		firstArg: firstArg,
   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", name, state.format)
   757  		return nil
   758  	}
   759  	verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
   760  	state.verb = verb
   761  	state.nbytes += w
   762  	if verb != '%' {
   763  		state.argNums = append(state.argNums, state.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.
   770  type printfArgType int
   771  
   772  const (
   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  
   784  type 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.
   791  const (
   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.
   799  var 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  	{'%', noFlag, 0},
   806  	{'b', sharpNumFlag, argInt | argFloat | argComplex | argPointer},
   807  	{'c', "-", argRune | argInt},
   808  	{'d', numFlag, argInt | argPointer},
   809  	{'e', sharpNumFlag, argFloat | argComplex},
   810  	{'E', sharpNumFlag, argFloat | argComplex},
   811  	{'f', sharpNumFlag, argFloat | argComplex},
   812  	{'F', sharpNumFlag, argFloat | argComplex},
   813  	{'g', sharpNumFlag, argFloat | argComplex},
   814  	{'G', sharpNumFlag, argFloat | argComplex},
   815  	{'o', sharpNumFlag, argInt | argPointer},
   816  	{'O', sharpNumFlag, argInt | 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', allFlags, anyType},
   824  	{'w', allFlags, argError},
   825  	{'x', sharpNumFlag, argRune | argInt | argString | argPointer | argFloat | argComplex},
   826  	{'X', sharpNumFlag, argRune | 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.
   832  func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *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 tv, ok := 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.name, state.format, state.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.flags, rune(flag)) {
   864  				pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag)
   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 := 0; i < nargs-trueArgs; i++ {
   877  		argNum := state.argNums[i]
   878  		if !argCanBeChecked(pass, call, i, state) {
   879  			return
   880  		}
   881  		arg := call.Args[argNum]
   882  		if reason, ok := matchArgType(pass, argInt, arg); !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.name, state.format, analysisutil.Format(pass.Fset, arg), 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(pass, call, len(state.argNums)-1, state) {
   897  		return false
   898  	}
   899  	arg := call.Args[argNum]
   900  	if isFunctionValue(pass, arg) && state.verb != 'p' && state.verb != 'T' {
   901  		pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg))
   902  		return false
   903  	}
   904  	if reason, ok := matchArgType(pass, v.typ, arg); !ok {
   905  		typeString := ""
   906  		if typ := pass.TypesInfo.Types[arg].Type; typ != 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.name, state.format, analysisutil.Format(pass.Fset, arg), typeString, details)
   914  		return false
   915  	}
   916  	if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) {
   917  		if methodName, ok := recursiveStringer(pass, arg); ok {
   918  			pass.ReportRangef(call, "%s format %s with arg %s causes recursive %s method call", state.name, state.format, analysisutil.Format(pass.Fset, arg), 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) }
   931  func recursiveStringer(pass *analysis.Pass, e ast.Expr) (string, bool) {
   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(typ, false, pass.Pkg, "String")
   941  	strMethod, strOk := strObj.(*types.Func)
   942  	errObj, _, _ := types.LookupFieldOrMethod(typ, false, pass.Pkg, "Error")
   943  	errMethod, errOk := 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.Expr, f *types.Func) bool {
   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(e, strMethod) {
   956  		method = strMethod
   957  	} else if errOk && errMethod.Pkg() == pass.Pkg && inScope(e, errMethod) {
   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 u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.AND {
   970  		e = u.X // strip off & from &r
   971  	}
   972  	if id, ok := 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.
   981  func isStringer(sig *types.Signature) bool {
   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.
   989  func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
   990  	if typ := pass.TypesInfo.Types[e].Type; typ != 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.
  1000  func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, state *formatState) bool {
  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.name, state.format, arg, count(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.
  1025  var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE)
  1026  
  1027  const (
  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.
  1035  func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *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 sig, ok := 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  		it, ok := 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 sel, ok := call.Args[0].(*ast.SelectorExpr); ok {
  1067  			if x, ok := 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.Fset, call.Args[0]))
  1070  				}
  1071  			}
  1072  		}
  1073  	}
  1074  
  1075  	arg := args[0]
  1076  	if s, ok := stringConstantExpr(pass, arg); 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 s, ok := stringConstantExpr(pass, arg); 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(pass, arg) {
  1098  			pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.FullName(), analysisutil.Format(pass.Fset, arg))
  1099  		}
  1100  		if methodName, ok := recursiveStringer(pass, arg); ok {
  1101  			pass.ReportRangef(call, "%s arg %s causes recursive call to %s method", fn.FullName(), analysisutil.Format(pass.Fset, arg), methodName)
  1102  		}
  1103  	}
  1104  }
  1105  
  1106  // count(n, what) returns "1 what" or "N whats"
  1107  // (assuming the plural of what is whats).
  1108  func count(n int, what string) string {
  1109  	if n == 1 {
  1110  		return "1 " + what
  1111  	}
  1112  	return fmt.Sprintf("%d %ss", n, what)
  1113  }
  1114  
  1115  // stringSet is a set-of-nonempty-strings-valued flag.
  1116  // Note: elements without a '.' get lower-cased.
  1117  type stringSet map[string]bool
  1118  
  1119  func (ss stringSet) String() string {
  1120  	var list []string
  1121  	for name := range ss {
  1122  		list = append(list, name)
  1123  	}
  1124  	sort.Strings(list)
  1125  	return strings.Join(list, ",")
  1126  }
  1127  
  1128  func (ss stringSet) Set(flag string) error {
  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  

View as plain text