From aafaee8bce8c38f7ce09907ff7430abcb6f58132 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Mon, 3 Feb 2020 14:53:33 +1030 Subject: [PATCH] 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 --- go/analysis/passes/printf/printf.go | 8 ++++++-- go/analysis/passes/printf/testdata/src/a/a.go | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/go/analysis/passes/printf/printf.go b/go/analysis/passes/printf/printf.go index ebd7f6e34b..eb597f63b5 100644 --- a/go/analysis/passes/printf/printf.go +++ b/go/analysis/passes/printf/printf.go @@ -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 { diff --git a/go/analysis/passes/printf/testdata/src/a/a.go b/go/analysis/passes/printf/testdata/src/a/a.go index b809262ccc..6596209b28 100644 --- a/go/analysis/passes/printf/testdata/src/a/a.go +++ b/go/analysis/passes/printf/testdata/src/a/a.go @@ -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