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

     1  package rule
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  
     7  	"github.com/songshiyun/revive/lint"
     8  )
     9  
    10  // UselessBreak lint rule.
    11  type UselessBreak struct{}
    12  
    13  // Apply applies the rule to given file.
    14  func (r *UselessBreak) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
    15  	var failures []lint.Failure
    16  
    17  	onFailure := func(failure lint.Failure) {
    18  		failures = append(failures, failure)
    19  	}
    20  
    21  	astFile := file.AST
    22  	w := &lintUselessBreak{onFailure, false}
    23  	ast.Walk(w, astFile)
    24  	return failures
    25  }
    26  
    27  // Name returns the rule name.
    28  func (r *UselessBreak) Name() string {
    29  	return "useless-break"
    30  }
    31  
    32  type lintUselessBreak struct {
    33  	onFailure  func(lint.Failure)
    34  	inLoopBody bool
    35  }
    36  
    37  func (w *lintUselessBreak) Visit(node ast.Node) ast.Visitor {
    38  	switch v := node.(type) {
    39  	case *ast.ForStmt:
    40  		w.inLoopBody = true
    41  		ast.Walk(w, v.Body)
    42  		w.inLoopBody = false
    43  		return nil
    44  	case *ast.RangeStmt:
    45  		w.inLoopBody = true
    46  		ast.Walk(w, v.Body)
    47  		w.inLoopBody = false
    48  		return nil
    49  	case *ast.CommClause:
    50  		for _, n := range v.Body {
    51  			w.inspectCaseStatement(n)
    52  		}
    53  		return nil
    54  	case *ast.CaseClause:
    55  		for _, n := range v.Body {
    56  			w.inspectCaseStatement(n)
    57  		}
    58  		return nil
    59  	}
    60  	return w
    61  }
    62  
    63  func (w *lintUselessBreak) inspectCaseStatement(n ast.Stmt) {
    64  	switch s := n.(type) {
    65  	case *ast.BranchStmt:
    66  		if s.Tok != token.BREAK {
    67  			return // not a break statement
    68  		}
    69  		if s.Label != nil {
    70  			return // labeled break statement, usually affects a nesting loop
    71  		}
    72  		msg := "useless break in case clause"
    73  		if w.inLoopBody {
    74  			msg += " (WARN: this break statement affects this switch or select statement and not the loop enclosing it)"
    75  		}
    76  		w.onFailure(lint.Failure{
    77  			Confidence: 1,
    78  			Node:       s,
    79  			Failure:    msg,
    80  		})
    81  	}
    82  }