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

     1  // Copyright 2023 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  //
     8  // # Analyzer printf
     9  //
    10  // printf: check consistency of Printf format strings and arguments
    11  //
    12  // The check applies to calls of the formatting functions such as
    13  // [fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of
    14  // those functions such as [log.Printf]. It reports a variety of
    15  // mistakes such as syntax errors in the format string and mismatches
    16  // (of number and type) between the verbs and their arguments.
    17  //
    18  // See the documentation of the fmt package for the complete set of
    19  // format operators and their operand types.
    20  //
    21  // # Examples
    22  //
    23  // The %d format operator requires an integer operand.
    24  // Here it is incorrectly applied to a string:
    25  //
    26  //	fmt.Printf("%d", "hello") // fmt.Printf format %d has arg "hello" of wrong type string
    27  //
    28  // A call to Printf must have as many operands as there are "verbs" in
    29  // the format string, not too few:
    30  //
    31  //	fmt.Printf("%d") // fmt.Printf format reads arg 1, but call has 0 args
    32  //
    33  // nor too many:
    34  //
    35  //	fmt.Printf("%d", 1, 2) // fmt.Printf call needs 1 arg, but has 2 args
    36  //
    37  // Explicit argument indexes must be no greater than the number of
    38  // arguments:
    39  //
    40  //	fmt.Printf("%[3]d", 1, 2) // fmt.Printf call has invalid argument index 3
    41  //
    42  // The checker also uses a heuristic to report calls to Print-like
    43  // functions that appear to have been intended for their Printf-like
    44  // counterpart:
    45  //
    46  //	log.Print("%d", 123) // log.Print call has possible formatting directive %d
    47  //
    48  // Conversely, it also reports calls to Printf-like functions with a
    49  // non-constant format string and no other arguments:
    50  //
    51  //	fmt.Printf(message) // non-constant format string in call to fmt.Printf
    52  //
    53  // Such calls may have been intended for the function's Print-like
    54  // counterpart: if the value of message happens to contain "%",
    55  // misformatting will occur. In this case, the checker additionally
    56  // suggests a fix to turn the call into:
    57  //
    58  //	fmt.Printf("%s", message)
    59  //
    60  // # Inferred printf wrappers
    61  //
    62  // Functions that delegate their arguments to fmt.Printf are
    63  // considered "printf wrappers"; calls to them are subject to the same
    64  // checking. In this example, logf is a printf wrapper:
    65  //
    66  //	func logf(level int, format string, args ...any) {
    67  //		if enabled(level) {
    68  //			log.Printf(format, args...)
    69  //		}
    70  //	}
    71  //
    72  //	logf(3, "invalid request: %v") // logf format reads arg 1, but call has 0 args
    73  //
    74  // To enable printf checking on a function that is not found by this
    75  // analyzer's heuristics (for example, because control is obscured by
    76  // dynamic method calls), insert a bogus call:
    77  //
    78  //	func MyPrintf(format string, args ...any) {
    79  //		if false {
    80  //			_ = fmt.Sprintf(format, args...) // enable printf checking
    81  //		}
    82  //		...
    83  //	}
    84  //
    85  // A local function may also be inferred as a printf wrapper. If it
    86  // is assigned to a variable, each call made through that variable will
    87  // be checked just like a call to a function:
    88  //
    89  //	logf := func(format string, args ...any) {
    90  //		message := fmt.Sprintf(format, args...)
    91  //		log.Printf("%s: %s", prefix, message)
    92  //	}
    93  //	logf("%s", 123) // logf format %s has arg 123 of wrong type int
    94  //
    95  // Interface methods may also be analyzed as printf wrappers, if
    96  // within the interface's package there is an assignment from a
    97  // implementation type whose corresponding method is a printf wrapper.
    98  //
    99  // For example, the var declaration below causes a *myLoggerImpl value
   100  // to be assigned to a Logger variable:
   101  //
   102  //	type Logger interface {
   103  //		Logf(format string, args ...any)
   104  //	}
   105  //
   106  //	type myLoggerImpl struct{ ... }
   107  //
   108  //	var _ Logger = (*myLoggerImpl)(nil)
   109  //
   110  //	func  (*myLoggerImpl) Logf(format string, args ...any) {
   111  //		println(fmt.Sprintf(format, args...))
   112  //	}
   113  //
   114  // Since myLoggerImpl's Logf method is a printf wrapper, this
   115  // establishes that Logger.Logf is a printf wrapper too, causing
   116  // dynamic calls through the interface to be checked:
   117  //
   118  //	func f(log Logger) {
   119  //		log.Logf("%s", 123) // Logger.Logf format %s has arg 123 of wrong type int
   120  //	}
   121  //
   122  // This feature applies only to interface methods declared in files
   123  // using at least Go 1.26.
   124  //
   125  // # Specifying printf wrappers by flag
   126  //
   127  // The -funcs flag specifies a comma-separated list of names of
   128  // additional known formatting functions or methods. (This legacy flag
   129  // is rarely used due to the automatic inference described above.)
   130  //
   131  // If the name contains a period, it must denote a specific function
   132  // using one of the following forms:
   133  //
   134  //	dir/pkg.Function
   135  //	dir/pkg.Type.Method
   136  //	(*dir/pkg.Type).Method
   137  //
   138  // Otherwise the name is interpreted as a case-insensitive unqualified
   139  // identifier such as "errorf". Either way, if a listed name ends in f, the
   140  // function is assumed to be Printf-like, taking a format string before the
   141  // argument list. Otherwise it is assumed to be Print-like, taking a list
   142  // of arguments with no format string.
   143  package printf
   144  

View as plain text