mirror of
https://github.com/realm/SwiftLint.git
synced 2026-05-07 20:12:49 +00:00
40bd97038a
Almost all rules based on SwiftSyntax can be set up now by just adding `@SwiftSyntaxRule` to the rule struct.
71 lines
2.4 KiB
Swift
71 lines
2.4 KiB
Swift
import SwiftSyntax
|
|
|
|
@SwiftSyntaxRule
|
|
struct ComputedAccessorsOrderRule: Rule {
|
|
var configuration = ComputedAccessorsOrderConfiguration()
|
|
|
|
static let description = RuleDescription(
|
|
identifier: "computed_accessors_order",
|
|
name: "Computed Accessors Order",
|
|
description: "Getter and setters in computed properties and subscripts should be in a consistent order.",
|
|
kind: .style,
|
|
nonTriggeringExamples: ComputedAccessorsOrderRuleExamples.nonTriggeringExamples,
|
|
triggeringExamples: ComputedAccessorsOrderRuleExamples.triggeringExamples
|
|
)
|
|
}
|
|
|
|
private extension ComputedAccessorsOrderRule {
|
|
private enum ViolationKind {
|
|
case `subscript`, property
|
|
}
|
|
|
|
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
|
|
override func visitPost(_ node: AccessorBlockSyntax) {
|
|
guard let firstAccessor = node.accessorsList.first,
|
|
let order = node.order,
|
|
order != configuration.order else {
|
|
return
|
|
}
|
|
|
|
let kind: ViolationKind = node.parent?.as(SubscriptDeclSyntax.self) == nil ? .property : .subscript
|
|
violations.append(
|
|
ReasonedRuleViolation(
|
|
position: firstAccessor.positionAfterSkippingLeadingTrivia,
|
|
reason: reason(for: kind)
|
|
)
|
|
)
|
|
}
|
|
|
|
private func reason(for kind: ViolationKind) -> String {
|
|
let kindString = kind == .subscript ? "subscripts" : "properties"
|
|
let orderString: String
|
|
switch configuration.order {
|
|
case .getSet:
|
|
orderString = "getter and then the setter"
|
|
case .setGet:
|
|
orderString = "setter and then the getter"
|
|
}
|
|
return "Computed \(kindString) should first declare the \(orderString)"
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension AccessorBlockSyntax {
|
|
var order: ComputedAccessorsOrderConfiguration.Order? {
|
|
guard accessorsList.count == 2, accessorsList.map(\.body).allSatisfy({ $0 != nil }) else {
|
|
return nil
|
|
}
|
|
|
|
let tokens = accessorsList.map(\.accessorSpecifier.tokenKind)
|
|
if tokens == [.keyword(.get), .keyword(.set)] {
|
|
return .getSet
|
|
}
|
|
|
|
if tokens == [.keyword(.set), .keyword(.get)] {
|
|
return .setGet
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|