src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

s1023.go (2205B)


      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) (any, 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 }