@@ -12,22 +12,20 @@ import (
1212 "go/types"
1313
1414 "golang.org/x/tools/go/analysis"
15- "golang.org/x/tools/go/analysis/passes/inspect"
16- "golang.org/x/tools/go/ast/inspector"
17- "golang.org/x/tools/go/types/typeutil"
18- "golang.org/x/tools/internal/analysisinternal"
15+ typeindexanalyzer "golang.org/x/tools/internal/analysisinternal/typeindex"
16+ "golang.org/x/tools/internal/typesinternal/typeindex"
1917)
2018
2119const Doc = `report passing non-pointer or non-error values to errors.As
2220
23- The errorsas analysis reports calls to errors.As where the type
21+ The errorsas analyzer reports calls to errors.As where the type
2422of the second argument is not a pointer to a type implementing error.`
2523
2624var Analyzer = & analysis.Analyzer {
2725 Name : "errorsas" ,
2826 Doc : Doc ,
2927 URL : "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/errorsas" ,
30- Requires : []* analysis.Analyzer {inspect .Analyzer },
28+ Requires : []* analysis.Analyzer {typeindexanalyzer .Analyzer },
3129 Run : run ,
3230}
3331
@@ -39,51 +37,48 @@ func run(pass *analysis.Pass) (any, error) {
3937 return nil , nil
4038 }
4139
42- if ! analysisinternal .Imports (pass .Pkg , "errors" ) {
43- return nil , nil // doesn't directly import errors
44- }
45-
46- inspect := pass .ResultOf [inspect .Analyzer ].(* inspector.Inspector )
40+ var (
41+ index = pass .ResultOf [typeindexanalyzer .Analyzer ].(* typeindex.Index )
42+ info = pass .TypesInfo
43+ )
4744
48- nodeFilter := []ast.Node {
49- (* ast .CallExpr )(nil ),
50- }
51- inspect .Preorder (nodeFilter , func (n ast.Node ) {
52- call := n .(* ast.CallExpr )
53- obj := typeutil .Callee (pass .TypesInfo , call )
54- if ! analysisinternal .IsFunctionNamed (obj , "errors" , "As" ) {
55- return
56- }
45+ for curCall := range index .Calls (index .Object ("errors" , "As" )) {
46+ call := curCall .Node ().(* ast.CallExpr )
5747 if len (call .Args ) < 2 {
58- return // not enough arguments, e.g. called with return values of another function
48+ continue // spread call: errors.As(pair())
5949 }
60- if err := checkAsTarget (pass , call .Args [1 ]); err != nil {
50+
51+ // Check for incorrect arguments.
52+ if err := checkAsTarget (info , call .Args [1 ]); err != nil {
6153 pass .ReportRangef (call , "%v" , err )
54+ continue
6255 }
63- })
56+ }
6457 return nil , nil
6558}
6659
67- var errorType = types .Universe .Lookup ("error" ).Type ()
68-
6960// checkAsTarget reports an error if the second argument to errors.As is invalid.
70- func checkAsTarget (pass * analysis. Pass , e ast.Expr ) error {
71- t := pass . TypesInfo .Types [e ].Type
72- if it , ok := t .Underlying ().( * types. Interface ); ok && it . NumMethods () == 0 {
73- // A target of interface{} is always allowed, since it often indicates
61+ func checkAsTarget (info * types. Info , e ast.Expr ) error {
62+ t := info .Types [e ].Type
63+ if types . Identical ( t .Underlying (), anyType ) {
64+ // A target of any is always allowed, since it often indicates
7465 // a value forwarded from another source.
7566 return nil
7667 }
7768 pt , ok := t .Underlying ().(* types.Pointer )
7869 if ! ok {
7970 return errors .New ("second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type" )
8071 }
81- if pt .Elem () == errorType {
72+ if types . Identical ( pt .Elem (), errorType ) {
8273 return errors .New ("second argument to errors.As should not be *error" )
8374 }
84- _ , ok = pt .Elem ().Underlying ().(* types.Interface )
85- if ok || types .Implements (pt .Elem (), errorType .Underlying ().(* types.Interface )) {
86- return nil
75+ if ! types .IsInterface (pt .Elem ()) && ! types .AssignableTo (pt .Elem (), errorType ) {
76+ return errors .New ("second argument to errors.As must be a non-nil pointer to either a type that implements error, or to any interface type" )
8777 }
88- return errors . New ( "second argument to errors.As must be a non- nil pointer to either a type that implements error, or to any interface type" )
78+ return nil
8979}
80+
81+ var (
82+ anyType = types .Universe .Lookup ("any" ).Type ()
83+ errorType = types .Universe .Lookup ("error" ).Type ()
84+ )
0 commit comments