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 }