Support arbitrary configurations in @SwiftSyntaxRule (#5275)

Almost all rules based on SwiftSyntax can be set up now by just adding
`@SwiftSyntaxRule` to the rule struct.
This commit is contained in:
Danny Mösch
2023-10-16 19:34:43 +02:00
committed by GitHub
parent 907294929b
commit 40bd97038a
177 changed files with 556 additions and 1061 deletions
@@ -3,12 +3,12 @@ import SwiftSyntaxBuilder
/// A helper to hold a visitor and rewriter that can lint and correct legacy NS/CG functions to a more modern syntax.
enum LegacyFunctionRuleHelper {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor<Configuration: RuleConfiguration>: ViolationsSyntaxVisitor<Configuration> {
private let legacyFunctions: [String: RewriteStrategy]
init(legacyFunctions: [String: RewriteStrategy]) {
init(configuration: Configuration, file: SwiftLintFile, legacyFunctions: [String: RewriteStrategy]) {
self.legacyFunctions = legacyFunctions
super.init(viewMode: .sourceAccurate)
super.init(configuration: configuration, file: file)
}
override func visitPost(_ node: FunctionCallExprSyntax) {
@@ -1,6 +1,7 @@
import SwiftSyntax
struct AnonymousArgumentInMultilineClosureRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct AnonymousArgumentInMultilineClosureRule: OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
@@ -30,21 +31,10 @@ struct AnonymousArgumentInMultilineClosureRule: SwiftSyntaxRule, OptInRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(locationConverter: file.locationConverter)
}
}
private extension AnonymousArgumentInMultilineClosureRule {
final class Visitor: ViolationsSyntaxVisitor {
private let locationConverter: SourceLocationConverter
init(locationConverter: SourceLocationConverter) {
self.locationConverter = locationConverter
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind {
let startLocation = locationConverter.location(for: node.leftBrace.positionAfterSkippingLeadingTrivia)
let endLocation = locationConverter.location(for: node.rightBrace.endPositionBeforeTrailingTrivia)
@@ -36,7 +36,7 @@ struct BlockBasedKVORule: Rule {
}
private extension BlockBasedKVORule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionDeclSyntax) {
guard node.modifiers.contains(keyword: .override),
case let parameterList = node.signature.parameterClause.parameters,
@@ -118,7 +118,7 @@ struct ConvenienceTypeRule: OptInRule {
}
private extension ConvenienceTypeRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: StructDeclSyntax) {
@@ -151,44 +151,44 @@ private extension ConvenienceTypeRule {
return false
}
return ConvenienceTypeCheckVisitor(viewMode: .sourceAccurate)
return ConvenienceTypeCheckVisitor(configuration: configuration, file: file)
.walk(tree: members, handler: \.canBeConvenienceType)
}
}
}
private class ConvenienceTypeCheckVisitor: ViolationsSyntaxVisitor {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
final class ConvenienceTypeCheckVisitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
private(set) var canBeConvenienceType = true
private(set) var canBeConvenienceType = true
override func visitPost(_ node: VariableDeclSyntax) {
if node.isInstanceVariable {
canBeConvenienceType = false
} else if node.attributes.containsObjc {
canBeConvenienceType = false
}
}
override func visitPost(_ node: FunctionDeclSyntax) {
if node.modifiers.containsStaticOrClass {
if node.attributes.containsObjc {
override func visitPost(_ node: VariableDeclSyntax) {
if node.isInstanceVariable {
canBeConvenienceType = false
} else if node.attributes.containsObjc {
canBeConvenienceType = false
}
} else {
canBeConvenienceType = false
}
}
override func visitPost(_ node: InitializerDeclSyntax) {
if !node.attributes.hasUnavailableAttribute {
canBeConvenienceType = false
override func visitPost(_ node: FunctionDeclSyntax) {
if node.modifiers.containsStaticOrClass {
if node.attributes.containsObjc {
canBeConvenienceType = false
}
} else {
canBeConvenienceType = false
}
}
}
override func visitPost(_ node: SubscriptDeclSyntax) {
if !node.modifiers.containsStaticOrClass {
canBeConvenienceType = false
override func visitPost(_ node: InitializerDeclSyntax) {
if !node.attributes.hasUnavailableAttribute {
canBeConvenienceType = false
}
}
override func visitPost(_ node: SubscriptDeclSyntax) {
if !node.modifiers.containsStaticOrClass {
canBeConvenienceType = false
}
}
}
}
@@ -26,7 +26,7 @@ struct DiscouragedAssertRule: OptInRule {
}
private extension DiscouragedAssertRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.calledExpression.as(DeclReferenceExprSyntax.self)?.baseName.text == "assert",
let firstArg = node.arguments.first,
@@ -180,7 +180,7 @@ struct DiscouragedNoneNameRule: OptInRule {
}
private extension DiscouragedNoneNameRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: EnumCaseElementSyntax) {
let emptyParams = node.parameterClause?.parameters.isEmpty ?? true
if emptyParams, node.name.isNone {
@@ -1,6 +1,7 @@
import SwiftSyntax
struct DiscouragedObjectLiteralRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct DiscouragedObjectLiteralRule: OptInRule {
var configuration = DiscouragedObjectLiteralConfiguration()
static let description = RuleDescription(
@@ -21,21 +22,10 @@ struct DiscouragedObjectLiteralRule: SwiftSyntaxRule, OptInRule {
Example("let color = ↓#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension DiscouragedObjectLiteralRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: ConfigurationType
init(configuration: ConfigurationType) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: MacroExpansionExprSyntax) {
guard
case let .identifier(identifierText) = node.macroName.tokenKind,
@@ -15,7 +15,7 @@ struct DiscouragedOptionalBooleanRule: OptInRule {
}
private extension DiscouragedOptionalBooleanRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: OptionalTypeSyntax) {
if node.wrappedType.as(IdentifierTypeSyntax.self)?.typeName == "Bool" {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -80,7 +80,7 @@ struct ExplicitEnumRawValueRule: OptInRule {
}
private extension ExplicitEnumRawValueRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: EnumCaseElementSyntax) {
@@ -1,6 +1,7 @@
import SwiftSyntax
import SwiftSyntaxBuilder
@SwiftSyntaxRule
struct ExplicitInitRule: SwiftSyntaxCorrectableRule, OptInRule {
var configuration = ExplicitInitConfiguration()
@@ -169,24 +170,13 @@ struct ExplicitInitRule: SwiftSyntaxCorrectableRule, OptInRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate, includeBareInit: configuration.includeBareInit)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
Rewriter(locationConverter: file.locationConverter, disabledRegions: disabledRegions(file: file))
}
}
private extension ExplicitInitRule {
final class Visitor: ViolationsSyntaxVisitor {
private let includeBareInit: Bool
init(viewMode: SyntaxTreeViewMode, includeBareInit: Bool) {
self.includeBareInit = includeBareInit
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard let calledExpression = node.calledExpression.as(MemberAccessExprSyntax.self) else {
return
@@ -196,7 +186,7 @@ private extension ExplicitInitRule {
violations.append(violationPosition)
}
if includeBareInit, let violationPosition = calledExpression.bareInitPosition {
if configuration.includeBareInit, let violationPosition = calledExpression.bareInitPosition {
let reason = "Prefer named constructors over .init and type inference"
violations.append(ReasonedRuleViolation(position: violationPosition, reason: reason))
}
@@ -31,7 +31,7 @@ struct ExplicitTopLevelACLRule: OptInRule {
}
private extension ExplicitTopLevelACLRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: ClassDeclSyntax) {
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ExplicitTypeInterfaceRule: OptInRule, SwiftSyntaxRule {
@SwiftSyntaxRule
struct ExplicitTypeInterfaceRule: OptInRule {
var configuration = ExplicitTypeInterfaceConfiguration()
static let description = RuleDescription(
@@ -68,23 +69,12 @@ struct ExplicitTypeInterfaceRule: OptInRule, SwiftSyntaxRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension ExplicitTypeInterfaceRule {
final class Visitor: ViolationsSyntaxVisitor {
let configuration: ExplicitTypeInterfaceConfiguration
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
init(configuration: ExplicitTypeInterfaceConfiguration) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: VariableDeclSyntax) {
if node.modifiers.contains(keyword: .class) {
if configuration.allowedKinds.contains(.class) {
@@ -31,7 +31,7 @@ struct FallthroughRule: OptInRule {
}
private extension FallthroughRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FallThroughStmtSyntax) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
@@ -37,7 +37,7 @@ struct FatalErrorMessageRule: OptInRule {
}
private extension FatalErrorMessageRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard let expression = node.calledExpression.as(DeclReferenceExprSyntax.self),
expression.baseName.text == "fatalError",
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ForWhereRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct ForWhereRule: Rule {
var configuration = ForWhereConfiguration()
static let description = RuleDescription(
@@ -115,21 +116,10 @@ struct ForWhereRule: SwiftSyntaxRule {
""", configuration: ["allow_for_as_filter": true])
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(allowForAsFilter: configuration.allowForAsFilter)
}
}
private extension ForWhereRule {
final class Visitor: ViolationsSyntaxVisitor {
private let allowForAsFilter: Bool
init(allowForAsFilter: Bool) {
self.allowForAsFilter = allowForAsFilter
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ForStmtSyntax) {
guard node.whereClause == nil,
let onlyExprStmt = node.body.statements.onlyElement?.item.as(ExpressionStmtSyntax.self),
@@ -142,7 +132,7 @@ private extension ForWhereRule {
return
}
if allowForAsFilter, ifExpr.containsReturnStatement {
if configuration.allowForAsFilter, ifExpr.containsReturnStatement {
return
}
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ForceCastRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct ForceCastRule: Rule {
var configuration = SeverityConfiguration<Self>(.error)
static let description = RuleDescription(
@@ -13,14 +14,10 @@ struct ForceCastRule: SwiftSyntaxRule {
],
triggeringExamples: [ Example("NSNumber() ↓as! Int") ]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension ForceCastRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: AsExprSyntax) {
if node.questionOrExclamationMark?.tokenKind == .exclamationMark {
violations.append(node.asKeyword.positionAfterSkippingLeadingTrivia)
@@ -27,7 +27,7 @@ struct ForceTryRule: Rule {
}
private extension ForceTryRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: TryExprSyntax) {
if node.questionOrExclamationMark?.tokenKind == .exclamationMark {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ForceUnwrappingRule: OptInRule, SwiftSyntaxRule {
@SwiftSyntaxRule
struct ForceUnwrappingRule: OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
@@ -64,14 +65,10 @@ struct ForceUnwrappingRule: OptInRule, SwiftSyntaxRule {
Example("map[\"a\"]↓!↓!")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension ForceUnwrappingRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ForceUnwrapExprSyntax) {
violations.append(node.exclamationMark.positionAfterSkippingLeadingTrivia)
}
@@ -52,7 +52,7 @@ struct FunctionDefaultParameterAtEndRule: OptInRule {
}
private extension FunctionDefaultParameterAtEndRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionDeclSyntax) {
guard !node.modifiers.contains(keyword: .override), node.signature.containsViolation else {
return
@@ -1,7 +1,8 @@
import Foundation
import SwiftSyntax
struct GenericTypeNameRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct GenericTypeNameRule: Rule {
var configuration = NameConfiguration<Self>(minLengthWarning: 1,
minLengthError: 0,
maxLengthWarning: 20,
@@ -47,21 +48,10 @@ struct GenericTypeNameRule: SwiftSyntaxRule {
]
}
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension GenericTypeNameRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: ConfigurationType
init(configuration: ConfigurationType) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: GenericParameterSyntax) {
let name = node.name.text
guard !name.isEmpty, !configuration.shouldExclude(name: name) else { return }
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ImplicitlyUnwrappedOptionalRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct ImplicitlyUnwrappedOptionalRule: OptInRule {
var configuration = ImplicitlyUnwrappedOptionalConfiguration()
static let description = RuleDescription(
@@ -40,27 +41,16 @@ struct ImplicitlyUnwrappedOptionalRule: SwiftSyntaxRule, OptInRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(mode: configuration.mode)
}
}
private extension ImplicitlyUnwrappedOptionalRule {
final class Visitor: ViolationsSyntaxVisitor {
private let mode: ConfigurationType.ImplicitlyUnwrappedOptionalModeConfiguration
init(mode: ConfigurationType.ImplicitlyUnwrappedOptionalModeConfiguration) {
self.mode = mode
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ImplicitlyUnwrappedOptionalTypeSyntax) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
switch mode {
switch configuration.mode {
case .all:
return .visitChildren
case .allExceptIBOutlets:
@@ -23,7 +23,7 @@ struct IsDisjointRule: Rule {
}
private extension IsDisjointRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: MemberAccessExprSyntax) {
guard
node.declName.baseName.text == "isEmpty",
@@ -46,7 +46,7 @@ struct JoinedDefaultParameterRule: SwiftSyntaxCorrectableRule, OptInRule {
}
private extension JoinedDefaultParameterRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
if let violationPosition = node.violationPosition {
violations.append(violationPosition)
@@ -100,8 +100,12 @@ struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule {
"CGRectIntersection": .function(name: "intersection", argumentLabels: [""])
]
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
LegacyFunctionRuleHelper.Visitor(legacyFunctions: Self.legacyFunctions)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
LegacyFunctionRuleHelper.Visitor(
configuration: configuration,
file: file,
legacyFunctions: Self.legacyFunctions
)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
@@ -24,7 +24,7 @@ struct LegacyConstantRule: SwiftSyntaxCorrectableRule {
}
private extension LegacyConstantRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: DeclReferenceExprSyntax) {
if LegacyConstantRuleExamples.patterns.keys.contains(node.baseName.text) {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -132,7 +132,7 @@ struct LegacyConstructorRule: SwiftSyntaxCorrectableRule {
}
private extension LegacyConstructorRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
if let identifierExpr = node.calledExpression.as(DeclReferenceExprSyntax.self),
constructorsToCorrectedNames[identifierExpr.baseName.text] != nil {
@@ -76,7 +76,7 @@ struct LegacyHashingRule: Rule {
}
private extension LegacyHashingRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: VariableDeclSyntax) {
guard
node.parent?.is(MemberBlockItemSyntax.self) == true,
@@ -40,7 +40,7 @@ struct LegacyMultipleRule: OptInRule {
}
private extension LegacyMultipleRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: InfixOperatorExprSyntax) {
guard let operatorNode = node.operator.as(BinaryOperatorExprSyntax.self),
operatorNode.operator.tokenKind == .binaryOperator("%"),
@@ -100,8 +100,12 @@ struct LegacyNSGeometryFunctionsRule: SwiftSyntaxCorrectableRule {
"NSPointInRect": .function(name: "contains", argumentLabels: [""], reversed: true)
]
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
LegacyFunctionRuleHelper.Visitor(legacyFunctions: Self.legacyFunctions)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
LegacyFunctionRuleHelper.Visitor(
configuration: configuration,
file: file,
legacyFunctions: Self.legacyFunctions
)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
@@ -69,7 +69,7 @@ struct LegacyObjcTypeRule: OptInRule {
}
private extension LegacyObjcTypeRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: IdentifierTypeSyntax) {
if let typeName = node.typeName, legacyObjcTypes.contains(typeName) {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -23,7 +23,7 @@ struct LegacyRandomRule: Rule {
}
private extension LegacyRandomRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private static let legacyRandomFunctions: Set<String> = [
"arc4random",
"arc4random_uniform",
@@ -24,7 +24,7 @@ struct NoExtensionAccessModifierRule: OptInRule {
}
private extension NoExtensionAccessModifierRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: ExtensionDeclSyntax) {
@@ -15,7 +15,7 @@ struct NoFallthroughOnlyRule: Rule {
}
private extension NoFallthroughOnlyRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: SwitchCaseListSyntax) {
let cases = node.compactMap { $0.as(SwitchCaseSyntax.self) }
@@ -1,6 +1,7 @@
import SwiftSyntax
struct NoMagicNumbersRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct NoMagicNumbersRule: OptInRule {
var configuration = NoMagicNumbersConfiguration()
static let description = RuleDescription(
@@ -90,27 +91,17 @@ struct NoMagicNumbersRule: SwiftSyntaxRule, OptInRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate, testParentClasses: configuration.testParentClasses)
}
}
private extension NoMagicNumbersRule {
final class Visitor: ViolationsSyntaxVisitor {
private let testParentClasses: Set<String>
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private var testClasses: Set<String> = []
private var nonTestClasses: Set<String> = []
private var possibleViolations: [String: Set<AbsolutePosition>] = [:]
init(viewMode: SyntaxTreeViewMode, testParentClasses: Set<String>) {
self.testParentClasses = testParentClasses
super.init(viewMode: viewMode)
}
override func visitPost(_ node: ClassDeclSyntax) {
let className = node.name.text
if node.isXCTestCase(testParentClasses) {
if node.isXCTestCase(configuration.testParentClasses) {
testClasses.insert(className)
removeViolations(forClassName: className)
} else {
@@ -133,7 +124,7 @@ private extension NoMagicNumbersRule {
}
private func collectViolation(forNode node: some ExprSyntaxProtocol) {
if node.isMemberOfATestClass(testParentClasses) {
if node.isMemberOfATestClass(configuration.testParentClasses) {
return
}
if node.isOperandOfBitwiseShiftOperation() {
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ObjectLiteralRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct ObjectLiteralRule: OptInRule {
var configuration = ObjectLiteralConfiguration<Self>()
static let description = RuleDescription(
@@ -30,32 +31,19 @@ struct ObjectLiteralRule: SwiftSyntaxRule, OptInRule {
}
}
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(validateImageLiteral: configuration.imageLiteral, validateColorLiteral: configuration.colorLiteral)
}
}
private extension ObjectLiteralRule {
final class Visitor: ViolationsSyntaxVisitor {
private let validateImageLiteral: Bool
private let validateColorLiteral: Bool
init(validateImageLiteral: Bool, validateColorLiteral: Bool) {
self.validateImageLiteral = validateImageLiteral
self.validateColorLiteral = validateColorLiteral
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard validateColorLiteral || validateImageLiteral else {
guard configuration.colorLiteral || configuration.imageLiteral else {
return
}
let name = node.calledExpression.trimmedDescription
if validateImageLiteral, isImageNamedInit(node: node, name: name) {
if configuration.imageLiteral, isImageNamedInit(node: node, name: name) {
violations.append(node.positionAfterSkippingLeadingTrivia)
} else if validateColorLiteral, isColorInit(node: node, name: name) {
} else if configuration.colorLiteral, isColorInit(node: node, name: name) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
@@ -36,16 +36,16 @@ struct PatternMatchingKeywordsRule: OptInRule {
}
private extension PatternMatchingKeywordsRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: SwitchCaseItemSyntax) {
let localViolations = TupleVisitor(viewMode: .sourceAccurate)
let localViolations = TupleVisitor(configuration: configuration, file: file)
.walk(tree: node.pattern, handler: \.violations)
violations.append(contentsOf: localViolations)
}
}
}
private final class TupleVisitor: ViolationsSyntaxVisitor {
private final class TupleVisitor<Configuration: RuleConfiguration>: ViolationsSyntaxVisitor<Configuration> {
override func visitPost(_ node: LabeledExprListSyntax) {
let list = node.flatteningEnumPatterns()
.compactMap { elem in
@@ -25,7 +25,7 @@ struct PreferNimbleRule: OptInRule {
}
private extension PreferNimbleRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
if let expr = node.calledExpression.as(DeclReferenceExprSyntax.self),
expr.baseName.text.starts(with: "XCTAssert") {
@@ -44,7 +44,7 @@ struct PreferZeroOverExplicitInitRule: SwiftSyntaxCorrectableRule, OptInRule {
}
private extension PreferZeroOverExplicitInitRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
if node.hasViolation {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -1,5 +1,6 @@
import SwiftSyntax
@SwiftSyntaxRule
struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule {
var configuration = PrivateOverFilePrivateConfiguration()
@@ -54,10 +55,6 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(validateExtensions: configuration.validateExtensions)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
Rewriter(
validateExtensions: configuration.validateExtensions,
@@ -68,14 +65,7 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule {
}
private extension PrivateOverFilePrivateRule {
final class Visitor: ViolationsSyntaxVisitor {
private let validateExtensions: Bool
init(validateExtensions: Bool) {
self.validateExtensions = validateExtensions
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
if let privateModifier = node.modifiers.fileprivateModifier {
violations.append(privateModifier.positionAfterSkippingLeadingTrivia)
@@ -84,7 +74,7 @@ private extension PrivateOverFilePrivateRule {
}
override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
if validateExtensions, let privateModifier = node.modifiers.fileprivateModifier {
if configuration.validateExtensions, let privateModifier = node.modifiers.fileprivateModifier {
violations.append(privateModifier.positionAfterSkippingLeadingTrivia)
}
return .skipChildren
@@ -31,7 +31,7 @@ struct RedundantNilCoalescingRule: OptInRule, SwiftSyntaxCorrectableRule {
}
private extension RedundantNilCoalescingRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: TokenSyntax) {
if node.tokenKind.isNilCoalescingOperator,
node.nextToken(viewMode: .sourceAccurate)?.tokenKind == .keyword(.nil) {
@@ -18,15 +18,15 @@ struct RedundantObjcAttributeRule: SwiftSyntaxRule, SubstitutionCorrectableRule
corrections: RedundantObjcAttributeRuleExamples.corrections
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor {
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: AttributeListSyntax) {
if let objcAttribute = node.violatingObjCAttribute {
violations.append(objcAttribute.positionAfterSkippingLeadingTrivia)
}
}
}
return Visitor(viewMode: .sourceAccurate)
return Visitor(configuration: configuration, file: file)
}
func violationRanges(in file: SwiftLintFile) -> [NSRange] {
@@ -114,7 +114,7 @@ struct RedundantOptionalInitializationRule: SwiftSyntaxCorrectableRule {
}
private extension RedundantOptionalInitializationRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: VariableDeclSyntax) {
guard node.bindingSpecifier.tokenKind == .keyword(.var),
!node.modifiers.contains(keyword: .lazy) else {
@@ -61,7 +61,7 @@ struct RedundantSetAccessControlRule: Rule {
}
private extension RedundantSetAccessControlRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
[FunctionDeclSyntax.self]
}
@@ -62,7 +62,7 @@ struct RedundantStringEnumValueRule: Rule {
}
private extension RedundantStringEnumValueRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: EnumDeclSyntax) {
guard node.isStringEnum else {
return
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ReturnValueFromVoidFunctionRule: OptInRule, SwiftSyntaxRule {
@SwiftSyntaxRule
struct ReturnValueFromVoidFunctionRule: OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
@@ -12,14 +13,10 @@ struct ReturnValueFromVoidFunctionRule: OptInRule, SwiftSyntaxRule {
nonTriggeringExamples: ReturnValueFromVoidFunctionRuleExamples.nonTriggeringExamples,
triggeringExamples: ReturnValueFromVoidFunctionRuleExamples.triggeringExamples
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension ReturnValueFromVoidFunctionRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ReturnStmtSyntax) {
if node.expression != nil,
let functionNode = Syntax(node).enclosingFunction(),
@@ -89,7 +89,7 @@ struct ShorthandOptionalBindingRule: OptInRule, SwiftSyntaxCorrectableRule {
}
private extension ShorthandOptionalBindingRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: OptionalBindingConditionSyntax) {
if node.isShadowingOptionalBinding {
violations.append(node.bindingSpecifier.positionAfterSkippingLeadingTrivia)
@@ -79,7 +79,7 @@ struct StaticOperatorRule: OptInRule {
}
private extension StaticOperatorRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: FunctionDeclSyntax) {
@@ -1,6 +1,7 @@
import SwiftSyntax
struct StrictFilePrivateRule: OptInRule, SwiftSyntaxRule {
@SwiftSyntaxRule
struct StrictFilePrivateRule: OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
@@ -122,10 +123,6 @@ struct StrictFilePrivateRule: OptInRule, SwiftSyntaxRule {
""", excludeFromDocumentation: true)
}
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate, file: file.syntaxTree)
}
}
private enum ProtocolRequirementType: Equatable {
@@ -135,16 +132,10 @@ private enum ProtocolRequirementType: Equatable {
}
private extension StrictFilePrivateRule {
final class Visitor: ViolationsSyntaxVisitor {
private let file: SourceFileSyntax
init(viewMode: SyntaxTreeViewMode, file: SourceFileSyntax) {
self.file = file
super.init(viewMode: viewMode)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private lazy var protocols = {
ProtocolCollector(viewMode: .sourceAccurate).walk(tree: file, handler: \.protocols)
ProtocolCollector(configuration: configuration, file: file)
.walk(tree: file.syntaxTree, handler: \.protocols)
}()
override func visitPost(_ node: DeclModifierSyntax) {
@@ -212,7 +203,7 @@ private extension StrictFilePrivateRule {
}
}
private final class ProtocolCollector: ViolationsSyntaxVisitor {
private final class ProtocolCollector<Configuration: RuleConfiguration>: ViolationsSyntaxVisitor<Configuration> {
private(set) var protocols = [String: [ProtocolRequirementType]]()
private var currentProtocolName: String = ""
@@ -39,7 +39,7 @@ struct ToggleBoolRule: SwiftSyntaxCorrectableRule, OptInRule {
}
private extension ToggleBoolRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ExprListSyntax) {
if node.hasToggleBoolViolation {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -34,7 +34,7 @@ struct TrailingSemicolonRule: SwiftSyntaxCorrectableRule {
}
private extension TrailingSemicolonRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: TokenSyntax) {
if node.isTrailingSemicolon {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -1,7 +1,8 @@
import Foundation
import SwiftSyntax
struct TypeNameRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct TypeNameRule: Rule {
var configuration = TypeNameConfiguration()
static let description = RuleDescription(
@@ -16,21 +17,10 @@ struct TypeNameRule: SwiftSyntaxRule {
nonTriggeringExamples: TypeNameRuleExamples.nonTriggeringExamples,
triggeringExamples: TypeNameRuleExamples.triggeringExamples
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension TypeNameRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: TypeNameConfiguration
init(configuration: TypeNameConfiguration) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: StructDeclSyntax) {
if let violation = violation(identifier: node.name, modifiers: node.modifiers,
inheritedTypes: node.inheritanceClause?.inheritedTypes) {
@@ -1,6 +1,7 @@
import SwiftSyntax
struct UnavailableConditionRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct UnavailableConditionRule: Rule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
@@ -68,14 +69,10 @@ struct UnavailableConditionRule: SwiftSyntaxRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension UnavailableConditionRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: IfExprSyntax) {
guard node.body.statements.isEmpty else {
return
@@ -73,7 +73,7 @@ struct UnavailableFunctionRule: OptInRule {
}
private extension UnavailableFunctionRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionDeclSyntax) {
guard !node.returnsNever,
!node.attributes.hasUnavailableAttribute,
@@ -12,6 +12,7 @@ private func embedInSwitch(
""", file: file, line: line)
}
@SwiftSyntaxRule
struct UnneededBreakInSwitchRule: SwiftSyntaxCorrectableRule {
var configuration = SeverityConfiguration<Self>(.warning)
@@ -86,10 +87,6 @@ struct UnneededBreakInSwitchRule: SwiftSyntaxCorrectableRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
Rewriter(
locationConverter: file.locationConverter,
@@ -99,7 +96,7 @@ struct UnneededBreakInSwitchRule: SwiftSyntaxCorrectableRule {
}
private extension UnneededBreakInSwitchRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: SwitchCaseSyntax) {
guard let statement = node.unneededBreak else {
return
@@ -37,7 +37,7 @@ struct UnneededSynthesizedInitializerRule: SwiftSyntaxCorrectableRule {
}
private extension UnneededSynthesizedInitializerRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
.allExcept(StructDeclSyntax.self, ClassDeclSyntax.self)
}
@@ -1,5 +1,6 @@
import SwiftSyntax
@SwiftSyntaxRule
struct UntypedErrorInCatchRule: OptInRule, SwiftSyntaxCorrectableRule {
var configuration = SeverityConfiguration<Self>(.warning)
@@ -85,10 +86,6 @@ struct UntypedErrorInCatchRule: OptInRule, SwiftSyntaxCorrectableRule {
Example("do {\n try foo() \n} ↓catch (let error) {}"): Example("do {\n try foo() \n} catch {}")
])
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
Rewriter(
locationConverter: file.locationConverter,
@@ -120,7 +117,7 @@ private extension CatchItemSyntax {
}
private extension UntypedErrorInCatchRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: CatchClauseSyntax) {
guard let item = node.catchItems.onlyElement, item.isIdentifierPattern else {
return
@@ -30,7 +30,7 @@ struct UnusedEnumeratedRule: Rule {
}
private extension UnusedEnumeratedRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ForStmtSyntax) {
guard let tuplePattern = node.pattern.as(TuplePatternSyntax.self),
tuplePattern.elements.count == 2,
@@ -1,6 +1,7 @@
import SwiftSyntax
struct VoidFunctionInTernaryConditionRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct VoidFunctionInTernaryConditionRule: Rule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
@@ -105,14 +106,10 @@ struct VoidFunctionInTernaryConditionRule: SwiftSyntaxRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension VoidFunctionInTernaryConditionRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: TernaryExprSyntax) {
guard node.thenExpression.is(FunctionCallExprSyntax.self),
node.elseExpression.is(FunctionCallExprSyntax.self),
@@ -37,7 +37,7 @@ struct XCTFailMessageRule: Rule {
}
private extension XCTFailMessageRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard
let expression = node.calledExpression.as(DeclReferenceExprSyntax.self),
@@ -1,7 +1,8 @@
import SwiftOperators
import SwiftSyntax
struct XCTSpecificMatcherRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct XCTSpecificMatcherRule: OptInRule {
var configuration = XCTSpecificMatcherConfiguration()
static let description = RuleDescription(
@@ -12,21 +13,10 @@ struct XCTSpecificMatcherRule: SwiftSyntaxRule, OptInRule {
nonTriggeringExamples: XCTSpecificMatcherRuleExamples.nonTriggeringExamples,
triggeringExamples: XCTSpecificMatcherRuleExamples.triggeringExamples
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension XCTSpecificMatcherRule {
final class Visitor: ViolationsSyntaxVisitor {
let configuration: XCTSpecificMatcherConfiguration
init(configuration: XCTSpecificMatcherConfiguration) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
if configuration.matchers.contains(.twoArgumentAsserts),
let suggestion = TwoArgsXCTAssert.violations(in: node) {
@@ -38,9 +38,9 @@ struct AnyObjectProtocolRule: SwiftSyntaxCorrectableRule, OptInRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
warnDeprecatedOnce()
return Visitor(viewMode: .sourceAccurate)
return Visitor(configuration: configuration, file: file)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
@@ -52,7 +52,7 @@ struct AnyObjectProtocolRule: SwiftSyntaxCorrectableRule, OptInRule {
}
private extension AnyObjectProtocolRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ClassRestrictionTypeSyntax) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
@@ -52,7 +52,7 @@ struct ArrayInitRule: OptInRule {
}
private extension ArrayInitRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard let memberAccess = node.calledExpression.as(MemberAccessExprSyntax.self),
memberAccess.declName.baseName.text == "map",
@@ -1,6 +1,7 @@
import SwiftSyntax
struct BalancedXCTestLifecycleRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct BalancedXCTestLifecycleRule: OptInRule {
var configuration = BalancedXCTestLifecycleConfiguration()
static let description = RuleDescription(
@@ -103,30 +104,20 @@ struct BalancedXCTestLifecycleRule: SwiftSyntaxRule, OptInRule {
"""#)
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate, testParentClasses: configuration.testParentClasses)
}
}
// MARK: - Private
private extension BalancedXCTestLifecycleRule {
final class Visitor: ViolationsSyntaxVisitor {
private let testParentClasses: Set<String>
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
init(viewMode: SyntaxTreeViewMode, testParentClasses: Set<String>) {
self.testParentClasses = testParentClasses
super.init(viewMode: viewMode)
}
override func visitPost(_ node: ClassDeclSyntax) {
guard node.isXCTestCase(testParentClasses) else {
guard node.isXCTestCase(configuration.testParentClasses) else {
return
}
let methods = SetupTearDownVisitor(viewMode: .sourceAccurate)
let methods = SetupTearDownVisitor(configuration: configuration, file: file)
.walk(tree: node.memberBlock, handler: \.methods)
guard methods.contains(.setUp) != methods.contains(.tearDown) else {
return
@@ -137,7 +128,7 @@ private extension BalancedXCTestLifecycleRule {
}
}
private final class SetupTearDownVisitor: ViolationsSyntaxVisitor {
private final class SetupTearDownVisitor<Configuration: RuleConfiguration>: ViolationsSyntaxVisitor<Configuration> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
private(set) var methods: Set<XCTMethod> = []
@@ -32,7 +32,7 @@ struct ClassDelegateProtocolRule: Rule {
}
private extension ClassDelegateProtocolRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
.allExcept(ProtocolDeclSyntax.self)
}
@@ -24,7 +24,7 @@ struct CompilerProtocolInitRule: Rule {
}
private extension CompilerProtocolInitRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.trailingClosure == nil else {
return
@@ -1,6 +1,7 @@
import SwiftSyntax
struct DeploymentTargetRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct DeploymentTargetRule {
fileprivate typealias Version = DeploymentTargetConfiguration.Version
var configuration = DeploymentTargetConfiguration()
@@ -13,50 +14,39 @@ struct DeploymentTargetRule: SwiftSyntaxRule {
nonTriggeringExamples: DeploymentTargetRuleExamples.nonTriggeringExamples,
triggeringExamples: DeploymentTargetRuleExamples.triggeringExamples
)
}
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(platformToConfiguredMinVersion: platformToConfiguredMinVersion)
}
private enum AvailabilityType {
case condition
case attribute
case negativeCondition
private var platformToConfiguredMinVersion: [String: Version] {
return [
"iOS": configuration.iOSDeploymentTarget,
"iOSApplicationExtension": configuration.iOSAppExtensionDeploymentTarget,
"macOS": configuration.macOSDeploymentTarget,
"macOSApplicationExtension": configuration.macOSAppExtensionDeploymentTarget,
"OSX": configuration.macOSDeploymentTarget,
"tvOS": configuration.tvOSDeploymentTarget,
"tvOSApplicationExtension": configuration.tvOSAppExtensionDeploymentTarget,
"watchOS": configuration.watchOSDeploymentTarget,
"watchOSApplicationExtension": configuration.watchOSAppExtensionDeploymentTarget
]
}
private enum AvailabilityType {
case condition
case attribute
case negativeCondition
var displayString: String {
switch self {
case .condition:
return "condition"
case .attribute:
return "attribute"
case .negativeCondition:
return "negative condition"
}
var displayString: String {
switch self {
case .condition:
return "condition"
case .attribute:
return "attribute"
case .negativeCondition:
return "negative condition"
}
}
}
private extension DeploymentTargetRule {
final class Visitor: ViolationsSyntaxVisitor {
private let platformToConfiguredMinVersion: [String: Version]
init(platformToConfiguredMinVersion: [String: Version]) {
self.platformToConfiguredMinVersion = platformToConfiguredMinVersion
super.init(viewMode: .sourceAccurate)
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private var platformToConfiguredMinVersion: [String: Version] {
[
"iOS": configuration.iOSDeploymentTarget,
"iOSApplicationExtension": configuration.iOSAppExtensionDeploymentTarget,
"macOS": configuration.macOSDeploymentTarget,
"macOSApplicationExtension": configuration.macOSAppExtensionDeploymentTarget,
"OSX": configuration.macOSDeploymentTarget,
"tvOS": configuration.tvOSDeploymentTarget,
"tvOSApplicationExtension": configuration.tvOSAppExtensionDeploymentTarget,
"watchOS": configuration.watchOSDeploymentTarget,
"watchOSApplicationExtension": configuration.watchOSAppExtensionDeploymentTarget
]
}
override func visitPost(_ node: AttributeSyntax) {
@@ -59,7 +59,7 @@ struct DiscardedNotificationCenterObserverRule: OptInRule {
}
private extension DiscardedNotificationCenterObserverRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard
let calledExpression = node.calledExpression.as(MemberAccessExprSyntax.self),
@@ -1,6 +1,7 @@
import SwiftSyntax
struct DiscouragedDirectInitRule: SwiftSyntaxRule {
@SwiftSyntaxRule
struct DiscouragedDirectInitRule: Rule {
var configuration = DiscouragedDirectInitConfiguration()
static let description = RuleDescription(
@@ -34,24 +35,13 @@ struct DiscouragedDirectInitRule: SwiftSyntaxRule {
Example("let foo = bar(bundle: ↓Bundle.init(), device: ↓UIDevice.init(), error: ↓NSError.init())")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(discouragedInits: configuration.discouragedInits)
}
}
private extension DiscouragedDirectInitRule {
final class Visitor: ViolationsSyntaxVisitor {
private let discouragedInits: Set<String>
init(discouragedInits: Set<String>) {
self.discouragedInits = discouragedInits
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.arguments.isEmpty, node.trailingClosure == nil,
discouragedInits.contains(node.calledExpression.trimmedDescription) else {
configuration.discouragedInits.contains(node.calledExpression.trimmedDescription) else {
return
}
@@ -158,7 +158,7 @@ struct DuplicateConditionsRule: Rule {
}
private extension DuplicateConditionsRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: IfExprSyntax) {
if node.parent?.is(IfExprSyntax.self) == true {
// We can skip these cases - they will be picked up when we visit the top level `if`
@@ -58,7 +58,7 @@ struct DuplicateEnumCasesRule: Rule {
}
private extension DuplicateEnumCasesRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: EnumDeclSyntax) {
let enumElements = node.memberBlock.members
.flatMap { member -> EnumCaseElementListSyntax in
@@ -80,7 +80,7 @@ struct DuplicatedKeyInDictionaryLiteralRule: Rule {
}
private extension DuplicatedKeyInDictionaryLiteralRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ list: DictionaryElementListSyntax) {
let keys = list.map(\.key).compactMap { expr -> DictionaryKey? in
expr.stringContent.map {
@@ -25,7 +25,7 @@ struct DynamicInlineRule: Rule {
}
private extension DynamicInlineRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionDeclSyntax) {
if node.modifiers.contains(where: { $0.name.text == "dynamic" }),
node.attributes.contains(where: { $0.as(AttributeSyntax.self)?.isInlineAlways == true }) {
@@ -1,6 +1,7 @@
import SwiftSyntax
struct EmptyXCTestMethodRule: OptInRule, SwiftSyntaxRule {
@SwiftSyntaxRule
struct EmptyXCTestMethodRule: OptInRule {
var configuration = EmptyXCTestMethodConfiguration()
static let description = RuleDescription(
@@ -11,24 +12,14 @@ struct EmptyXCTestMethodRule: OptInRule, SwiftSyntaxRule {
nonTriggeringExamples: EmptyXCTestMethodRuleExamples.nonTriggeringExamples,
triggeringExamples: EmptyXCTestMethodRuleExamples.triggeringExamples
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(testParentClasses: configuration.testParentClasses)
}
}
private extension EmptyXCTestMethodRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
private let testParentClasses: Set<String>
init(testParentClasses: Set<String>) {
self.testParentClasses = testParentClasses
super.init(viewMode: .sourceAccurate)
}
override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
node.isXCTestCase(testParentClasses) ? .visitChildren : .skipChildren
node.isXCTestCase(configuration.testParentClasses) ? .visitChildren : .skipChildren
}
override func visitPost(_ node: FunctionDeclSyntax) {
@@ -27,7 +27,7 @@ struct IBInspectableInExtensionRule: OptInRule {
}
private extension IBInspectableInExtensionRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
.allExcept(ExtensionDeclSyntax.self, VariableDeclSyntax.self)
}
@@ -72,7 +72,7 @@ struct IdenticalOperandsRule: OptInRule {
}
private extension IdenticalOperandsRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: InfixOperatorExprSyntax) {
guard let operatorNode = node.operator.as(BinaryOperatorExprSyntax.self),
IdenticalOperandsRule.operators.contains(operatorNode.operator.text) else {
@@ -83,14 +83,14 @@ struct InertDeferRule: SwiftSyntaxRule, OptInRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
warnDeprecatedOnce()
return Visitor(viewMode: .sourceAccurate)
return Visitor(configuration: configuration, file: file)
}
}
private extension InertDeferRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: DeferStmtSyntax) {
guard node.isLastStatement else {
return
@@ -40,20 +40,25 @@ struct LocalDocCommentRule: SwiftSyntaxRule, OptInRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(classifications: file.syntaxClassifications.filter { $0.kind != .none })
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
Visitor(
configuration: configuration,
file: file,
classifications: file.syntaxClassifications.filter { $0.kind != .none }
)
}
}
private extension LocalDocCommentRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private let docCommentRanges: [ByteSourceRange]
init(classifications: [SyntaxClassifiedRange]) {
init(configuration: ConfigurationType, file: SwiftLintFile,
classifications: [SyntaxClassifiedRange]) {
self.docCommentRanges = classifications
.filter { $0.kind == .docLineComment || $0.kind == .docBlockComment }
.map(\.range)
super.init(viewMode: .sourceAccurate)
super.init(configuration: configuration, file: file)
}
override func visitPost(_ node: FunctionDeclSyntax) {
@@ -90,7 +90,7 @@ struct LowerACLThanParentRule: OptInRule, SwiftSyntaxCorrectableRule {
}
private extension LowerACLThanParentRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: DeclModifierSyntax) {
if node.isHigherACLThanParent {
violations.append(node.positionAfterSkippingLeadingTrivia)
@@ -34,7 +34,7 @@ struct NSLocalizedStringKeyRule: OptInRule {
}
private extension NSLocalizedStringKeyRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.calledExpression.as(DeclReferenceExprSyntax.self)?.baseName.text == "NSLocalizedString" else {
return
@@ -43,7 +43,7 @@ struct NSLocalizedStringRequireBundleRule: OptInRule {
}
private extension NSLocalizedStringRequireBundleRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
if let identifierExpr = node.calledExpression.as(DeclReferenceExprSyntax.self),
identifierExpr.baseName.tokenKind == .identifier("NSLocalizedString"),
@@ -26,7 +26,7 @@ struct NSNumberInitAsFunctionReferenceRule: Rule {
}
private extension NSNumberInitAsFunctionReferenceRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: MemberAccessExprSyntax) {
guard node.declName.argumentNames.isEmptyOrNil,
node.declName.baseName.text == "init",
@@ -15,7 +15,7 @@ struct NSObjectPreferIsEqualRule: Rule {
}
private extension NSObjectPreferIsEqualRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .extensionsAndProtocols }
override func visitPost(_ node: FunctionDeclSyntax) {
@@ -15,7 +15,7 @@ struct NotificationCenterDetachmentRule: Rule {
}
private extension NotificationCenterDetachmentRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.isNotificationCenterDettachmentCall,
let arg = node.arguments.first,
@@ -1,6 +1,7 @@
import SwiftSyntax
struct OverriddenSuperCallRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct OverriddenSuperCallRule: OptInRule {
var configuration = OverriddenSuperCallConfiguration()
static let description = RuleDescription(
@@ -73,31 +74,18 @@ struct OverriddenSuperCallRule: SwiftSyntaxRule, OptInRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(resolvedMethodNames: configuration.resolvedMethodNames)
}
}
private extension OverriddenSuperCallRule {
final class Visitor: ViolationsSyntaxVisitor {
private let resolvedMethodNames: [String]
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
[ProtocolDeclSyntax.self]
}
init(resolvedMethodNames: [String]) {
self.resolvedMethodNames = resolvedMethodNames
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: FunctionDeclSyntax) {
guard let body = node.body,
node.modifiers.contains(keyword: .override),
!node.modifiers.containsStaticOrClass,
case let name = node.resolvedName(),
resolvedMethodNames.contains(name) else {
configuration.resolvedMethodNames.contains(name) else {
return
}
@@ -33,20 +33,27 @@ struct OverrideInExtensionRule: OptInRule, SwiftSyntaxRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
let allowedExtensions = ClassNameCollectingVisitor(viewMode: .sourceAccurate)
.walk(tree: file.syntaxTree, handler: \.classNames)
return Visitor(allowedExtensions: allowedExtensions)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor<ConfigurationType> {
let allowedExtensions = ClassNameCollectingVisitor(
configuration: configuration,
file: file
).walk(tree: file.syntaxTree, handler: \.classNames)
return Visitor(
configuration: configuration,
file: file,
allowedExtensions: allowedExtensions
)
}
}
private extension OverrideInExtensionRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private let allowedExtensions: Set<String>
init(allowedExtensions: Set<String>) {
init(configuration: ConfigurationType, file: SwiftLintFile,
allowedExtensions: Set<String>) {
self.allowedExtensions = allowedExtensions
super.init(viewMode: .sourceAccurate)
super.init(configuration: configuration, file: file)
}
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .allExcept(ExtensionDeclSyntax.self) }
@@ -72,14 +79,14 @@ private extension OverrideInExtensionRule {
return .visitChildren
}
}
}
private class ClassNameCollectingVisitor: ViolationsSyntaxVisitor {
private(set) var classNames: Set<String> = []
final class ClassNameCollectingVisitor: ViolationsSyntaxVisitor<ConfigurationType> {
private(set) var classNames: Set<String> = []
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: ClassDeclSyntax) {
classNames.insert(node.name.text)
override func visitPost(_ node: ClassDeclSyntax) {
classNames.insert(node.name.text)
}
}
}
@@ -34,7 +34,7 @@ struct PrivateActionRule: OptInRule {
}
private extension PrivateActionRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind {
node.modifiers.containsPrivateOrFileprivate() ? .skipChildren : .visitChildren
}
@@ -1,6 +1,7 @@
import SwiftSyntax
struct PrivateOutletRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct PrivateOutletRule: OptInRule {
var configuration = PrivateOutletConfiguration()
static let description = RuleDescription(
@@ -75,21 +76,10 @@ struct PrivateOutletRule: SwiftSyntaxRule, OptInRule {
""", configuration: ["allow_private_set": false], excludeFromDocumentation: true)
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(allowPrivateSet: configuration.allowPrivateSet)
}
}
private extension PrivateOutletRule {
final class Visitor: ViolationsSyntaxVisitor {
private let allowPrivateSet: Bool
init(allowPrivateSet: Bool) {
self.allowPrivateSet = allowPrivateSet
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: MemberBlockItemSyntax) {
guard
let decl = node.decl.as(VariableDeclSyntax.self),
@@ -99,7 +89,7 @@ private extension PrivateOutletRule {
return
}
if allowPrivateSet && decl.modifiers.containsPrivateOrFileprivate(setOnly: true) {
if configuration.allowPrivateSet && decl.modifiers.containsPrivateOrFileprivate(setOnly: true) {
return
}
@@ -15,7 +15,7 @@ struct PrivateSubjectRule: OptInRule {
}
private extension PrivateSubjectRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private let subjectTypes: Set<String> = ["PassthroughSubject", "CurrentValueSubject"]
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
@@ -196,7 +196,7 @@ struct PrivateSwiftUIStatePropertyRule: OptInRule {
}
private extension PrivateSwiftUIStatePropertyRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
[ProtocolDeclSyntax.self]
}
@@ -1,6 +1,7 @@
import Foundation
import SwiftSyntax
@SwiftSyntaxRule
struct PrivateUnitTestRule: SwiftSyntaxCorrectableRule {
var configuration = PrivateUnitTestConfiguration()
@@ -125,10 +126,6 @@ struct PrivateUnitTestRule: SwiftSyntaxCorrectableRule {
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
func makeRewriter(file: SwiftLintFile) -> (some ViolationsSyntaxRewriter)? {
Rewriter(
configuration: configuration,
@@ -139,16 +136,9 @@ struct PrivateUnitTestRule: SwiftSyntaxCorrectableRule {
}
private extension PrivateUnitTestRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: PrivateUnitTestConfiguration
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
init(configuration: PrivateUnitTestConfiguration) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
!node.isPrivate && node.hasParent(configuredIn: configuration) ? .visitChildren : .skipChildren
}
@@ -21,7 +21,7 @@ struct ProhibitedInterfaceBuilderRule: OptInRule {
}
private extension ProhibitedInterfaceBuilderRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: VariableDeclSyntax) {
if node.isIBOutlet {
violations.append(node.bindingSpecifier.positionAfterSkippingLeadingTrivia)
@@ -1,6 +1,7 @@
import SwiftSyntax
struct ProhibitedSuperRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct ProhibitedSuperRule: OptInRule {
var configuration = ProhibitedSuperConfiguration()
static let description = RuleDescription(
@@ -69,31 +70,18 @@ struct ProhibitedSuperRule: SwiftSyntaxRule, OptInRule {
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(resolvedMethodNames: configuration.resolvedMethodNames)
}
}
private extension ProhibitedSuperRule {
final class Visitor: ViolationsSyntaxVisitor {
private let resolvedMethodNames: [String]
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] {
[ProtocolDeclSyntax.self]
}
init(resolvedMethodNames: [String]) {
self.resolvedMethodNames = resolvedMethodNames
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: FunctionDeclSyntax) {
guard let body = node.body,
node.modifiers.contains(keyword: .override),
!node.modifiers.containsStaticOrClass,
case let name = node.resolvedName(),
resolvedMethodNames.contains(name),
configuration.resolvedMethodNames.contains(name),
node.numberOfCallsToSuper() > 0 else {
return
}
@@ -15,7 +15,7 @@ struct QuickDiscouragedFocusedTestRule: OptInRule {
}
private extension QuickDiscouragedFocusedTestRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: FunctionCallExprSyntax) {
@@ -15,7 +15,7 @@ struct QuickDiscouragedPendingTestRule: OptInRule {
}
private extension QuickDiscouragedPendingTestRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: FunctionCallExprSyntax) {
@@ -94,7 +94,7 @@ struct RawValueForCamelCasedCodableEnumRule: OptInRule {
}
private extension RawValueForCamelCasedCodableEnumRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
private let codableTypes = Set(["Codable", "Decodable", "Encodable"])
override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
@@ -69,22 +69,22 @@ struct RequiredDeinitRule: OptInRule {
}
private extension RequiredDeinitRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: ClassDeclSyntax) {
let visitor = DeinitVisitor(viewMode: .sourceAccurate)
let visitor = DeinitVisitor(configuration: configuration, file: file)
if !visitor.walk(tree: node.memberBlock, handler: \.hasDeinit) {
violations.append(node.classKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
}
private class DeinitVisitor: ViolationsSyntaxVisitor {
private(set) var hasDeinit = false
final class DeinitVisitor: ViolationsSyntaxVisitor<ConfigurationType> {
private(set) var hasDeinit = false
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: DeinitializerDeclSyntax) {
hasDeinit = true
override func visitPost(_ node: DeinitializerDeclSyntax) {
hasDeinit = true
}
}
}
@@ -67,7 +67,8 @@ import SwiftSyntax
/// case accountCreated
/// }
/// ````
struct RequiredEnumCaseRule: SwiftSyntaxRule, OptInRule {
@SwiftSyntaxRule
struct RequiredEnumCaseRule: OptInRule {
var configuration = RequiredEnumCaseConfiguration()
private static let exampleConfiguration = [
@@ -130,21 +131,10 @@ struct RequiredEnumCaseRule: SwiftSyntaxRule, OptInRule {
""", configuration: exampleConfiguration)
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension RequiredEnumCaseRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: RequiredEnumCaseConfiguration
init(configuration: RequiredEnumCaseConfiguration) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: EnumDeclSyntax) {
guard configuration.protocols.isNotEmpty else {
return
@@ -93,7 +93,7 @@ struct SelfInPropertyInitializationRule: Rule {
}
private extension SelfInPropertyInitializationRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: VariableDeclSyntax) {
guard !node.modifiers.contains(keyword: .lazy),
!node.modifiers.containsStaticOrClass,
@@ -37,7 +37,7 @@ struct StrongIBOutletRule: SwiftSyntaxCorrectableRule, OptInRule {
}
private extension StrongIBOutletRule {
final class Visitor: ViolationsSyntaxVisitor {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: VariableDeclSyntax) {
if let violationPosition = node.violationPosition {
violations.append(violationPosition)
@@ -1,8 +1,8 @@
import Foundation
import SwiftSyntax
struct TestCaseAccessibilityRule: SwiftSyntaxRule, OptInRule,
SubstitutionCorrectableRule {
@SwiftSyntaxRule
struct TestCaseAccessibilityRule: OptInRule, SubstitutionCorrectableRule {
var configuration = TestCaseAccessibilityConfiguration()
static let description = RuleDescription(
@@ -15,10 +15,6 @@ struct TestCaseAccessibilityRule: SwiftSyntaxRule, OptInRule,
corrections: TestCaseAccessibilityRuleExamples.corrections
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(allowedPrefixes: configuration.allowedPrefixes, testParentClasses: configuration.testParentClasses)
}
func violationRanges(in file: SwiftLintFile) -> [NSRange] {
makeVisitor(file: file)
.walk(tree: file.syntaxTree, handler: \.violations)
@@ -33,101 +29,84 @@ struct TestCaseAccessibilityRule: SwiftSyntaxRule, OptInRule,
}
private extension TestCaseAccessibilityRule {
final class Visitor: ViolationsSyntaxVisitor {
private let allowedPrefixes: Set<String>
private let testParentClasses: Set<String>
init(allowedPrefixes: Set<String>, testParentClasses: Set<String>) {
self.allowedPrefixes = allowedPrefixes
self.testParentClasses = testParentClasses
super.init(viewMode: .sourceAccurate)
}
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: ClassDeclSyntax) {
guard !testParentClasses.isDisjoint(with: node.inheritedTypes) else {
guard !configuration.testParentClasses.isDisjoint(with: node.inheritedTypes) else {
return
}
violations.append(
contentsOf: XCTestClassVisitor(allowedPrefixes: allowedPrefixes)
contentsOf: XCTestClassVisitor(configuration: configuration, file: file)
.walk(tree: node.memberBlock, handler: \.violations)
)
}
}
}
private final class XCTestClassVisitor: ViolationsSyntaxVisitor {
private let allowedPrefixes: Set<String>
final class XCTestClassVisitor: ViolationsSyntaxVisitor<ConfigurationType> {
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
init(allowedPrefixes: Set<String>) {
self.allowedPrefixes = allowedPrefixes
super.init(viewMode: .sourceAccurate)
}
override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: VariableDeclSyntax) {
guard !node.modifiers.containsPrivateOrFileprivate(),
!XCTestHelpers.isXCTestVariable(node) else {
return
}
for binding in node.bindings {
guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self),
case let name = pattern.identifier.text,
!allowedPrefixes.contains(where: name.hasPrefix) else {
continue
override func visitPost(_ node: VariableDeclSyntax) {
guard !node.modifiers.containsPrivateOrFileprivate(),
!XCTestHelpers.isXCTestVariable(node) else {
return
}
violations.append(node.bindingSpecifier.positionAfterSkippingLeadingTrivia)
return
}
}
for binding in node.bindings {
guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self),
case let name = pattern.identifier.text,
!configuration.allowedPrefixes.contains(where: name.hasPrefix) else {
continue
}
override func visitPost(_ node: FunctionDeclSyntax) {
guard hasViolation(modifiers: node.modifiers, identifierToken: node.name),
!XCTestHelpers.isXCTestFunction(node) else {
return
violations.append(node.bindingSpecifier.positionAfterSkippingLeadingTrivia)
return
}
}
violations.append(node.positionAfterSkippingLeadingTrivia)
}
override func visitPost(_ node: FunctionDeclSyntax) {
guard hasViolation(modifiers: node.modifiers, identifierToken: node.name),
!XCTestHelpers.isXCTestFunction(node) else {
return
}
override func visitPost(_ node: ClassDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.classKeyword.positionAfterSkippingLeadingTrivia)
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: EnumDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.enumKeyword.positionAfterSkippingLeadingTrivia)
override func visitPost(_ node: ClassDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.classKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
override func visitPost(_ node: StructDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.structKeyword.positionAfterSkippingLeadingTrivia)
override func visitPost(_ node: EnumDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.enumKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
override func visitPost(_ node: ActorDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.actorKeyword.positionAfterSkippingLeadingTrivia)
override func visitPost(_ node: StructDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.structKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
override func visitPost(_ node: TypeAliasDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.typealiasKeyword.positionAfterSkippingLeadingTrivia)
override func visitPost(_ node: ActorDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.actorKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
private func hasViolation(modifiers: DeclModifierListSyntax, identifierToken: TokenSyntax) -> Bool {
!modifiers.containsPrivateOrFileprivate()
&& !allowedPrefixes.contains(where: identifierToken.text.hasPrefix)
override func visitPost(_ node: TypeAliasDeclSyntax) {
if hasViolation(modifiers: node.modifiers, identifierToken: node.name) {
violations.append(node.typealiasKeyword.positionAfterSkippingLeadingTrivia)
}
}
private func hasViolation(modifiers: DeclModifierListSyntax, identifierToken: TokenSyntax) -> Bool {
!modifiers.containsPrivateOrFileprivate()
&& !configuration.allowedPrefixes.contains(where: identifierToken.text.hasPrefix)
}
}
}

Some files were not shown because too many files have changed in this diff Show More