Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / analysis / passes / deepequalerrors / deepequalerrors.go
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 }