From b1dcc6b1892c0a4e28b52b9f6b680076c895c74a Mon Sep 17 00:00:00 2001 From: Jonathan Amsterdam Date: Tue, 7 May 2019 06:38:00 -0400 Subject: [PATCH] errorsas: ignore empty interface target No longer report a problem if target's type is interface{}. This avoids false positives like ``` var e error var i interface{} = &e ... errors.As(..., i) ... ``` Change-Id: Ibf6e7163147248305130a5e650f92b80e34a44de Reviewed-on: https://go-review.googlesource.com/c/tools/+/175717 Run-TryBot: Jonathan Amsterdam TryBot-Result: Gobot Gobot Reviewed-by: Michael Matloob Reviewed-by: Damien Neil --- go/analysis/passes/errorsas/errorsas.go | 6 +++++- .../passes/errorsas/testdata/src/a/a.go | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/go/analysis/passes/errorsas/errorsas.go b/go/analysis/passes/errorsas/errorsas.go index 8dcbaaa2..337a61d8 100644 --- a/go/analysis/passes/errorsas/errorsas.go +++ b/go/analysis/passes/errorsas/errorsas.go @@ -56,9 +56,13 @@ func run(pass *analysis.Pass) (interface{}, error) { var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) -// pointerToInterfaceOrError reports whether the type of e is a pointer to an interface or a type implementing error. +// pointerToInterfaceOrError reports whether the type of e is a pointer to an interface or a type implementing error, +// or is the empty interface. func pointerToInterfaceOrError(pass *analysis.Pass, e ast.Expr) bool { t := pass.TypesInfo.Types[e].Type + if it, ok := t.Underlying().(*types.Interface); ok && it.NumMethods() == 0 { + return true + } pt, ok := t.Underlying().(*types.Pointer) if !ok { return false diff --git a/go/analysis/passes/errorsas/testdata/src/a/a.go b/go/analysis/passes/errorsas/testdata/src/a/a.go index f2e4060e..bebf2679 100644 --- a/go/analysis/passes/errorsas/testdata/src/a/a.go +++ b/go/analysis/passes/errorsas/testdata/src/a/a.go @@ -20,15 +20,17 @@ type iface interface { func _() { var ( - e error - m myError - i int - f iface + e error + m myError + i int + f iface + ei interface{} ) - errors.As(nil, &e) - errors.As(nil, &m) - errors.As(nil, &f) - errors.As(nil, perr()) + errors.As(nil, &e) // *error + errors.As(nil, &m) // *T where T implemements error + errors.As(nil, &f) // *interface + errors.As(nil, perr()) // *error, via a call + errors.As(nil, ei) // empty interface errors.As(nil, nil) // want `second argument to errors.As must be a pointer to an interface or a type implementing error` errors.As(nil, e) // want `second argument to errors.As must be a pointer to an interface or a type implementing error`