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