github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/analysis/passes/nilfunc/nilfunc.go (about) 1 // Copyright 2013 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 nilfunc defines an Analyzer that checks for useless 6 // comparisons against nil. 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 // Only want == or != comparisons. 41 if e.Op != token.EQL && e.Op != token.NEQ { 42 return 43 } 44 45 // Only want comparisons with a nil identifier on one side. 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 // Only want identifiers or selector expressions. 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 // Check generic functions such as "f[T1,T2]". 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 // Only want functions. 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 }