honnef.co/go/tools@v0.5.0-0.dev.0.20240520180541-dcae280a5e87/simple/s1020/s1020.go (about) 1 package s1020 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/types" 7 8 "honnef.co/go/tools/analysis/code" 9 "honnef.co/go/tools/analysis/facts/generated" 10 "honnef.co/go/tools/analysis/lint" 11 "honnef.co/go/tools/analysis/report" 12 "honnef.co/go/tools/pattern" 13 14 "golang.org/x/tools/go/analysis" 15 "golang.org/x/tools/go/analysis/passes/inspect" 16 ) 17 18 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 19 Analyzer: &analysis.Analyzer{ 20 Name: "S1020", 21 Run: run, 22 Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer}, 23 }, 24 Doc: &lint.Documentation{ 25 Title: `Omit redundant nil check in type assertion`, 26 Before: `if _, ok := i.(T); ok && i != nil {}`, 27 After: `if _, ok := i.(T); ok {}`, 28 Since: "2017.1", 29 MergeIf: lint.MergeIfAny, 30 }, 31 }) 32 33 var Analyzer = SCAnalyzer.Analyzer 34 35 var ( 36 checkAssertNotNilFn1Q = pattern.MustParse(` 37 (IfStmt 38 (AssignStmt [(Ident "_") ok@(Object _)] _ [(TypeAssertExpr assert@(Object _) _)]) 39 (Or 40 (BinaryExpr ok "&&" (BinaryExpr assert "!=" (Builtin "nil"))) 41 (BinaryExpr (BinaryExpr assert "!=" (Builtin "nil")) "&&" ok)) 42 _ 43 _)`) 44 checkAssertNotNilFn2Q = pattern.MustParse(` 45 (IfStmt 46 nil 47 (BinaryExpr lhs@(Object _) "!=" (Builtin "nil")) 48 [ 49 ifstmt@(IfStmt 50 (AssignStmt [(Ident "_") ok@(Object _)] _ [(TypeAssertExpr lhs _)]) 51 ok 52 _ 53 nil) 54 ] 55 nil)`) 56 ) 57 58 func run(pass *analysis.Pass) (interface{}, error) { 59 fn1 := func(node ast.Node) { 60 m, ok := code.Match(pass, checkAssertNotNilFn1Q, node) 61 if !ok { 62 return 63 } 64 assert := m.State["assert"].(types.Object) 65 assign := m.State["ok"].(types.Object) 66 report.Report(pass, node, fmt.Sprintf("when %s is true, %s can't be nil", assign.Name(), assert.Name()), 67 report.ShortRange(), 68 report.FilterGenerated()) 69 } 70 fn2 := func(node ast.Node) { 71 m, ok := code.Match(pass, checkAssertNotNilFn2Q, node) 72 if !ok { 73 return 74 } 75 ifstmt := m.State["ifstmt"].(*ast.IfStmt) 76 lhs := m.State["lhs"].(types.Object) 77 assignIdent := m.State["ok"].(types.Object) 78 report.Report(pass, ifstmt, fmt.Sprintf("when %s is true, %s can't be nil", assignIdent.Name(), lhs.Name()), 79 report.ShortRange(), 80 report.FilterGenerated()) 81 } 82 // OPT(dh): merge fn1 and fn2 83 code.Preorder(pass, fn1, (*ast.IfStmt)(nil)) 84 code.Preorder(pass, fn2, (*ast.IfStmt)(nil)) 85 return nil, nil 86 }