github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/simple/s1023/s1023.go (about) 1 package s1023 2 3 import ( 4 "go/ast" 5 "go/token" 6 7 "github.com/amarpal/go-tools/analysis/code" 8 "github.com/amarpal/go-tools/analysis/facts/generated" 9 "github.com/amarpal/go-tools/analysis/lint" 10 "github.com/amarpal/go-tools/analysis/report" 11 12 "golang.org/x/tools/go/analysis" 13 "golang.org/x/tools/go/analysis/passes/inspect" 14 ) 15 16 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 17 Analyzer: &analysis.Analyzer{ 18 Name: "S1023", 19 Run: run, 20 Requires: []*analysis.Analyzer{inspect.Analyzer, generated.Analyzer}, 21 }, 22 Doc: &lint.Documentation{ 23 Title: `Omit redundant control flow`, 24 Text: `Functions that have no return value do not need a return statement as 25 the final statement of the function. 26 27 Switches in Go do not have automatic fallthrough, unlike languages 28 like C. It is not necessary to have a break statement as the final 29 statement in a case block.`, 30 Since: "2017.1", 31 MergeIf: lint.MergeIfAny, 32 }, 33 }) 34 35 var Analyzer = SCAnalyzer.Analyzer 36 37 func run(pass *analysis.Pass) (interface{}, error) { 38 fn1 := func(node ast.Node) { 39 clause := node.(*ast.CaseClause) 40 if len(clause.Body) < 2 { 41 return 42 } 43 branch, ok := clause.Body[len(clause.Body)-1].(*ast.BranchStmt) 44 if !ok || branch.Tok != token.BREAK || branch.Label != nil { 45 return 46 } 47 report.Report(pass, branch, "redundant break statement", report.FilterGenerated()) 48 } 49 fn2 := func(node ast.Node) { 50 var ret *ast.FieldList 51 var body *ast.BlockStmt 52 switch x := node.(type) { 53 case *ast.FuncDecl: 54 ret = x.Type.Results 55 body = x.Body 56 case *ast.FuncLit: 57 ret = x.Type.Results 58 body = x.Body 59 default: 60 lint.ExhaustiveTypeSwitch(node) 61 } 62 // if the func has results, a return can't be redundant. 63 // similarly, if there are no statements, there can be 64 // no return. 65 if ret != nil || body == nil || len(body.List) < 1 { 66 return 67 } 68 rst, ok := body.List[len(body.List)-1].(*ast.ReturnStmt) 69 if !ok { 70 return 71 } 72 // we don't need to check rst.Results as we already 73 // checked x.Type.Results to be nil. 74 report.Report(pass, rst, "redundant return statement", report.FilterGenerated()) 75 } 76 code.Preorder(pass, fn1, (*ast.CaseClause)(nil)) 77 code.Preorder(pass, fn2, (*ast.FuncDecl)(nil), (*ast.FuncLit)(nil)) 78 return nil, nil 79 }