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