Ignore TipKit's #Rule macro in empty_count rule (#5918)

Co-authored-by: Danny Mösch <danny.moesch@icloud.com>
This commit is contained in:
Koichiro Ueki
2025-01-07 23:22:10 +09:00
committed by GitHub
parent fb4b8e0ef2
commit fc70594ad2
3 changed files with 52 additions and 0 deletions
+4
View File
@@ -58,6 +58,10 @@
#### Bug Fixes
* Ignore TipKit's `#Rule` macro in `empty_count` rule.
[Ueeek](https://github.com/Ueeek)
[#5883](https://github.com/realm/SwiftLint/issues/5883)
* Ignore super calls with trailing closures in `unneeded_override` rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#5886](ttps://github.com/realm/SwiftLint/issues/5886)
@@ -20,6 +20,8 @@ struct EmptyCountRule: Rule {
Example("[Int]().count == 0o07"),
Example("discount == 0"),
Example("order.discount == 0"),
Example("let rule = #Rule(Tips.Event(id: \"someTips\")) { $0.donations.count == 0 }"),
Example("#Rule(param1: \"param1\")", excludeFromDocumentation: true),
],
triggeringExamples: [
Example("[Int]().↓count == 0"),
@@ -32,6 +34,23 @@ struct EmptyCountRule: Rule {
Example("[Int]().↓count == 0b00"),
Example("[Int]().↓count == 0o00"),
Example("↓count == 0"),
Example("#ExampleMacro { $0.list.↓count == 0 }"),
Example("#Rule { $0.donations.↓count == 0 }", excludeFromDocumentation: true),
Example(
"#Rule(param1: \"param1\", param2: \"param2\") { $0.donations.↓count == 0 }",
excludeFromDocumentation: true
),
Example(
"#Rule(param1: \"param1\") { $0.donations.↓count == 0 } closure2: { doSomething() }",
excludeFromDocumentation: true
),
Example("#Rule(param1: \"param1\") { return $0.donations.↓count == 0 }", excludeFromDocumentation: true),
Example("""
#Rule(param1: "param1") {
doSomething()
return $0.donations.↓count == 0
}
""", excludeFromDocumentation: true),
],
corrections: [
Example("[].↓count == 0"):
@@ -62,6 +81,10 @@ struct EmptyCountRule: Rule {
Example("isEmpty && [Int]().isEmpty"),
Example("[Int]().count != 3 && [Int]().↓count != 0 || ↓count == 0 && [Int]().count > 2"):
Example("[Int]().count != 3 && ![Int]().isEmpty || isEmpty && [Int]().count > 2"),
Example("#ExampleMacro { $0.list.↓count == 0 }"):
Example("#ExampleMacro { $0.list.isEmpty }"),
Example("#Rule(param1: \"param1\") { return $0.donations.↓count == 0 }"):
Example("#Rule(param1: \"param1\") { return $0.donations.isEmpty }"),
]
)
}
@@ -77,6 +100,10 @@ private extension EmptyCountRule {
violations.append(position)
}
}
override func visit(_ node: MacroExpansionExprSyntax) -> SyntaxVisitorContinueKind {
node.isTipsRuleMacro ? .skipChildren : .visitChildren
}
}
final class Rewriter: ViolationsSyntaxRewriter<ConfigurationType> {
@@ -105,6 +132,14 @@ private extension EmptyCountRule {
}
return super.visit(node)
}
override func visit(_ node: MacroExpansionExprSyntax) -> ExprSyntax {
if node.isTipsRuleMacro {
ExprSyntax(node)
} else {
super.visit(node)
}
}
}
}
@@ -137,6 +172,15 @@ private extension TokenSyntax {
}
}
private extension MacroExpansionExprSyntax {
var isTipsRuleMacro: Bool {
macroName.text == "Rule" &&
additionalTrailingClosures.isEmpty &&
arguments.count == 1 &&
trailingClosure.map { $0.statements.onlyElement?.item.is(ReturnStmtSyntax.self) == false } ?? false
}
}
private extension ExprSyntaxProtocol {
var negated: ExprSyntax {
ExprSyntax(PrefixOperatorExprSyntax(operator: .prefixOperator("!"), expression: self))
@@ -15,6 +15,7 @@ final class EmptyCountRuleTests: SwiftLintTestCase {
Example("discount == 0\n"),
Example("order.discount == 0\n"),
Example("count == 0\n"),
Example("let rule = #Rule(Tips.Event(id: \"someTips\")) { $0.donations.isEmpty }"),
]
let triggeringExamples = [
Example("[Int]().↓count == 0\n"),
@@ -24,6 +25,7 @@ final class EmptyCountRuleTests: SwiftLintTestCase {
Example("[Int]().↓count == 0x00_00\n"),
Example("[Int]().↓count == 0b00\n"),
Example("[Int]().↓count == 0o00\n"),
Example("#ExampleMacro { $0.list.↓count == 0 }"),
]
let corrections = [
@@ -55,6 +57,8 @@ final class EmptyCountRuleTests: SwiftLintTestCase {
Example("count == 0 && [Int]().isEmpty"),
Example("[Int]().count != 3 && [Int]().↓count != 0 || count == 0 && [Int]().count > 2"):
Example("[Int]().count != 3 && ![Int]().isEmpty || count == 0 && [Int]().count > 2"),
Example("#ExampleMacro { $0.list.↓count == 0 }"):
Example("#ExampleMacro { $0.list.isEmpty }"),
]
let description = EmptyCountRule.description