mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
With the binding of configurations to their associated rule types "unknown configuration" errors can be made more specific mentioning also the rule's identifier in the printed message.
57 lines
2.5 KiB
Swift
57 lines
2.5 KiB
Swift
import SwiftSyntax
|
|
|
|
struct ReduceBooleanRule: SwiftSyntaxRule, ConfigurationProviderRule {
|
|
var configuration = SeverityConfiguration<Self>(.warning)
|
|
|
|
static let description = RuleDescription(
|
|
identifier: "reduce_boolean",
|
|
name: "Reduce Boolean",
|
|
description: "Prefer using `.allSatisfy()` or `.contains()` over `reduce(true)` or `reduce(false)`.",
|
|
kind: .performance,
|
|
nonTriggeringExamples: [
|
|
Example("nums.reduce(0) { $0.0 + $0.1 }"),
|
|
Example("nums.reduce(0.0) { $0.0 + $0.1 }"),
|
|
Example("nums.reduce(initial: true) { $0.0 && $0.1 == 3 }")
|
|
],
|
|
triggeringExamples: [
|
|
Example("let allNines = nums.↓reduce(true) { $0.0 && $0.1 == 9 }"),
|
|
Example("let anyNines = nums.↓reduce(false) { $0.0 || $0.1 == 9 }"),
|
|
Example("let allValid = validators.↓reduce(true) { $0 && $1(input) }"),
|
|
Example("let anyValid = validators.↓reduce(false) { $0 || $1(input) }"),
|
|
Example("let allNines = nums.↓reduce(true, { $0.0 && $0.1 == 9 })"),
|
|
Example("let anyNines = nums.↓reduce(false, { $0.0 || $0.1 == 9 })"),
|
|
Example("let allValid = validators.↓reduce(true, { $0 && $1(input) })"),
|
|
Example("let anyValid = validators.↓reduce(false, { $0 || $1(input) })"),
|
|
Example("nums.reduce(into: true) { (r: inout Bool, s) in r = r && (s == 3) }")
|
|
]
|
|
)
|
|
|
|
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
|
|
Visitor(viewMode: .sourceAccurate)
|
|
}
|
|
}
|
|
|
|
private extension ReduceBooleanRule {
|
|
final class Visitor: ViolationsSyntaxVisitor {
|
|
override func visitPost(_ node: FunctionCallExprSyntax) {
|
|
guard
|
|
let calledExpression = node.calledExpression.as(MemberAccessExprSyntax.self),
|
|
calledExpression.name.text == "reduce",
|
|
let firstArgument = node.argumentList.first,
|
|
firstArgument.label?.text ?? "into" == "into",
|
|
let bool = firstArgument.expression.as(BooleanLiteralExprSyntax.self)
|
|
else {
|
|
return
|
|
}
|
|
|
|
let suggestedFunction = bool.booleanLiteral.tokenKind == .keyword(.true) ? "allSatisfy" : "contains"
|
|
violations.append(
|
|
ReasonedRuleViolation(
|
|
position: calledExpression.name.positionAfterSkippingLeadingTrivia,
|
|
reason: "Use `\(suggestedFunction)` instead"
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|