...
1
2
3
4
5
6
7 package nilfunc
8
9 import (
10 "go/ast"
11 "go/token"
12 "go/types"
13
14 "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/internal/typeparams"
18 )
19
20 const Doc = `check for useless comparisons between functions and nil
21
22 A useless comparison is one like f == nil as opposed to f() == nil.`
23
24 var Analyzer = &analysis.Analyzer{
25 Name: "nilfunc",
26 Doc: Doc,
27 Requires: []*analysis.Analyzer{inspect.Analyzer},
28 Run: run,
29 }
30
31 func run(pass *analysis.Pass) (interface{}, error) {
32 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
33
34 nodeFilter := []ast.Node{
35 (*ast.BinaryExpr)(nil),
36 }
37 inspect.Preorder(nodeFilter, func(n ast.Node) {
38 e := n.(*ast.BinaryExpr)
39
40
41 if e.Op != token.EQL && e.Op != token.NEQ {
42 return
43 }
44
45
46 var e2 ast.Expr
47 switch {
48 case pass.TypesInfo.Types[e.X].IsNil():
49 e2 = e.Y
50 case pass.TypesInfo.Types[e.Y].IsNil():
51 e2 = e.X
52 default:
53 return
54 }
55
56
57 var obj types.Object
58 switch v := e2.(type) {
59 case *ast.Ident:
60 obj = pass.TypesInfo.Uses[v]
61 case *ast.SelectorExpr:
62 obj = pass.TypesInfo.Uses[v.Sel]
63 case *ast.IndexExpr, *typeparams.IndexListExpr:
64
65 x, _, _, _ := typeparams.UnpackIndexExpr(v)
66 if id, ok := x.(*ast.Ident); ok {
67 obj = pass.TypesInfo.Uses[id]
68 }
69 default:
70 return
71 }
72
73
74 if _, ok := obj.(*types.Func); !ok {
75 return
76 }
77
78 pass.ReportRangef(e, "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ)
79 })
80 return nil, nil
81 }
82
View as plain text