Skip to content

Commit 6065a15

Browse files
LaurenWhiteallevato
authored andcommitted
Implement no labels in case patterns. (swiftlang#90)
1 parent 8da26ce commit 6065a15

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

Sources/Rules/NoLabelsInCasePatterns.swift

+51-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,56 @@ import SwiftSyntax
1212
/// Format: Redundant labels in case patterns are removed.
1313
///
1414
/// - SeeAlso: https://google.github.io/swift#pattern-matching
15-
public final class NoLablesInCasePatterns: SyntaxFormatRule {
15+
public final class NoLabelsInCasePatterns: SyntaxFormatRule {
16+
public override func visit(_ node: SwitchCaseLabelSyntax) -> Syntax {
1617

18+
var newCaseItems: [CaseItemSyntax] = []
19+
for item in node.caseItems {
20+
guard let expPat = item.pattern as? ExpressionPatternSyntax else {
21+
newCaseItems.append(item)
22+
continue
23+
}
24+
guard let funcCall = expPat.expression as? FunctionCallExprSyntax else {
25+
newCaseItems.append(item)
26+
continue
27+
}
28+
29+
// Search function call argument list for violations
30+
var newArgs: [FunctionCallArgumentSyntax] = []
31+
for argument in funcCall.argumentList {
32+
guard let label = argument.label else {
33+
newArgs.append(argument)
34+
continue
35+
}
36+
guard let unresolvedPat = argument.expression as? UnresolvedPatternExprSyntax,
37+
let valueBinding = unresolvedPat.pattern as? ValueBindingPatternSyntax else {
38+
newArgs.append(argument)
39+
continue
40+
}
41+
42+
// Remove label if it's the same as the value identifier
43+
let name = valueBinding.valuePattern.description.trimmingCharacters(in: .whitespaces)
44+
guard name == label.text else {
45+
newArgs.append(argument)
46+
continue
47+
}
48+
diagnose(.removeRedundantLabel(name: name), on: label)
49+
newArgs.append(argument.withLabel(nil).withColon(nil))
50+
}
51+
52+
let newArgList = SyntaxFactory.makeFunctionCallArgumentList(newArgs)
53+
let newFuncCall = funcCall.withArgumentList(newArgList)
54+
let newExpPat = expPat.withExpression(newFuncCall)
55+
let newItem = item.withPattern(newExpPat)
56+
newCaseItems.append(newItem)
57+
}
58+
let newCaseItemList = SyntaxFactory.makeCaseItemList(newCaseItems)
59+
return node.withCaseItems(newCaseItemList)
60+
}
61+
}
62+
63+
extension Diagnostic.Message {
64+
static func removeRedundantLabel(name: String) -> Diagnostic.Message {
65+
return .init(.warning, "remove \(name) label from case argument")
66+
}
1767
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import Foundation
2+
import XCTest
3+
import SwiftSyntax
4+
5+
@testable import Rules
6+
7+
public class NoLabelsInCasePatternsTests: DiagnosingTestCase {
8+
public func testRedundantCaseLabels() {
9+
XCTAssertFormatting(
10+
NoLabelsInCasePatterns.self,
11+
input: """
12+
switch treeNode {
13+
case .root(let data):
14+
break
15+
case .subtree(left: let left, right: let right):
16+
break
17+
case .leaf(element: let element):
18+
break
19+
}
20+
""",
21+
expected: """
22+
switch treeNode {
23+
case .root(let data):
24+
break
25+
case .subtree(let left, let right):
26+
break
27+
case .leaf(let element):
28+
break
29+
}
30+
""")
31+
XCTAssertNotDiagnosed(.removeRedundantLabel(name: "data"))
32+
XCTAssertDiagnosed(.removeRedundantLabel(name: "left"))
33+
XCTAssertDiagnosed(.removeRedundantLabel(name: "right"))
34+
XCTAssertDiagnosed(.removeRedundantLabel(name: "element"))
35+
}
36+
37+
#if !os(macOS)
38+
static let allTests = [
39+
NoLabelsInCasePatternsTests.testRedundantCaseLabels,
40+
]
41+
#endif
42+
}
43+

0 commit comments

Comments
 (0)