golang.org/x/tools@v0.21.0/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 _ "embed" 11 "go/ast" 12 "go/token" 13 "go/types" 14 15 "golang.org/x/tools/go/analysis" 16 "golang.org/x/tools/go/analysis/passes/inspect" 17 "golang.org/x/tools/go/analysis/passes/internal/analysisutil" 18 "golang.org/x/tools/go/ast/inspector" 19 "golang.org/x/tools/internal/typeparams" 20 ) 21 22 //go:embed doc.go 23 var doc string 24 25 var Analyzer = &analysis.Analyzer{ 26 Name: "nilfunc", 27 Doc: analysisutil.MustExtractDoc(doc, "nilfunc"), 28 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc", 29 Requires: []*analysis.Analyzer{inspect.Analyzer}, 30 Run: run, 31 } 32 33 func run(pass *analysis.Pass) (interface{}, error) { 34 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 35 36 nodeFilter := []ast.Node{ 37 (*ast.BinaryExpr)(nil), 38 } 39 inspect.Preorder(nodeFilter, func(n ast.Node) { 40 e := n.(*ast.BinaryExpr) 41 42 // Only want == or != comparisons. 43 if e.Op != token.EQL && e.Op != token.NEQ { 44 return 45 } 46 47 // Only want comparisons with a nil identifier on one side. 48 var e2 ast.Expr 49 switch { 50 case pass.TypesInfo.Types[e.X].IsNil(): 51 e2 = e.Y 52 case pass.TypesInfo.Types[e.Y].IsNil(): 53 e2 = e.X 54 default: 55 return 56 } 57 58 // Only want identifiers or selector expressions. 59 var obj types.Object 60 switch v := e2.(type) { 61 case *ast.Ident: 62 obj = pass.TypesInfo.Uses[v] 63 case *ast.SelectorExpr: 64 obj = pass.TypesInfo.Uses[v.Sel] 65 case *ast.IndexExpr, *ast.IndexListExpr: 66 // Check generic functions such as "f[T1,T2]". 67 x, _, _, _ := typeparams.UnpackIndexExpr(v) 68 if id, ok := x.(*ast.Ident); ok { 69 obj = pass.TypesInfo.Uses[id] 70 } 71 default: 72 return 73 } 74 75 // Only want functions. 76 if _, ok := obj.(*types.Func); !ok { 77 return 78 } 79 80 pass.ReportRangef(e, "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ) 81 }) 82 return nil, nil 83 }