go/analysis/passes/printf: warn against using non-error interface values with %w

CL 217180 permits passing interface values to any format verb, since
we have no way of knowing if the underlying type implements
fmt.Formatter. Restore the previous behavior of reporting an error
for passing a non-error value to %w.  The %w verb requires an error
argument, and the risk of false positives is small.

Fixes golang/go#48931

Change-Id: I83a6c9ed252976476f12372a490779336a1f536f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/355730
Trust: Damien Neil <dneil@google.com>
Run-TryBot: Damien Neil <dneil@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/go/analysis/passes/printf/printf.go b/go/analysis/passes/printf/printf.go
index de0369a..4169d30 100644
--- a/go/analysis/passes/printf/printf.go
+++ b/go/analysis/passes/printf/printf.go
@@ -834,8 +834,9 @@
 	}
 
 	// Could current arg implement fmt.Formatter?
+	// Skip check for the %w verb, which requires an error.
 	formatter := false
-	if state.argNum < len(call.Args) {
+	if v.typ != argError && state.argNum < len(call.Args) {
 		if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok {
 			formatter = isFormatter(tv.Type)
 		}
diff --git a/go/analysis/passes/printf/testdata/src/a/a.go b/go/analysis/passes/printf/testdata/src/a/a.go
index 89ef9ba..568a19e 100644
--- a/go/analysis/passes/printf/testdata/src/a/a.go
+++ b/go/analysis/passes/printf/testdata/src/a/a.go
@@ -51,6 +51,10 @@
 func (errorTest5) error() { // niladic; don't complain if no args (was bug)
 }
 
+type errorTestOK int
+
+func (errorTestOK) Error() string { return "" }
+
 // This function never executes, but it serves as a simple test for the program.
 // Test with make test.
 func PrintfTests() {
@@ -327,12 +331,19 @@
 	dbg("", 1) // no error "call has arguments but no formatting directive"
 
 	// %w
+	var errSubset interface {
+		Error() string
+		A()
+	}
 	_ = fmt.Errorf("%w", err)               // OK
 	_ = fmt.Errorf("%#w", err)              // OK
 	_ = fmt.Errorf("%[2]w %[1]s", "x", err) // OK
 	_ = fmt.Errorf("%[2]w %[1]s", e, "x")   // want `fmt.Errorf format %\[2\]w has arg "x" of wrong type string`
 	_ = fmt.Errorf("%w", "x")               // want `fmt.Errorf format %w has arg "x" of wrong type string`
 	_ = fmt.Errorf("%w %w", err, err)       // want `fmt.Errorf call has more than one error-wrapping directive %w`
+	_ = fmt.Errorf("%w", interface{}(nil))  // want `fmt.Errorf format %w has arg interface{}\(nil\) of wrong type interface{}`
+	_ = fmt.Errorf("%w", errorTestOK(0))    // concrete value implements error
+	_ = fmt.Errorf("%w", errSubset)         // interface value implements error
 	fmt.Printf("%w", err)                   // want `fmt.Printf does not support error-wrapping directive %w`
 	var wt *testing.T
 	wt.Errorf("%w", err)          // want `\(\*testing.common\).Errorf does not support error-wrapping directive %w`