...

Source file src/golang.org/x/tools/go/analysis/passes/deepequalerrors/deepequalerrors.go

Documentation: golang.org/x/tools/go/analysis/passes/deepequalerrors

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package deepequalerrors defines an Analyzer that checks for the use
     6  // of reflect.DeepEqual with error values.
     7  package deepequalerrors
     8  
     9  import (
    10  	"go/ast"
    11  	"go/types"
    12  
    13  	"golang.org/x/tools/go/analysis"
    14  	"golang.org/x/tools/go/analysis/passes/inspect"
    15  	"golang.org/x/tools/go/ast/inspector"
    16  	"golang.org/x/tools/go/types/typeutil"
    17  )
    18  
    19  const Doc = `check for calls of reflect.DeepEqual on error values
    20  
    21  The deepequalerrors checker looks for calls of the form:
    22  
    23      reflect.DeepEqual(err1, err2)
    24  
    25  where err1 and err2 are errors. Using reflect.DeepEqual to compare
    26  errors is discouraged.`
    27  
    28  var Analyzer = &analysis.Analyzer{
    29  	Name:     "deepequalerrors",
    30  	Doc:      Doc,
    31  	Requires: []*analysis.Analyzer{inspect.Analyzer},
    32  	Run:      run,
    33  }
    34  
    35  func run(pass *analysis.Pass) (interface{}, error) {
    36  	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
    37  
    38  	nodeFilter := []ast.Node{
    39  		(*ast.CallExpr)(nil),
    40  	}
    41  	inspect.Preorder(nodeFilter, func(n ast.Node) {
    42  		call := n.(*ast.CallExpr)
    43  		fn, ok := typeutil.Callee(pass.TypesInfo, call).(*types.Func)
    44  		if !ok {
    45  			return
    46  		}
    47  		if fn.FullName() == "reflect.DeepEqual" && hasError(pass, call.Args[0]) && hasError(pass, call.Args[1]) {
    48  			pass.ReportRangef(call, "avoid using reflect.DeepEqual with errors")
    49  		}
    50  	})
    51  	return nil, nil
    52  }
    53  
    54  var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
    55  
    56  // hasError reports whether the type of e contains the type error.
    57  // See containsError, below, for the meaning of "contains".
    58  func hasError(pass *analysis.Pass, e ast.Expr) bool {
    59  	tv, ok := pass.TypesInfo.Types[e]
    60  	if !ok { // no type info, assume good
    61  		return false
    62  	}
    63  	return containsError(tv.Type)
    64  }
    65  
    66  // Report whether any type that typ could store and that could be compared is the
    67  // error type. This includes typ itself, as well as the types of struct field, slice
    68  // and array elements, map keys and elements, and pointers. It does not include
    69  // channel types (incomparable), arg and result types of a Signature (not stored), or
    70  // methods of a named or interface type (not stored).
    71  func containsError(typ types.Type) bool {
    72  	// Track types being processed, to avoid infinite recursion.
    73  	// Using types as keys here is OK because we are checking for the identical pointer, not
    74  	// type identity. See analysis/passes/printf/types.go.
    75  	inProgress := make(map[types.Type]bool)
    76  
    77  	var check func(t types.Type) bool
    78  	check = func(t types.Type) bool {
    79  		if t == errorType {
    80  			return true
    81  		}
    82  		if inProgress[t] {
    83  			return false
    84  		}
    85  		inProgress[t] = true
    86  		switch t := t.(type) {
    87  		case *types.Pointer:
    88  			return check(t.Elem())
    89  		case *types.Slice:
    90  			return check(t.Elem())
    91  		case *types.Array:
    92  			return check(t.Elem())
    93  		case *types.Map:
    94  			return check(t.Key()) || check(t.Elem())
    95  		case *types.Struct:
    96  			for i := 0; i < t.NumFields(); i++ {
    97  				if check(t.Field(i).Type()) {
    98  					return true
    99  				}
   100  			}
   101  		case *types.Named:
   102  			return check(t.Underlying())
   103  
   104  		// We list the remaining valid type kinds for completeness.
   105  		case *types.Basic:
   106  		case *types.Chan: // channels store values, but they are not comparable
   107  		case *types.Signature:
   108  		case *types.Tuple: // tuples are only part of signatures
   109  		case *types.Interface:
   110  		}
   111  		return false
   112  	}
   113  
   114  	return check(typ)
   115  }
   116  

View as plain text