mirror of
https://github.com/realm/SwiftLint.git
synced 2026-05-07 20:12:49 +00:00
47335d7f95
Report number of corrections per file instead.
135 lines
4.2 KiB
Swift
135 lines
4.2 KiB
Swift
import SwiftSyntax
|
|
|
|
@SwiftSyntaxRule(explicitRewriter: true)
|
|
struct UnusedControlFlowLabelRule: Rule {
|
|
var configuration = SeverityConfiguration<Self>(.warning)
|
|
|
|
static let description = RuleDescription(
|
|
identifier: "unused_control_flow_label",
|
|
name: "Unused Control Flow Label",
|
|
description: "Unused control flow label should be removed",
|
|
kind: .lint,
|
|
nonTriggeringExamples: [
|
|
Example("loop: while true { break loop }"),
|
|
Example("loop: while true { continue loop }"),
|
|
Example("loop:\n while true { break loop }"),
|
|
Example("while true { break }"),
|
|
Example("loop: for x in array { break loop }"),
|
|
Example("""
|
|
label: switch number {
|
|
case 1: print("1")
|
|
case 2: print("2")
|
|
default: break label
|
|
}
|
|
"""),
|
|
Example("""
|
|
loop: repeat {
|
|
if x == 10 {
|
|
break loop
|
|
}
|
|
} while true
|
|
"""),
|
|
],
|
|
triggeringExamples: [
|
|
Example("↓loop: while true { break }"),
|
|
Example("↓loop: while true { break loop1 }"),
|
|
Example("↓loop: while true { break outerLoop }"),
|
|
Example("↓loop: for x in array { break }"),
|
|
Example("""
|
|
↓label: switch number {
|
|
case 1: print("1")
|
|
case 2: print("2")
|
|
default: break
|
|
}
|
|
"""),
|
|
Example("""
|
|
↓loop: repeat {
|
|
if x == 10 {
|
|
break
|
|
}
|
|
} while true
|
|
"""),
|
|
],
|
|
corrections: [
|
|
Example("↓loop: while true { break }"): Example("while true { break }"),
|
|
Example("↓loop: while true { break loop1 }"): Example("while true { break loop1 }"),
|
|
Example("↓loop: while true { break outerLoop }"): Example("while true { break outerLoop }"),
|
|
Example("↓loop: for x in array { break }"): Example("for x in array { break }"),
|
|
Example("""
|
|
↓label: switch number {
|
|
case 1: print("1")
|
|
case 2: print("2")
|
|
default: break
|
|
}
|
|
"""): Example("""
|
|
switch number {
|
|
case 1: print("1")
|
|
case 2: print("2")
|
|
default: break
|
|
}
|
|
"""),
|
|
Example("""
|
|
↓loop: repeat {
|
|
if x == 10 {
|
|
break
|
|
}
|
|
} while true
|
|
"""): Example("""
|
|
repeat {
|
|
if x == 10 {
|
|
break
|
|
}
|
|
} while true
|
|
"""),
|
|
]
|
|
)
|
|
}
|
|
|
|
private extension UnusedControlFlowLabelRule {
|
|
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
|
|
override func visitPost(_ node: LabeledStmtSyntax) {
|
|
if let position = node.violationPosition {
|
|
violations.append(position)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class Rewriter: ViolationsSyntaxRewriter<ConfigurationType> {
|
|
override func visit(_ node: LabeledStmtSyntax) -> StmtSyntax {
|
|
guard node.violationPosition != nil else {
|
|
return super.visit(node)
|
|
}
|
|
numberOfCorrections += 1
|
|
return visit(node.statement.with(\.leadingTrivia, node.leadingTrivia))
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension LabeledStmtSyntax {
|
|
var violationPosition: AbsolutePosition? {
|
|
let visitor = BreakAndContinueLabelCollector(viewMode: .sourceAccurate)
|
|
let labels = visitor.walk(tree: self, handler: \.labels)
|
|
guard !labels.contains(label.text) else {
|
|
return nil
|
|
}
|
|
|
|
return label.positionAfterSkippingLeadingTrivia
|
|
}
|
|
}
|
|
|
|
private class BreakAndContinueLabelCollector: SyntaxVisitor {
|
|
private(set) var labels: Set<String> = []
|
|
|
|
override func visitPost(_ node: BreakStmtSyntax) {
|
|
if let label = node.label?.text {
|
|
labels.insert(label)
|
|
}
|
|
}
|
|
|
|
override func visitPost(_ node: ContinueStmtSyntax) {
|
|
if let label = node.label?.text {
|
|
labels.insert(label)
|
|
}
|
|
}
|
|
}
|