mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
Almost all rules based on SwiftSyntax can be set up now by just adding `@SwiftSyntaxRule` to the rule struct.
92 lines
3.2 KiB
Swift
92 lines
3.2 KiB
Swift
import SwiftSyntax
|
|
|
|
@SwiftSyntaxRule(foldExpressions: true)
|
|
struct EmptyCountRule: OptInRule {
|
|
var configuration = EmptyCountConfiguration()
|
|
|
|
static let description = RuleDescription(
|
|
identifier: "empty_count",
|
|
name: "Empty Count",
|
|
description: "Prefer checking `isEmpty` over comparing `count` to zero",
|
|
kind: .performance,
|
|
nonTriggeringExamples: [
|
|
Example("var count = 0"),
|
|
Example("[Int]().isEmpty"),
|
|
Example("[Int]().count > 1"),
|
|
Example("[Int]().count == 1"),
|
|
Example("[Int]().count == 0xff"),
|
|
Example("[Int]().count == 0b01"),
|
|
Example("[Int]().count == 0o07"),
|
|
Example("discount == 0"),
|
|
Example("order.discount == 0")
|
|
],
|
|
triggeringExamples: [
|
|
Example("[Int]().↓count == 0"),
|
|
Example("0 == [Int]().↓count"),
|
|
Example("[Int]().↓count==0"),
|
|
Example("[Int]().↓count > 0"),
|
|
Example("[Int]().↓count != 0"),
|
|
Example("[Int]().↓count == 0x0"),
|
|
Example("[Int]().↓count == 0x00_00"),
|
|
Example("[Int]().↓count == 0b00"),
|
|
Example("[Int]().↓count == 0o00"),
|
|
Example("↓count == 0")
|
|
]
|
|
)
|
|
}
|
|
|
|
private extension EmptyCountRule {
|
|
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
|
|
private let operators: Set = ["==", "!=", ">", ">=", "<", "<="]
|
|
|
|
override func visitPost(_ node: InfixOperatorExprSyntax) {
|
|
guard let operatorNode = node.operator.as(BinaryOperatorExprSyntax.self),
|
|
let binaryOperator = operatorNode.operator.binaryOperator,
|
|
operators.contains(binaryOperator) else {
|
|
return
|
|
}
|
|
|
|
if let intExpr = node.rightOperand.as(IntegerLiteralExprSyntax.self), intExpr.isZero,
|
|
let position = node.leftOperand.countCallPosition(onlyAfterDot: configuration.onlyAfterDot) {
|
|
violations.append(position)
|
|
return
|
|
}
|
|
|
|
if let intExpr = node.leftOperand.as(IntegerLiteralExprSyntax.self), intExpr.isZero,
|
|
let position = node.rightOperand.countCallPosition(onlyAfterDot: configuration.onlyAfterDot) {
|
|
violations.append(position)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension ExprSyntax {
|
|
func countCallPosition(onlyAfterDot: Bool) -> AbsolutePosition? {
|
|
if let expr = self.as(MemberAccessExprSyntax.self) {
|
|
if expr.declName.argumentNames == nil && expr.declName.baseName.tokenKind == .identifier("count") {
|
|
return expr.declName.baseName.positionAfterSkippingLeadingTrivia
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
if !onlyAfterDot, let expr = self.as(DeclReferenceExprSyntax.self) {
|
|
return expr.baseName.tokenKind == .identifier("count") ? expr.positionAfterSkippingLeadingTrivia : nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
private extension TokenSyntax {
|
|
var binaryOperator: String? {
|
|
switch tokenKind {
|
|
case .binaryOperator(let str):
|
|
return str
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
}
|