go/analysis/passes/printf: give leeway for fmt.Formatter satisfaction

We have no way of knowing the concrete type of an interface value;
it might be a fmt.Formatter. To avoid false positives, assume that
all interface values are fmt.Formatters.

Updates golang/go#36564

Change-Id: Iaf18ba2794e4d3095d0018502c1c6c459a360b42
Reviewed-on: https://go-review.googlesource.com/c/tools/+/217180
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Dan Kortschak 2020-02-03 14:53:33 +10:30 committed by Rob Pike
parent 43e3193a9b
commit aafaee8bce
2 changed files with 9 additions and 4 deletions

View File

@ -508,9 +508,13 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func,
return fn, KindNone
}
// isFormatter reports whether t satisfies fmt.Formatter.
// isFormatter reports whether t could satisfy fmt.Formatter.
// The only interface method to look for is "Format(State, rune)".
func isFormatter(typ types.Type) bool {
// If the type is an interface, the value it holds might satisfy fmt.Formatter.
if _, ok := typ.Underlying().(*types.Interface); ok {
return true
}
obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format")
fn, ok := obj.(*types.Func)
if !ok {
@ -827,7 +831,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
}
}
// Does current arg implement fmt.Formatter?
// Could current arg implement fmt.Formatter?
formatter := false
if state.argNum < len(call.Args) {
if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok {

View File

@ -101,8 +101,9 @@ func PrintfTests() {
fmt.Printf("%v", notstringerarrayv)
fmt.Printf("%T", notstringerarrayv)
fmt.Printf("%d", new(fmt.Formatter))
fmt.Printf("%*%", 2) // Ridiculous but allowed.
fmt.Printf("%s", interface{}(nil)) // Nothing useful we can say.
fmt.Printf("%*%", 2) // Ridiculous but allowed.
fmt.Printf("%s", interface{}(nil)) // Nothing useful we can say.
fmt.Printf("%a", interface{}(new(BoolFormatter))) // Could be a fmt.Formatter.
fmt.Printf("%g", 1+2i)
fmt.Printf("%#e %#E %#f %#F %#g %#G", 1.2, 1.2, 1.2, 1.2, 1.2, 1.2) // OK since Go 1.9