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>
diff --git a/go/analysis/passes/printf/printf.go b/go/analysis/passes/printf/printf.go
index ebd7f6e..eb597f6 100644
--- a/go/analysis/passes/printf/printf.go
+++ b/go/analysis/passes/printf/printf.go
@@ -508,9 +508,13 @@
 	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 @@
 		}
 	}
 
-	// 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 b809262..6596209 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 @@
 	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