1 package s1023
2 3 import (
4 "go/ast"
5 "go/token"
6 7 "honnef.co/go/tools/analysis/code"
8 "honnef.co/go/tools/analysis/facts/generated"
9 "honnef.co/go/tools/analysis/lint"
10 "honnef.co/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.RawDocumentation{
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 }
80