go/analysis/passes/printf: fix %w for non-fmt.Errorf functions
Previously all functions that were named Errorf have been treated like a
fmt.Errorf-based function. But only fmt.Errorf (and functions based on
fmt.Errorf) accept the %w verb. Fix that.
Updates golang/go#47641.
Change-Id: Iec5d0ae674c7dc817e85291dcfa064303eafba7e
Reviewed-on: https://go-review.googlesource.com/c/tools/+/340409
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Trust: Damien Neil <dneil@google.com>
diff --git a/go/analysis/passes/printf/printf.go b/go/analysis/passes/printf/printf.go
index 53b3f2b..de0369a 100644
--- a/go/analysis/passes/printf/printf.go
+++ b/go/analysis/passes/printf/printf.go
@@ -490,7 +490,7 @@
_, ok = isPrint[strings.ToLower(fn.Name())]
}
if ok {
- if fn.Name() == "Errorf" {
+ if fn.FullName() == "fmt.Errorf" {
kind = KindErrorf
} else if strings.HasSuffix(fn.Name(), "f") {
kind = KindPrintf
diff --git a/go/analysis/passes/printf/testdata/src/a/a.go b/go/analysis/passes/printf/testdata/src/a/a.go
index 378bdff..89ef9ba 100644
--- a/go/analysis/passes/printf/testdata/src/a/a.go
+++ b/go/analysis/passes/printf/testdata/src/a/a.go
@@ -327,14 +327,26 @@
dbg("", 1) // no error "call has arguments but no formatting directive"
// %w
- _ = fmt.Errorf("%w", err)
- _ = fmt.Errorf("%#w", err)
- _ = fmt.Errorf("%[2]w %[1]s", "x", err)
- _ = 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.Printf("%w", err) // want `fmt.Printf does not support error-wrapping directive %w`
- Errorf(0, "%w", err)
+ _ = 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.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`
+ wt.Errorf("%[1][3]d x", 1, 2) // want `\(\*testing.common\).Errorf format %\[1\]\[ has unknown verb \[`
+ wt.Errorf("%[1]d x", 1, 2) // OK
+ // Errorf is a printfWrapper, not an errorfWrapper.
+ Errorf(0, "%w", err) // want `a.Errorf does not support error-wrapping directive %w`
+ // %w should work on fmt.Errorf-based wrappers.
+ var es errorfStruct
+ var eis errorfIntStruct
+ var ess errorfStringStruct
+ es.Errorf("%w", err) // OK
+ eis.Errorf(0, "%w", err) // OK
+ ess.Errorf("ERROR", "%w", err) // OK
}
func someString() string { return "X" }
@@ -379,13 +391,36 @@
// Errorf is used by the test for a case in which the first parameter
// is not a format string.
-func Errorf(i int, format string, args ...interface{}) { // want Errorf:"errorfWrapper"
- _ = fmt.Errorf(format, args...)
+func Errorf(i int, format string, args ...interface{}) { // want Errorf:"printfWrapper"
+ fmt.Sprintf(format, args...)
}
// errorf is used by the test for a case in which the function accepts multiple
// string parameters before variadic arguments
-func errorf(level, format string, args ...interface{}) { // want errorf:"errorfWrapper"
+func errorf(level, format string, args ...interface{}) { // want errorf:"printfWrapper"
+ fmt.Sprintf(format, args...)
+}
+
+type errorfStruct struct{}
+
+// Errorf is used to test %w works on errorf wrappers.
+func (errorfStruct) Errorf(format string, args ...interface{}) { // want Errorf:"errorfWrapper"
+ _ = fmt.Errorf(format, args...)
+}
+
+type errorfStringStruct struct{}
+
+// Errorf is used by the test for a case in which the function accepts multiple
+// string parameters before variadic arguments
+func (errorfStringStruct) Errorf(level, format string, args ...interface{}) { // want Errorf:"errorfWrapper"
+ _ = fmt.Errorf(format, args...)
+}
+
+type errorfIntStruct struct{}
+
+// Errorf is used by the test for a case in which the first parameter
+// is not a format string.
+func (errorfIntStruct) Errorf(i int, format string, args ...interface{}) { // want Errorf:"errorfWrapper"
_ = fmt.Errorf(format, args...)
}