| // Copyright 2023 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package printf defines an Analyzer that checks consistency |
| // of Printf format strings and arguments. |
| // |
| // # Analyzer printf |
| // |
| // printf: check consistency of Printf format strings and arguments |
| // |
| // The check applies to calls of the formatting functions such as |
| // [fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of |
| // those functions such as [log.Printf]. It reports a variety of |
| // mistakes such as syntax errors in the format string and mismatches |
| // (of number and type) between the verbs and their arguments. |
| // |
| // See the documentation of the fmt package for the complete set of |
| // format operators and their operand types. |
| // |
| // # Examples |
| // |
| // The %d format operator requires an integer operand. |
| // Here it is incorrectly applied to a string: |
| // |
| // fmt.Printf("%d", "hello") // fmt.Printf format %d has arg "hello" of wrong type string |
| // |
| // A call to Printf must have as many operands as there are "verbs" in |
| // the format string, not too few: |
| // |
| // fmt.Printf("%d") // fmt.Printf format reads arg 1, but call has 0 args |
| // |
| // nor too many: |
| // |
| // fmt.Printf("%d", 1, 2) // fmt.Printf call needs 1 arg, but has 2 args |
| // |
| // Explicit argument indexes must be no greater than the number of |
| // arguments: |
| // |
| // fmt.Printf("%[3]d", 1, 2) // fmt.Printf call has invalid argument index 3 |
| // |
| // The checker also uses a heuristic to report calls to Print-like |
| // functions that appear to have been intended for their Printf-like |
| // counterpart: |
| // |
| // log.Print("%d", 123) // log.Print call has possible formatting directive %d |
| // |
| // # Inferred printf wrappers |
| // |
| // Functions that delegate their arguments to fmt.Printf are |
| // considered "printf wrappers"; calls to them are subject to the same |
| // checking. In this example, logf is a printf wrapper: |
| // |
| // func logf(level int, format string, args ...any) { |
| // if enabled(level) { |
| // log.Printf(format, args...) |
| // } |
| // } |
| // |
| // logf(3, "invalid request: %v") // logf format reads arg 1, but call has 0 args |
| // |
| // To enable printf checking on a function that is not found by this |
| // analyzer's heuristics (for example, because control is obscured by |
| // dynamic method calls), insert a bogus call: |
| // |
| // func MyPrintf(format string, args ...any) { |
| // if false { |
| // _ = fmt.Sprintf(format, args...) // enable printf checking |
| // } |
| // ... |
| // } |
| // |
| // # Specifying printf wrappers by flag |
| // |
| // The -funcs flag specifies a comma-separated list of names of |
| // additional known formatting functions or methods. (This legacy flag |
| // is rarely used due to the automatic inference described above.) |
| // |
| // If the name contains a period, it must denote a specific function |
| // using one of the following forms: |
| // |
| // dir/pkg.Function |
| // dir/pkg.Type.Method |
| // (*dir/pkg.Type).Method |
| // |
| // Otherwise the name is interpreted as a case-insensitive unqualified |
| // identifier such as "errorf". Either way, if a listed name ends in f, the |
| // function is assumed to be Printf-like, taking a format string before the |
| // argument list. Otherwise it is assumed to be Print-like, taking a list |
| // of arguments with no format string. |
| package printf |