@@ -61,10 +61,12 @@ var Analyzer = &analysis.Analyzer{
61
61
// we let it go. But if it does have a fmt.ScanState, then the
62
62
// rest has to match.
63
63
var canonicalMethods = map [string ]struct { args , results []string }{
64
+ "As" : {[]string {"interface{}" }, []string {"bool" }}, // errors.As
64
65
// "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict
65
66
"Format" : {[]string {"=fmt.State" , "rune" }, []string {}}, // fmt.Formatter
66
67
"GobDecode" : {[]string {"[]byte" }, []string {"error" }}, // gob.GobDecoder
67
68
"GobEncode" : {[]string {}, []string {"[]byte" , "error" }}, // gob.GobEncoder
69
+ "Is" : {[]string {"error" }, []string {"bool" }}, // errors.Is
68
70
"MarshalJSON" : {[]string {}, []string {"[]byte" , "error" }}, // json.Marshaler
69
71
"MarshalXML" : {[]string {"*xml.Encoder" , "xml.StartElement" }, []string {"error" }}, // xml.Marshaler
70
72
"ReadByte" : {[]string {}, []string {"byte" , "error" }}, // io.ByteReader
@@ -76,6 +78,7 @@ var canonicalMethods = map[string]struct{ args, results []string }{
76
78
"UnmarshalXML" : {[]string {"*xml.Decoder" , "xml.StartElement" }, []string {"error" }}, // xml.Unmarshaler
77
79
"UnreadByte" : {[]string {}, []string {"error" }},
78
80
"UnreadRune" : {[]string {}, []string {"error" }},
81
+ "Unwrap" : {[]string {}, []string {"error" }}, // errors.Unwrap
79
82
"WriteByte" : {[]string {"byte" }, []string {"error" }}, // jpeg.writer (matching bufio.Writer)
80
83
"WriteTo" : {[]string {"=io.Writer" }, []string {"int64" , "error" }}, // io.WriterTo
81
84
}
@@ -123,6 +126,14 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident) {
123
126
return
124
127
}
125
128
129
+ // Special case: Is, As and Unwrap only apply when type
130
+ // implements error.
131
+ if id .Name == "Is" || id .Name == "As" || id .Name == "Unwrap" {
132
+ if recv := sign .Recv (); recv == nil || ! implementsError (recv .Type ()) {
133
+ return
134
+ }
135
+ }
136
+
126
137
// Do the =s (if any) all match?
127
138
if ! matchParams (pass , expect .args , args , "=" ) || ! matchParams (pass , expect .results , results , "=" ) {
128
139
return
@@ -185,3 +196,9 @@ func matchParamType(expect string, actual types.Type) bool {
185
196
// Overkill but easy.
186
197
return typeString (actual ) == expect
187
198
}
199
+
200
+ var errorType = types .Universe .Lookup ("error" ).Type ().Underlying ().(* types.Interface )
201
+
202
+ func implementsError (actual types.Type ) bool {
203
+ return types .Implements (actual , errorType )
204
+ }
0 commit comments