github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/rule/unnecessary-stmt.go (about)

     1  package rule
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  
     7  	"github.com/songshiyun/revive/lint"
     8  )
     9  
    10  // UnnecessaryStmtRule warns on unnecessary statements.
    11  type UnnecessaryStmtRule struct{}
    12  
    13  // Apply applies the rule to given file.
    14  func (r *UnnecessaryStmtRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
    15  	var failures []lint.Failure
    16  	onFailure := func(failure lint.Failure) {
    17  		failures = append(failures, failure)
    18  	}
    19  
    20  	w := lintUnnecessaryStmtRule{onFailure}
    21  	ast.Walk(w, file.AST)
    22  	return failures
    23  }
    24  
    25  // Name returns the rule name.
    26  func (r *UnnecessaryStmtRule) Name() string {
    27  	return "unnecessary-stmt"
    28  }
    29  
    30  type lintUnnecessaryStmtRule struct {
    31  	onFailure func(lint.Failure)
    32  }
    33  
    34  func (w lintUnnecessaryStmtRule) Visit(node ast.Node) ast.Visitor {
    35  	switch n := node.(type) {
    36  	case *ast.FuncDecl:
    37  		if n.Body == nil || n.Type.Results != nil {
    38  			return w
    39  		}
    40  		stmts := n.Body.List
    41  		if len(stmts) == 0 {
    42  			return w
    43  		}
    44  
    45  		lastStmt := stmts[len(stmts)-1]
    46  		rs, ok := lastStmt.(*ast.ReturnStmt)
    47  		if !ok {
    48  			return w
    49  		}
    50  
    51  		if len(rs.Results) == 0 {
    52  			w.newFailure(lastStmt, "omit unnecessary return statement")
    53  		}
    54  
    55  	case *ast.SwitchStmt:
    56  		w.checkSwitchBody(n.Body)
    57  	case *ast.TypeSwitchStmt:
    58  		w.checkSwitchBody(n.Body)
    59  	case *ast.CaseClause:
    60  		if n.Body == nil {
    61  			return w
    62  		}
    63  		stmts := n.Body
    64  		if len(stmts) == 0 {
    65  			return w
    66  		}
    67  
    68  		lastStmt := stmts[len(stmts)-1]
    69  		rs, ok := lastStmt.(*ast.BranchStmt)
    70  		if !ok {
    71  			return w
    72  		}
    73  
    74  		if rs.Tok == token.BREAK && rs.Label == nil {
    75  			w.newFailure(lastStmt, "omit unnecessary break at the end of case clause")
    76  		}
    77  	}
    78  
    79  	return w
    80  }
    81  
    82  func (w lintUnnecessaryStmtRule) checkSwitchBody(b *ast.BlockStmt) {
    83  	cases := b.List
    84  	if len(cases) != 1 {
    85  		return
    86  	}
    87  
    88  	cc, ok := cases[0].(*ast.CaseClause)
    89  	if !ok {
    90  		return
    91  	}
    92  
    93  	if len(cc.List) > 1 { // skip cases with multiple expressions
    94  		return
    95  	}
    96  
    97  	w.newFailure(b, "switch with only one case can be replaced by an if-then")
    98  }
    99  
   100  func (w lintUnnecessaryStmtRule) newFailure(node ast.Node, msg string) {
   101  	w.onFailure(lint.Failure{
   102  		Confidence: 1,
   103  		Node:       node,
   104  		Category:   "style",
   105  		Failure:    msg,
   106  	})
   107  }