From a84d9a9ed4334890ffe4ccc4214c57ac2365cc57 Mon Sep 17 00:00:00 2001 From: Phlippie Date: Fri, 8 Mar 2024 21:37:35 +0200 Subject: [PATCH 001/265] Add new `static_over_final_class` rule (#5487) --- .swiftlint.yml | 1 + CHANGELOG.md | 5 + .../Models/BuiltInRules.swift | 1 + .../Idiomatic/StaticOverFinalClassRule.swift | 112 ++++++++++++++++++ Tests/GeneratedTests/GeneratedTests.swift | 6 + 5 files changed, 125 insertions(+) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 211a408baa..0cf6fd23ee 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -46,6 +46,7 @@ disabled_rules: - redundant_self_in_closure - required_deinit - self_binding + - static_over_final_class - shorthand_argument - sorted_enum_cases - strict_fileprivate diff --git a/CHANGELOG.md b/CHANGELOG.md index d67fd76ba7..32c7178000 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,11 @@ * Make `trailing_closure` correctable. [KS1019](https://github.com/KS1019/) +* Add new `static_over_final_class` rule to prefer `static` over + `final class` declaration. + [phlippieb](https://github.com/phlippieb) + [#5471](https://github.com/realm/SwiftLint/issues/5471) + #### Bug Fixes * Silence `discarded_notification_center_observer` rule in closures. Furthermore, diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 59b7908a1a..3c1332980a 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -190,6 +190,7 @@ public let builtInRules: [any Rule.Type] = [ SortedImportsRule.self, StatementPositionRule.self, StaticOperatorRule.self, + StaticOverFinalClassRule.self, StrictFilePrivateRule.self, StrongIBOutletRule.self, SuperfluousElseRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift new file mode 100644 index 0000000000..7b501883d9 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift @@ -0,0 +1,112 @@ +import SwiftSyntax + +@SwiftSyntaxRule +struct StaticOverFinalClassRule: Rule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "static_over_final_class", + name: "Static Over Final Class", + description: "Prefer `static` over `final class` for non-overridable declarations", + kind: .idiomatic, + nonTriggeringExamples: [ + Example(""" + class C { + static func f() {} + } + """), + Example(""" + class C { + static var i: Int { 0 } + } + """), + Example(""" + class C { + static subscript(_: Int) -> Int { 0 } + } + """), + Example(""" + class C { + class func f() {} + } + """), + Example(""" + final class C {} + """), + Example(""" + final class C { + class D { + class func f() {} + } + } + """) + ], + triggeringExamples: [ + Example(""" + class C { + ↓final class func f() {} + } + """), + Example(""" + class C { + ↓final class var i: Int { 0 } + } + """), + Example(""" + class C { + ↓final class subscript(_: Int) -> Int { 0 } + } + """), + Example(""" + final class C { + ↓class func f() {} + } + """), + Example(""" + class C { + final class D { + ↓class func f() {} + } + } + """) + ] + ) +} + +private extension StaticOverFinalClassRule { + final class Visitor: ViolationsSyntaxVisitor { + private var classContexts = Stack() + + override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { + classContexts.push(node.modifiers.contains(keyword: .final)) + return .visitChildren + } + + override func visitPost(_ node: ClassDeclSyntax) { + classContexts.pop() + } + + override func visitPost(_ node: FunctionDeclSyntax) { + validateNode(at: node.positionAfterSkippingLeadingTrivia, with: node.modifiers) + } + + override func visitPost(_ node: VariableDeclSyntax) { + validateNode(at: node.positionAfterSkippingLeadingTrivia, with: node.modifiers) + } + + override func visitPost(_ node: SubscriptDeclSyntax) { + validateNode(at: node.positionAfterSkippingLeadingTrivia, with: node.modifiers) + } + + // MARK: - + private func validateNode(at position: AbsolutePosition, with modifiers: DeclModifierListSyntax) { + if modifiers.contains(keyword: .final), + modifiers.contains(keyword: .class) { + violations.append(position) + } else if modifiers.contains(keyword: .class), + classContexts.peek() == true { + violations.append(position) + } + } + } +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index c45701eda7..2da52685e7 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -1129,6 +1129,12 @@ class StaticOperatorRuleGeneratedTests: SwiftLintTestCase { } } +class StaticOverFinalClassRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(StaticOverFinalClassRule.description) + } +} + class StrictFilePrivateRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(StrictFilePrivateRule.description) From e0b6a54f6b6855fcb8741e7f4b8a7ba6f2759212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 8 Mar 2024 23:37:13 +0100 Subject: [PATCH 002/265] Support `private_over_fileprivate` rule for actors (#5490) --- CHANGELOG.md | 4 + .../PrivateOverFilePrivateRule.swift | 202 +++++------------- 2 files changed, 52 insertions(+), 154 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32c7178000..4c77608de1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -142,6 +142,10 @@ [SimplyDanny](https://github.com/SimplyDanny) [#4801](https://github.com/realm/SwiftLint/pull/4801) +* Support `private_over_fileprivate` rule for actors. + [SimplyDanny](https://github.com/SimplyDanny) + [#5489](https://github.com/realm/SwiftLint/pull/5489) + * Fix some false positives in `multiline_literal_brackets` rule that would happen when comments are present. [Marcelo Fabri](https://github.com/marcelofabri) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift index ebb812c631..b317c6bcfc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift @@ -1,7 +1,7 @@ import SwiftSyntax -@SwiftSyntaxRule(explicitRewriter: true) -struct PrivateOverFilePrivateRule: Rule { +@SwiftSyntaxRule +struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule { var configuration = PrivateOverFilePrivateConfiguration() static let description = RuleDescription( @@ -26,6 +26,11 @@ struct PrivateOverFilePrivateRule: Rule { } """), Example(""" + actor MyActor { + fileprivate let myInt = 4 + } + """), + Example(""" class MyClass { fileprivate(set) var myInt = 4 } @@ -44,190 +49,79 @@ struct PrivateOverFilePrivateRule: Rule { ↓fileprivate class MyClass { fileprivate(set) var myInt = 4 } + """), + Example(""" + ↓fileprivate actor MyActor { + fileprivate let myInt = 4 + } """) ], corrections: [ - Example("↓fileprivate enum MyEnum {}"): Example("private enum MyEnum {}"), + Example("↓fileprivate enum MyEnum {}"): + Example("private enum MyEnum {}"), Example("↓fileprivate enum MyEnum { fileprivate class A {} }"): Example("private enum MyEnum { fileprivate class A {} }"), - Example("↓fileprivate class MyClass {\nfileprivate(set) var myInt = 4\n}"): - Example("private class MyClass {\nfileprivate(set) var myInt = 4\n}") + Example("↓fileprivate class MyClass { fileprivate(set) var myInt = 4 }"): + Example("private class MyClass { fileprivate(set) var myInt = 4 }"), + Example("↓fileprivate actor MyActor { fileprivate(set) var myInt = 4 }"): + Example("private actor MyActor { fileprivate(set) var myInt = 4 }") ] ) } private extension PrivateOverFilePrivateRule { final class Visitor: ViolationsSyntaxVisitor { - override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { - if let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) - } - return .skipChildren - } - - override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { - if configuration.validateExtensions, let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) - } - return .skipChildren - } + override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all } - override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { - if let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) - } - return .skipChildren + override func visitPost(_ node: ActorDeclSyntax) { + visit(withModifier: node) } - override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { - if let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) - } - return .skipChildren + override func visitPost(_ node: ClassDeclSyntax) { + visit(withModifier: node) } - override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { - if let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) - } - return .skipChildren + override func visitPost(_ node: EnumDeclSyntax) { + visit(withModifier: node) } - override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { - if let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) + override func visitPost(_ node: ExtensionDeclSyntax) { + if configuration.validateExtensions { + visit(withModifier: node) } - return .skipChildren } - override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { - if let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) - } - return .skipChildren + override func visitPost(_ node: FunctionDeclSyntax) { + visit(withModifier: node) } - override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { - if let privateModifier = node.modifiers.fileprivateModifier { - violations.append(privateModifier.positionAfterSkippingLeadingTrivia) - } - return .skipChildren + override func visitPost(_ node: ProtocolDeclSyntax) { + visit(withModifier: node) } - } - final class Rewriter: ViolationsSyntaxRewriter { - // don't call super in any of the `visit` methods to avoid digging into the children - override func visit(_ node: ExtensionDeclSyntax) -> DeclSyntax { - guard configuration.validateExtensions, let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) - } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) + override func visitPost(_ node: StructDeclSyntax) { + visit(withModifier: node) } - override func visit(_ node: ClassDeclSyntax) -> DeclSyntax { - guard let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) - } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) + override func visitPost(_ node: TypeAliasDeclSyntax) { + visit(withModifier: node) } - override func visit(_ node: StructDeclSyntax) -> DeclSyntax { - guard let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) - } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) + override func visitPost(_ node: VariableDeclSyntax) { + visit(withModifier: node) } - override func visit(_ node: EnumDeclSyntax) -> DeclSyntax { - guard let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) - } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) - } - - override func visit(_ node: ProtocolDeclSyntax) -> DeclSyntax { - guard let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) - } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) - } - - override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax { - guard let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) - } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) - } - - override func visit(_ node: VariableDeclSyntax) -> DeclSyntax { - guard let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) - } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) - } - - override func visit(_ node: TypeAliasDeclSyntax) -> DeclSyntax { - guard let modifier = node.modifiers.fileprivateModifier, - let modifierIndex = node.modifiers.fileprivateModifierIndex else { - return DeclSyntax(node) + private func visit(withModifier node: some WithModifiersSyntax) { + if let modifier = node.modifiers.first(where: { $0.name.tokenKind == .keyword(.fileprivate) }) { + violations.append(modifier.positionAfterSkippingLeadingTrivia) + violationCorrections.append( + ViolationCorrection( + start: modifier.positionAfterSkippingLeadingTrivia, + end: modifier.endPositionBeforeTrailingTrivia, + replacement: "private" + ) + ) } - - correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia) - let newNode = node.with(\.modifiers, node.modifiers.replacing(fileprivateModifierIndex: modifierIndex)) - return DeclSyntax(newNode) } } } - -private extension DeclModifierListSyntax { - var fileprivateModifierIndex: DeclModifierListSyntax.Index? { - firstIndex(where: { $0.name.tokenKind == .keyword(.fileprivate) }) - } - - var fileprivateModifier: DeclModifierSyntax? { - fileprivateModifierIndex.flatMap { self[$0] } - } - - func replacing(fileprivateModifierIndex: DeclModifierListSyntax.Index) -> DeclModifierListSyntax { - let fileprivateModifier = self[fileprivateModifierIndex] - return with( - \.[fileprivateModifierIndex], - fileprivateModifier.with( - \.name, - .keyword( - .private, - leadingTrivia: fileprivateModifier.leadingTrivia, - trailingTrivia: fileprivateModifier.trailingTrivia - ) - ) - ) - } -} From a5818b906698d6700cfeaae7db937fadaf394553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 9 Mar 2024 14:34:07 +0100 Subject: [PATCH 003/265] Support Swift version 5.10.0 (#5491) --- Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift index 7a6a734808..8a1b566a96 100644 --- a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift +++ b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift @@ -5,6 +5,8 @@ final class SwiftVersionTests: SwiftLintTestCase { func testDetectSwiftVersion() { #if compiler(>=6.0.0) let version = "6.0.0" +#elseif compiler(>=5.10.0) + let version = "5.10.0" #elseif compiler(>=5.9.2) let version = "5.9.2" #elseif compiler(>=5.9.1) From ed0241abf45b12ff5b9bc06f3dae8c1391dffc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 9 Mar 2024 14:50:42 +0100 Subject: [PATCH 004/265] Move @preconcurrency attribute to script (#5492) --- .../Rules/Lint/UnusedClosureParameterRule.swift | 2 +- tools/add-preconcurrency-imports.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRule.swift index 14f1f19332..fb4f701a68 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRule.swift @@ -1,4 +1,4 @@ -@preconcurrency import SwiftSyntax +import SwiftSyntax import SwiftSyntaxBuilder @SwiftSyntaxRule(explicitRewriter: true) diff --git a/tools/add-preconcurrency-imports.sh b/tools/add-preconcurrency-imports.sh index acef5af261..e65de3a03c 100755 --- a/tools/add-preconcurrency-imports.sh +++ b/tools/add-preconcurrency-imports.sh @@ -3,6 +3,7 @@ files=( "Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift" "Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift" +"Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRule.swift" "Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift" "Source/SwiftLintBuiltInRules/Rules/Style/OptionalEnumCaseMatchingRule.swift" "Source/SwiftLintBuiltInRules/Rules/Style/TrailingCommaRule.swift" From 5bfe329d09c6816fcc490899c38a83a55aafa2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 9 Mar 2024 21:46:45 +0100 Subject: [PATCH 005/265] Update SwiftSyntax to version 510.0.0 (#5479) --- MODULE.bazel | 2 +- Package.resolved | 4 +-- Package.swift | 2 +- .../Rules/Idiomatic/NimbleOperatorRule.swift | 8 +++--- .../Lint/UnusedControlFlowLabelRule.swift | 4 +-- .../Rules/Lint/ValidIBInspectableRule.swift | 2 +- .../Rules/Performance/EmptyCountRule.swift | 4 +-- .../Rules/Style/SuperfluousElseRule.swift | 2 +- .../DeclaredIdentifiersTrackingVisitor.swift | 28 +++++++++++++------ 9 files changed, 33 insertions(+), 23 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index d38d2cd08e..d9b455aaff 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,7 +11,7 @@ bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "rules_apple", version = "3.1.1", repo_name = "build_bazel_rules_apple") bazel_dep(name = "rules_swift", version = "1.16.0", repo_name = "build_bazel_rules_swift") bazel_dep(name = "sourcekitten", version = "0.34.1", repo_name = "com_github_jpsim_sourcekitten") -bazel_dep(name = "swift-syntax", version = "509.1.1", repo_name = "SwiftSyntax") +bazel_dep(name = "swift-syntax", version = "510.0.0", repo_name = "SwiftSyntax") bazel_dep(name = "swift_argument_parser", version = "1.2.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") bazel_dep(name = "yams", version = "5.0.6", repo_name = "sourcekitten_com_github_jpsim_yams") diff --git a/Package.resolved b/Package.resolved index 8c2cf35951..84a5b28ce4 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", - "version" : "509.1.1" + "revision" : "08a2f0a9a30e0f705f79c9cfaca1f68b71bdc775", + "version" : "510.0.0" } }, { diff --git a/Package.swift b/Package.swift index 9f18539861..c635b893ef 100644 --- a/Package.swift +++ b/Package.swift @@ -23,7 +23,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.1")), - .package(url: "https://github.com/apple/swift-syntax.git", exact: "509.1.1"), + .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.0"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.34.1")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift index 884ab0011d..59950d7f02 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift @@ -92,10 +92,10 @@ private extension NimbleOperatorRule { correctionPositions.append(node.positionAfterSkippingLeadingTrivia) let elements = ExprListSyntax([ - expectation.baseExpr.with(\.trailingTrivia, .space).cast(ExprSyntax.self), - operatorExpr.with(\.trailingTrivia, .space).cast(ExprSyntax.self), + expectation.baseExpr.with(\.trailingTrivia, .space), + operatorExpr.with(\.trailingTrivia, .space), expectedValueExpr.with(\.trailingTrivia, node.trailingTrivia) - ]) + ].map(ExprSyntax.init)) return super.visit(SequenceExprSyntax(elements: elements)) } } @@ -174,7 +174,7 @@ private struct Expectation { case .withArguments: expected case .nullary(let analogueValue): - analogueValue.cast(ExprSyntax.self) + ExprSyntax(analogueValue) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift index 681c98f27a..76284d83df 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift @@ -99,10 +99,8 @@ private extension UnusedControlFlowLabelRule { guard let violationPosition = node.violationPosition else { return super.visit(node) } - - let newNode = node.statement.with(\.leadingTrivia, node.leadingTrivia) correctionPositions.append(violationPosition) - return visit(newNode).as(StmtSyntax.self) ?? newNode + return visit(node.statement.with(\.leadingTrivia, node.leadingTrivia)) } } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift index 7ded48d717..47ff7bf31f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift @@ -186,7 +186,7 @@ private extension VariableDeclSyntax { } return bindings.allSatisfy { binding in - guard let accessorBlock = binding.accessorBlock?.as(AccessorBlockSyntax.self) else { + guard let accessorBlock = binding.accessorBlock else { return true } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift index c5293d75cf..477c1a40d8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift @@ -88,9 +88,9 @@ private extension EmptyCountRule { if let (count, position) = node.countNodeAndPosition(onlyAfterDot: configuration.onlyAfterDot) { let newNode = if let count = count.as(MemberAccessExprSyntax.self) { - count.with(\.declName.baseName, "isEmpty").trimmed.as(ExprSyntax.self) + ExprSyntax(count.with(\.declName.baseName, "isEmpty").trimmed) } else { - count.as(DeclReferenceExprSyntax.self)?.with(\.baseName, "isEmpty").trimmed.as(ExprSyntax.self) + ExprSyntax(count.as(DeclReferenceExprSyntax.self)?.with(\.baseName, "isEmpty").trimmed) } guard let newNode else { return super.visit(node) } correctionPositions.append(position) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift index 08b79c7d0f..cd257ae235 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift @@ -350,7 +350,7 @@ private extension IfExprSyntax { } private func lastStatementExitsScope(in block: CodeBlockSyntax) -> Bool { - guard let lastItem = block.statements.last?.as(CodeBlockItemSyntax.self)?.item else { + guard let lastItem = block.statements.last?.item else { return false } if [.returnStmt, .throwStmt, .continueStmt, .breakStmt].contains(lastItem.kind) { diff --git a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift index fe8caeb582..8c47c1f9bf 100644 --- a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift +++ b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift @@ -3,7 +3,7 @@ import SwiftSyntax /// A specialized `ViolationsSyntaxVisitor` that tracks declared identifiers per scope while traversing the AST. open class DeclaredIdentifiersTrackingVisitor: ViolationsSyntaxVisitor { - /// A type that remembers the declared identifers (in order) up to the current position in the code. + /// A type that remembers the declared identifiers (in order) up to the current position in the code. public typealias Scope = Stack> /// The hierarchical stack of identifiers declared up to the current position in the code. @@ -14,7 +14,7 @@ open class DeclaredIdentifiersTrackingVisitor: /// - Parameters: /// - configuration: Configuration of a rule. /// - file: File from which the syntax tree stems from. - /// - scope: A (potentially already pre-filled) scope to collect identifers into. + /// - scope: A (potentially already pre-filled) scope to collect identifiers into. @inlinable public init(configuration: Configuration, file: SwiftLintFile, scope: Scope = Scope()) { self.scope = scope @@ -82,13 +82,25 @@ open class DeclaredIdentifiersTrackingVisitor: private func collectIdentifiers(from switchCase: SwitchCaseLabelSyntax) { switchCase.caseItems - .compactMap { $0.pattern.as(ValueBindingPatternSyntax.self)?.pattern ?? $0.pattern } - .compactMap { $0.as(ExpressionPatternSyntax.self)?.expression.asFunctionCall } - .compactMap { $0.arguments.as(LabeledExprListSyntax.self) } + .map { item -> PatternSyntax in + item.pattern.as(ValueBindingPatternSyntax.self)?.pattern ?? item.pattern + } + .compactMap { pattern -> FunctionCallExprSyntax? in + pattern.as(ExpressionPatternSyntax.self)?.expression.asFunctionCall + } + .map { call -> LabeledExprListSyntax in + call.arguments + } .flatMap { $0 } - .compactMap { $0.expression.as(PatternExprSyntax.self) } - .compactMap { $0.pattern.as(ValueBindingPatternSyntax.self)?.pattern ?? $0.pattern } - .compactMap { $0.as(IdentifierPatternSyntax.self) } + .compactMap { labeledExpr -> PatternExprSyntax? in + labeledExpr.expression.as(PatternExprSyntax.self) + } + .map { patternExpr -> any PatternSyntaxProtocol in + patternExpr.pattern.as(ValueBindingPatternSyntax.self)?.pattern ?? patternExpr.pattern + } + .compactMap { pattern -> IdentifierPatternSyntax? in + pattern.as(IdentifierPatternSyntax.self) + } .forEach { scope.addToCurrentScope($0.identifier.text) } } From c32d5028cdbdc738d53130b258174599f3f43717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 11 Mar 2024 20:14:10 +0100 Subject: [PATCH 006/265] Warn when `--fix` comes together with `--strict` or `--lenient` (#5493) --- CHANGELOG.md | 5 +++++ Source/swiftlint/Commands/Lint.swift | 22 +++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c77608de1..8b454241dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#70](https://github.com/realm/SwiftLint/issues/70) +* Warn when `--fix` comes together with `--strict` or `--lenient` as only `--fix` + takes effect then. + [SimplyDanny](https://github.com/SimplyDanny) + [#5387](https://github.com/realm/SwiftLint/pull/5387) + * Add new `one_declaration_per_file` rule that allows only a single class/struct/enum/protocol declaration per file. Extensions are an exception; more than one is allowed. diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index b6f39fd33e..7a26830b91 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -27,18 +27,26 @@ extension SwiftLint { func run() async throws { Issue.printDeprecationWarnings = !silenceDeprecationWarnings - let allPaths: [String] - if let path { + if path != nil { // TODO: [06/14/2024] Remove deprecation warning after ~2 years. Issue.genericWarning( "The --path option is deprecated. Pass the path(s) to lint last to the swiftlint command." ).print() - allPaths = [path] + paths - } else if !paths.isEmpty { - allPaths = paths - } else { - allPaths = [""] // Lint files in current working directory if no paths were specified. } + + if common.fix, let leniency = common.leniency { + Issue.genericWarning("The option --\(leniency) has no effect together with --fix.").print() + } + + let allPaths = + if let path { + [path] + paths + } else if !paths.isEmpty { + paths + } else { + [""] // Lint files in current working directory if no paths were specified. + } + let options = LintOrAnalyzeOptions( mode: .lint, paths: allPaths, From bedf211c434c421298d6dc963a5370588b5b111c Mon Sep 17 00:00:00 2001 From: Oleg Kohtenko Date: Sat, 16 Mar 2024 10:29:42 -0400 Subject: [PATCH 007/265] Ignore absence of child or parent config instead of falling back to default (#5407) --- CHANGELOG.md | 4 +++ .../Extensions/Configuration+FileGraph.swift | 34 ++++++++++++++++--- .../Configuration+FileGraphSubtypes.swift | 6 ++-- Source/SwiftLintCore/Models/Issue.swift | 5 +++ .../ChildConfig/Test1/Main/main.yml | 1 + 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b454241dc..06a6f657bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ #### Enhancements +* Ignore absence of a non-initial local config instead of + falling back to default. + [kohtenko](https://github.com/kohtenko) + * Add new option `ignore_typealiases_and_associatedtypes` to `nesting` rule. It excludes `typealias` and `associatedtype` declarations from the analysis. diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift index 09ae4f30b3..6193feca49 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift @@ -88,18 +88,44 @@ package extension Configuration { ) if !ignoreParentAndChildConfigs { - try processPossibleReference( + try processPossibleReferenceIgnoringFileAbsence( ofType: .childConfig, from: vertex, remoteConfigTimeoutOverride: remoteConfigTimeoutOverride, - remoteConfigTimeoutIfCachedOverride: remoteConfigTimeoutIfCachedOverride - ) - try processPossibleReference( + remoteConfigTimeoutIfCachedOverride: remoteConfigTimeoutIfCachedOverride) + + try processPossibleReferenceIgnoringFileAbsence( ofType: .parentConfig, from: vertex, remoteConfigTimeoutOverride: remoteConfigTimeoutOverride, + remoteConfigTimeoutIfCachedOverride: remoteConfigTimeoutIfCachedOverride) + } + } + + private mutating func processPossibleReferenceIgnoringFileAbsence( + ofType type: EdgeType, + from vertex: Vertex, + remoteConfigTimeoutOverride: TimeInterval?, + remoteConfigTimeoutIfCachedOverride: TimeInterval? + ) throws { + do { + try processPossibleReference( + ofType: type, + from: vertex, + remoteConfigTimeoutOverride: remoteConfigTimeoutOverride, remoteConfigTimeoutIfCachedOverride: remoteConfigTimeoutIfCachedOverride ) + } catch { + // If a child or parent config file doesn't exist, do not fail the rest of the config tree. + // Instead, just ignore this leaf of the config. Otherwise, rethrow the error. + guard case let Issue.fileNotFound(path) = error else { + throw error + } + queuedPrintError(""" + A local configuration at \(path) was not found. \ + Ignoring this part of the configuration. + """ + ) } } diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift index 9af6186879..8fb43be37d 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift @@ -72,9 +72,9 @@ internal extension Configuration.FileGraph { private func read(at path: String) throws -> String { guard !path.isEmpty && FileManager.default.fileExists(atPath: path) else { - throw isInitialVertex ? - Issue.initialFileNotFound(path: path) : - Issue.genericWarning("File \(path) can't be found.") + throw isInitialVertex + ? Issue.initialFileNotFound(path: path) + : Issue.fileNotFound(path: path) } return try String(contentsOfFile: path, encoding: .utf8) diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index b26ea6bc75..77c5bcf33f 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -32,6 +32,9 @@ public enum Issue: LocalizedError, Equatable { /// The initial configuration file was not found. case initialFileNotFound(path: String) + /// A file at specified path was not found. + case fileNotFound(path: String) + /// The file at `path` is not readable or cannot be opened. case fileNotReadable(path: String?, ruleID: String) @@ -125,6 +128,8 @@ public enum Issue: LocalizedError, Equatable { return "Cannot get cursor info from file at path '\(path ?? "...")' within '\(id)' rule." case let .yamlParsing(message): return "Cannot parse YAML file: \(message)" + case let .fileNotFound(path): + return "File at path '\(path)' not found." } } } diff --git a/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/main.yml b/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/main.yml index 6dbadd2528..86193fdbf8 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/main.yml +++ b/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/ChildConfig/Test1/Main/main.yml @@ -9,3 +9,4 @@ excluded: line_length: 80 child_config: child1.yml +parent_config: nonExistingParent.yml From 6398c3b8077a5ea8c93ca9f7a1aab3980736519e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 17 Mar 2024 20:26:15 +0100 Subject: [PATCH 008/265] Shift selection of default reporter (#5499) --- Source/SwiftLintCore/Models/Configuration.swift | 8 ++++---- Source/SwiftLintCore/Protocols/Reporter.swift | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 2a06b66813..1ee5344b70 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -27,7 +27,7 @@ public struct Configuration { public let warningThreshold: Int? /// The identifier for the `Reporter` to use to report style violations. - public let reporter: String + public let reporter: String? /// The location of the persisted cache to use with this configuration. public let cachePath: String? @@ -70,7 +70,7 @@ public struct Configuration { excludedPaths: [String], indentation: IndentationStyle, warningThreshold: Int?, - reporter: String, + reporter: String?, cachePath: String?, allowZeroLintableFiles: Bool, strict: Bool @@ -160,7 +160,7 @@ public struct Configuration { excludedPaths: excludedPaths, indentation: indentation, warningThreshold: warningThreshold, - reporter: reporter ?? XcodeReporter.identifier, + reporter: reporter, cachePath: cachePath, allowZeroLintableFiles: allowZeroLintableFiles, strict: strict @@ -298,7 +298,7 @@ extension Configuration: CustomStringConvertible { + "- Excluded Paths: \(excludedPaths)\n" + "- Warning Threshold: \(warningThreshold as Optional)\n" + "- Root Directory: \(rootDirectory as Optional)\n" - + "- Reporter: \(reporter)\n" + + "- Reporter: \(reporter ?? "default")\n" + "- Cache Path: \(cachePath as Optional)\n" + "- Computed Cache Description: \(computedCacheDescription as Optional)\n" + "- Rules: \(rules.map { type(of: $0).description.identifier })" diff --git a/Source/SwiftLintCore/Protocols/Reporter.swift b/Source/SwiftLintCore/Protocols/Reporter.swift index 8244fed412..18667c9d65 100644 --- a/Source/SwiftLintCore/Protocols/Reporter.swift +++ b/Source/SwiftLintCore/Protocols/Reporter.swift @@ -32,7 +32,10 @@ extension Reporter { /// - parameter identifier: The identifier corresponding to the reporter. /// /// - returns: The reporter type. -public func reporterFrom(identifier: String) -> any Reporter.Type { +public func reporterFrom(identifier: String?) -> any Reporter.Type { + guard let identifier else { + return XcodeReporter.self + } guard let reporter = reportersList.first(where: { $0.identifier == identifier }) else { queuedFatalError("No reporter with identifier '\(identifier)' available.") } From 9259698eef930ead6745c490f2831b168006c2c7 Mon Sep 17 00:00:00 2001 From: Matt Thompson <32947659+mt00chikin@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:58:45 -0500 Subject: [PATCH 009/265] Make `private_swiftui_state` rule correctable (#5447) --- CHANGELOG.md | 3 + .../PrivateSwiftUIStatePropertyRule.swift | 315 +++++++----------- ...vateSwiftUIStatePropertyRuleExamples.swift | 270 +++++++++++++++ 3 files changed, 394 insertions(+), 194 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 06a6f657bd..639b976462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,9 @@ * Make `empty_count` auto-correctable. [KS1019](https://github.com/KS1019/) + +* Make `private_swiftui_state` auto-correctable. + [mt00chikin](https://github.com/mt00chikin) * Make `trailing_closure` correctable. [KS1019](https://github.com/KS1019/) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift index 1c98aacecd..2bba7313a4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift @@ -10,7 +10,7 @@ import SwiftSyntax /// /// Declare state and state objects as private to prevent setting them from a memberwise initializer, /// which can conflict with the storage management that SwiftUI provides: -@SwiftSyntaxRule +@SwiftSyntaxRule(explicitRewriter: true) struct PrivateSwiftUIStatePropertyRule: OptInRule { var configuration = SeverityConfiguration(.warning) @@ -19,179 +19,9 @@ struct PrivateSwiftUIStatePropertyRule: OptInRule { name: "Private SwiftUI State Properties", description: "SwiftUI state properties should be private", kind: .lint, - nonTriggeringExamples: [ - Example(""" - struct MyApp: App { - @State private var isPlaying: Bool = false - } - """), - Example(""" - struct MyScene: Scene { - @State private var isPlaying: Bool = false - } - """), - Example(""" - struct ContentView: View { - @State private var isPlaying: Bool = false - } - """), - Example(""" - struct ContentView: View { - @State fileprivate var isPlaying: Bool = false - } - """), - Example(""" - struct ContentView: View { - @State private var isPlaying: Bool = false - - struct InnerView: View { - @State private var showsIndicator: Bool = false - } - } - """), - Example(""" - struct MyStruct { - struct ContentView: View { - @State private var isPlaying: Bool = false - } - } - """), - Example(""" - struct MyStruct { - struct ContentView: View { - @State private var isPlaying: Bool = false - } - - @State var nonTriggeringState: Bool = false - } - """), - - Example(""" - struct ContentView: View { - var isPlaying = false - } - """), - Example(""" - struct MyApp: App { - @StateObject private var model = DataModel() - } - """), - Example(""" - struct MyScene: Scene { - @StateObject private var model = DataModel() - } - """), - Example(""" - struct ContentView: View { - @StateObject private var model = DataModel() - } - """), - Example(""" - struct MyStruct { - struct ContentView: View { - @StateObject private var dataModel = DataModel() - } - - @StateObject var nonTriggeringObject = MyModel() - } - """), - Example(""" - struct Foo { - @State var bar = false - } - """), - Example(""" - class Foo: ObservableObject { - @State var bar = Bar() - } - """), - Example(""" - extension MyObject { - struct ContentView: View { - @State private var isPlaying: Bool = false - } - } - """), - Example(""" - actor ContentView: View { - @State private var isPlaying: Bool = false - } - """) - ], - triggeringExamples: [ - Example(""" - struct MyApp: App { - @State ↓var isPlaying: Bool = false - } - """), - Example(""" - struct MyScene: Scene { - @State ↓var isPlaying: Bool = false - } - """), - Example(""" - struct ContentView: View { - @State ↓var isPlaying: Bool = false - } - """), - Example(""" - struct ContentView: View { - struct InnerView: View { - @State private var showsIndicator: Bool = false - } - - @State ↓var isPlaying: Bool = false - } - """), - Example(""" - struct MyStruct { - struct ContentView: View { - @State ↓var isPlaying: Bool = false - } - } - """), - Example(""" - struct MyStruct { - struct ContentView: View { - @State ↓var isPlaying: Bool = false - } - - @State var isPlaying: Bool = false - } - """), - Example(""" - final class ContentView: View { - @State ↓var isPlaying: Bool = false - } - """), - Example(""" - extension MyObject { - struct ContentView: View { - @State ↓var isPlaying: Bool = false - } - } - """), - Example(""" - actor ContentView: View { - @State ↓var isPlaying: Bool = false - } - """), - Example(""" - struct MyApp: App { - @StateObject ↓var model = DataModel() - } - """), - Example(""" - struct MyScene: Scene { - @StateObject ↓var model = DataModel() - } - """), - Example(""" - struct ContentView: View { - @StateObject ↓var model = DataModel() - } - """) - ] + nonTriggeringExamples: PrivateSwiftUIStatePropertyRuleExamples.nonTriggeringExamples, + triggeringExamples: PrivateSwiftUIStatePropertyRuleExamples.triggeringExamples, + corrections: PrivateSwiftUIStatePropertyRuleExamples.corrections ) } @@ -201,59 +31,156 @@ private extension PrivateSwiftUIStatePropertyRule { [ProtocolDeclSyntax.self] } - /// LIFO stack that stores type inheritance clauses for each visited node - /// The last value is the inheritance clause for the most recently visited node - /// A nil value indicates that the node does not provide any inheritance clause - private var visitedTypeInheritances = Stack() + /// LIFO stack that stores if a type conforms to SwiftUI protocols. + /// `true` indicates that SwiftUI state properties should be + /// checked in the scope of the last entered declaration. + private var swiftUITypeScopes = Stack() override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { - visitedTypeInheritances.push(node.inheritanceClause) + swiftUITypeScopes.push(node.inheritanceClause.conformsToApplicableSwiftUIProtocol) return .visitChildren } override func visitPost(_ node: ClassDeclSyntax) { - visitedTypeInheritances.pop() + swiftUITypeScopes.pop() } override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { - visitedTypeInheritances.push(node.inheritanceClause) + swiftUITypeScopes.push(node.inheritanceClause.conformsToApplicableSwiftUIProtocol) return .visitChildren } override func visitPost(_ node: StructDeclSyntax) { - visitedTypeInheritances.pop() + swiftUITypeScopes.pop() } override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind { - visitedTypeInheritances.push(node.inheritanceClause) + swiftUITypeScopes.push(node.inheritanceClause.conformsToApplicableSwiftUIProtocol) return .visitChildren } override func visitPost(_ node: ActorDeclSyntax) { - visitedTypeInheritances.pop() + swiftUITypeScopes.pop() } - override func visitPost(_ node: MemberBlockItemSyntax) { - guard - let decl = node.decl.as(VariableDeclSyntax.self), - let inheritanceClause = visitedTypeInheritances.peek() as? InheritanceClauseSyntax, - inheritanceClause.conformsToApplicableSwiftUIProtocol, - decl.attributes.hasStateAttribute, - !decl.modifiers.containsPrivateOrFileprivate() + override func visitPost(_ node: VariableDeclSyntax) { + guard node.parent?.is(MemberBlockItemSyntax.self) == true, + swiftUITypeScopes.peek() ?? false, + node.containsSwiftUIStateAccessLevelViolation else { return } - violations.append(decl.bindingSpecifier.positionAfterSkippingLeadingTrivia) + if let firstAccessLevelModifier = node.modifiers.accessLevelModifier { + violations.append(firstAccessLevelModifier.positionAfterSkippingLeadingTrivia) + } else { + violations.append(node.bindingSpecifier.positionAfterSkippingLeadingTrivia) + } + } + } + + final class Rewriter: ViolationsSyntaxRewriter { + /// LIFO stack that stores if a type conforms to SwiftUI protocols. + /// `true` indicates that SwiftUI state properties should be + /// checked in the scope of the last entered declaration. + private var swiftUITypeScopes = Stack() + + override func visit(_ node: ClassDeclSyntax) -> DeclSyntax { + swiftUITypeScopes.push(node.inheritanceClause.conformsToApplicableSwiftUIProtocol) + return super.visit(node) + } + + override func visit(_ node: StructDeclSyntax) -> DeclSyntax { + swiftUITypeScopes.push(node.inheritanceClause.conformsToApplicableSwiftUIProtocol) + return super.visit(node) } + + override func visit(_ node: ActorDeclSyntax) -> DeclSyntax { + swiftUITypeScopes.push(node.inheritanceClause.conformsToApplicableSwiftUIProtocol) + return super.visit(node) + } + + override func visitPost(_ node: Syntax) { + if node.is(ClassDeclSyntax.self) || + node.is(StructDeclSyntax.self) || + node.is(ActorDeclSyntax.self) { + swiftUITypeScopes.pop() + } + } + + override func visit(_ node: VariableDeclSyntax) -> DeclSyntax { + guard + node.parent?.is(MemberBlockItemSyntax.self) == true, + swiftUITypeScopes.peek() ?? false, + node.containsSwiftUIStateAccessLevelViolation + else { + return DeclSyntax(node) + } + + correctionPositions.append(node.bindingSpecifier.positionAfterSkippingLeadingTrivia) + + // If there are no modifiers present on the current syntax node, + // then we should retain the binding specifier's leading trivia + // by appending it to our inserted private access level modifier + if node.modifiers.isEmpty { + // Extract the leading trivia from the binding specifier and apply it to the private modifier + let privateModifier = DeclModifierSyntax( + leadingTrivia: node.bindingSpecifier.leadingTrivia, + name: .keyword(.private), + trailingTrivia: .space + ) + + let bindingSpecifier = node.bindingSpecifier.with(\.leadingTrivia, []) + let newNode = node + .with(\.modifiers, [privateModifier]) + .with(\.bindingSpecifier, bindingSpecifier) + return DeclSyntax(newNode) + } + + // If any existing, violating access modifiers are present + // then we should extract their trivia and + // append it to the inserted private access level modifier + let existingAccessLevelModifiers = node.modifiers.filter { $0.asAccessLevelModifier != nil } + // Remove any existing access control modifiers, but preserve any of their leading and trailing trivia + // Existing trivia will be appended to the rewritten access modifier + let previousAccessModifierLeadingTrivia = existingAccessLevelModifiers + .map(\.leadingTrivia) + .reduce(Trivia(pieces: [])) { partialResult, trivia in + partialResult.merging(trivia) + } + + let previousAccessModifierTrailingTrivia = existingAccessLevelModifiers + .map(\.trailingTrivia) + .reduce(Trivia(pieces: [])) { partialResult, trivia in + partialResult.merging(trivia) + } + + let filteredModifiers = node.modifiers.filter { $0.asAccessLevelModifier == nil } + // Extract the leading trivia from the binding specifier and apply it to the private modifier + let privateModifier = DeclModifierSyntax( + leadingTrivia: previousAccessModifierLeadingTrivia, + name: .keyword(.private), + trailingTrivia: previousAccessModifierTrailingTrivia.merging(.space) + ) + + return DeclSyntax( + node.with(\.modifiers, [privateModifier] + filteredModifiers) + ) + } + } +} + +private extension VariableDeclSyntax { + var containsSwiftUIStateAccessLevelViolation: Bool { + attributes.hasStateAttribute && !modifiers.containsPrivateOrFileprivate() } } -private extension InheritanceClauseSyntax { +private extension InheritanceClauseSyntax? { static let applicableSwiftUIProtocols: Set = ["View", "App", "Scene"] var conformsToApplicableSwiftUIProtocol: Bool { - inheritedTypes.containsInheritedType(inheritedTypes: Self.applicableSwiftUIProtocols) + self?.inheritedTypes.containsInheritedType(inheritedTypes: Self.applicableSwiftUIProtocols) ?? false } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift new file mode 100644 index 0000000000..2f8321a704 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift @@ -0,0 +1,270 @@ +internal struct PrivateSwiftUIStatePropertyRuleExamples { + static let nonTriggeringExamples: [Example] = [ + Example(""" + struct MyApp: App { + @State private var isPlaying: Bool = false + } + """), + Example(""" + struct MyScene: Scene { + @State private var isPlaying: Bool = false + } + """), + Example(""" + struct CofntentView: View { + @State private var isPlaying: Bool = false + } + """), + Example(""" + struct ContentView: View { + @State private var isPlaying: Bool = false + + struct InnerView: View { + @State private var showsIndicator: Bool = false + } + } + """), + Example(""" + struct MyStruct { + struct ContentView: View { + @State private var isPlaying: Bool = false + } + } + """), + Example(""" + struct MyStruct { + struct ContentView: View { + @State private var isPlaying: Bool = false + } + + @State var nonTriggeringState: Bool = false + } + """), + Example(""" + struct ContentView: View { + var s: Int { + @State + var s: Int = 3 + return s + } + + var body: some View { Text("") } + } + """), + Example(""" + struct ContentView: View { + var isPlaying = false + } + """), + Example(""" + struct MyApp: App { + @StateObject private var model = DataModel() + } + """), + Example(""" + struct MyScene: Scene { + @StateObject private var model = DataModel() + } + """), + Example(""" + struct ContentView: View { + @StateObject private var model = DataModel() + } + """), + Example(""" + struct MyStruct { + struct ContentView: View { + @StateObject private var dataModel = DataModel() + } + + @StateObject var nonTriggeringObject = MyModel() + } + """), + Example(""" + struct Foo { + @State var bar = false + } + """), + Example(""" + class Foo: ObservableObject { + @State var bar = Bar() + } + """), + Example(""" + extension MyObject { + struct ContentView: View { + @State private var isPlaying: Bool = false + } + } + """), + Example(""" + actor ContentView: View { + @State private var isPlaying: Bool = false + } + """) + ] + + static let triggeringExamples: [Example] = [ + Example(""" + struct MyApp: App { + @State ↓var isPlaying: Bool = false + } + """), + Example(""" + struct MyScene: Scene { + @State ↓public var isPlaying: Bool = false + } + """), + Example(""" + struct ContentView: View { + @State ↓var isPlaying: Bool = false + } + """), + Example(""" + struct ContentView: View { + struct InnerView: View { + @State private var showsIndicator: Bool = false + } + + @State ↓var isPlaying: Bool = false + } + """), + Example(""" + struct MyStruct { + struct ContentView: View { + @State ↓var isPlaying: Bool = false + } + } + """), + Example(""" + struct MyStruct { + struct ContentView: View { + @State ↓var isPlaying: Bool = false + } + + @State var isPlaying: Bool = false + } + """), + Example(""" + final class ContentView: View { + @State ↓var isPlaying: Bool = false + } + """), + Example(""" + extension MyObject { + struct ContentView: View { + @State ↓var isPlaying: Bool = false + } + } + """), + Example(""" + actor ContentView: View { + @State ↓var isPlaying: Bool = false + } + """), + Example(""" + struct MyApp: App { + @StateObject ↓var model = DataModel() + } + """), + Example(""" + struct MyScene: Scene { + @StateObject ↓var model = DataModel() + } + """), + Example(""" + struct ContentView: View { + @StateObject ↓var model = DataModel() + } + """), + Example(""" + struct ContentView: View { + @State ↓private(set) var isPlaying = false + """), + Example(""" + struct ContentView: View { + @State ↓fileprivate(set) public var isPlaying = false + """) + ] + + static let corrections: [Example: Example] = [ + Example(""" + struct ContentView: View { + @State ↓var isPlaying: Bool = false + } + """): Example(""" + struct ContentView: View { + @State private var isPlaying: Bool = false + } + """), + Example(""" + struct ContentView: View { + @State public ↓var isPlaying: Bool = false + } + """): Example(""" + struct ContentView: View { + @State private var isPlaying: Bool = false + } + """), + Example(""" + struct ContentView: View { + @State private(set) ↓var isPlaying: Bool = false + } + """): Example(""" + struct ContentView: View { + @State private var isPlaying: Bool = false + } + """), + Example(""" + struct ContentView: View { + @State + /// This will track if the content is currently playing + private(set) + // This is another comment about this property + public ↓var isPlaying: Bool = false + } + """): Example(""" + struct ContentView: View { + @State + /// This will track if the content is currently playing + // This is another comment about this property + private var isPlaying: Bool = false + } + """), + Example(""" + struct MyApp: App { + @State + /// This will track if the content is currently playing + ↓var isPlaying: Bool = false + } + """): Example(""" + struct MyApp: App { + @State + /// This will track if the content is currently playing + private var isPlaying: Bool = false + } + """), + Example(""" + struct MyScene: Scene { + @State /* This is a comment */ ↓var isPlaying: Bool = false + } + """): Example(""" + struct MyScene: Scene { + @State /* This is a comment */ private var isPlaying: Bool = false + } + """), + Example(""" + struct ContentView: View { + @State + /// This will track if the content is currently playing + ↓var isPlaying: Bool = false + } + """): Example(""" + struct ContentView: View { + @State + /// This will track if the content is currently playing + private var isPlaying: Bool = false + } + """) + ] +} From e66d0a3a8b2f7a671a71af963d18f3f8510b4961 Mon Sep 17 00:00:00 2001 From: "Garric G. Nahapetian" Date: Mon, 18 Mar 2024 12:59:50 -0700 Subject: [PATCH 010/265] =?UTF-8?q?Move=20=E2=80=9CRewrite=20SwiftLintPlug?= =?UTF-8?q?in=E2=80=9D=20to=20Breaking=20section=20(#5500)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 639b976462..f72dca954e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ #### Breaking -* None. +* Rewrite `SwiftLintPlugin` using `BUILD_WORKSPACE_DIRECTORY` without relying + on the `--config` option. + [Garric Nahapetian](https://github.com/garricn) #### Experimental @@ -862,10 +864,6 @@ * Catch more valid `no_magic_numbers` violations. [JP Simard](https://github.com/jpsim) -* Rewrite `SwiftLintPlugin` using `BUILD_WORKSPACE_DIRECTORY` without relying - on the `--config` option. - [Garric Nahapetian](https://github.com/garricn) - * Add `blanket_disable_command` rule that checks whether rules are re-enabled after being disabled. [Martin Redington](https://github.com/mildm8nnered) From e4e3545b712460509db6bc159838679f7b11b7cc Mon Sep 17 00:00:00 2001 From: "Garric G. Nahapetian" Date: Tue, 19 Mar 2024 14:07:22 -0700 Subject: [PATCH 011/265] Introduce SwiftLintCommandPlugin (#5497) --- CHANGELOG.md | 5 +++ Package.swift | 10 ++++- .../Path+Helpers.swift | 2 +- .../SwiftLintBuildToolPlugin.swift} | 8 ++-- .../SwiftLintBuildToolPluginError.swift} | 2 +- .../SwiftLintCommandPlugin.swift | 40 +++++++++++++++++++ README.md | 40 ++++++++++++++----- 7 files changed, 88 insertions(+), 19 deletions(-) rename Plugins/{SwiftLintPlugin => SwiftLintBuildToolPlugin}/Path+Helpers.swift (89%) rename Plugins/{SwiftLintPlugin/SwiftLintPlugin.swift => SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift} (95%) rename Plugins/{SwiftLintPlugin/SwiftLintPluginError.swift => SwiftLintBuildToolPlugin/SwiftLintBuildToolPluginError.swift} (90%) create mode 100644 Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index f72dca954e..8cfb3a49ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ * Rewrite `SwiftLintPlugin` using `BUILD_WORKSPACE_DIRECTORY` without relying on the `--config` option. [Garric Nahapetian](https://github.com/garricn) + +* Introduce SwiftLintCommandPlugin. + Rename SwiftLintBuildToolPlugin. + Add Swift Package Manager installation instructions. + [garricn](https://github.com/garricn) #### Experimental diff --git a/Package.swift b/Package.swift index c635b893ef..2fd4bc541a 100644 --- a/Package.swift +++ b/Package.swift @@ -19,7 +19,8 @@ let package = Package( products: [ .executable(name: "swiftlint", targets: ["swiftlint"]), .library(name: "SwiftLintFramework", targets: ["SwiftLintFramework"]), - .plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"]) + .plugin(name: "SwiftLintBuildToolPlugin", targets: ["SwiftLintBuildToolPlugin"]), + .plugin(name: "SwiftLintCommandPlugin", targets: ["SwiftLintCommandPlugin"]) ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.1")), @@ -32,10 +33,15 @@ let package = Package( ], targets: [ .plugin( - name: "SwiftLintPlugin", + name: "SwiftLintBuildToolPlugin", capability: .buildTool(), dependencies: swiftLintPluginDependencies ), + .plugin( + name: "SwiftLintCommandPlugin", + capability: .command(intent: .custom(verb: "swiftlint", description: "SwiftLint Command Plugin")), + dependencies: swiftLintPluginDependencies + ), .executableTarget( name: "swiftlint", dependencies: [ diff --git a/Plugins/SwiftLintPlugin/Path+Helpers.swift b/Plugins/SwiftLintBuildToolPlugin/Path+Helpers.swift similarity index 89% rename from Plugins/SwiftLintPlugin/Path+Helpers.swift rename to Plugins/SwiftLintBuildToolPlugin/Path+Helpers.swift index 239b190592..8de05a75fd 100644 --- a/Plugins/SwiftLintPlugin/Path+Helpers.swift +++ b/Plugins/SwiftLintBuildToolPlugin/Path+Helpers.swift @@ -16,7 +16,7 @@ extension Path { func resolveWorkingDirectory(in directory: Path) throws -> Path { guard "\(self)".hasPrefix("\(directory)") else { - throw SwiftLintPluginError.pathNotInDirectory(path: self, directory: directory) + throw SwiftLintBuildToolPluginError.pathNotInDirectory(path: self, directory: directory) } let path: Path? = sequence(first: self) { path in diff --git a/Plugins/SwiftLintPlugin/SwiftLintPlugin.swift b/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift similarity index 95% rename from Plugins/SwiftLintPlugin/SwiftLintPlugin.swift rename to Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift index 0969731cd9..65fbe02129 100644 --- a/Plugins/SwiftLintPlugin/SwiftLintPlugin.swift +++ b/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift @@ -2,7 +2,7 @@ import Foundation import PackagePlugin @main -struct SwiftLintPlugin: BuildToolPlugin { +struct SwiftLintBuildToolPlugin: BuildToolPlugin { func createBuildCommands( context: PluginContext, target: Target @@ -86,7 +86,7 @@ struct SwiftLintPlugin: BuildToolPlugin { import XcodeProjectPlugin // swiftlint:disable:next no_grouping_extension -extension SwiftLintPlugin: XcodeBuildToolPlugin { +extension SwiftLintBuildToolPlugin: XcodeBuildToolPlugin { func createBuildCommands( context: XcodePluginContext, target: XcodeTarget @@ -125,7 +125,7 @@ extension SwiftLintPlugin: XcodeBuildToolPlugin { let swiftFilesNotInProjectDirectory: [Path] = swiftFiles.filter { !$0.isDescendant(of: projectDirectory) } guard swiftFilesNotInProjectDirectory.isEmpty else { - throw SwiftLintPluginError.swiftFilesNotInProjectDirectory(projectDirectory) + throw SwiftLintBuildToolPluginError.swiftFilesNotInProjectDirectory(projectDirectory) } let directories: [Path] = try swiftFiles.map { try $0.resolveWorkingDirectory(in: projectDirectory) } @@ -133,7 +133,7 @@ extension SwiftLintPlugin: XcodeBuildToolPlugin { let swiftFilesNotInWorkingDirectory: [Path] = swiftFiles.filter { !$0.isDescendant(of: workingDirectory) } guard swiftFilesNotInWorkingDirectory.isEmpty else { - throw SwiftLintPluginError.swiftFilesNotInWorkingDirectory(workingDirectory) + throw SwiftLintBuildToolPluginError.swiftFilesNotInWorkingDirectory(workingDirectory) } return ["BUILD_WORKSPACE_DIRECTORY": "\(workingDirectory)"] diff --git a/Plugins/SwiftLintPlugin/SwiftLintPluginError.swift b/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPluginError.swift similarity index 90% rename from Plugins/SwiftLintPlugin/SwiftLintPluginError.swift rename to Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPluginError.swift index 3136f368a7..16f839502f 100644 --- a/Plugins/SwiftLintPlugin/SwiftLintPluginError.swift +++ b/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPluginError.swift @@ -1,6 +1,6 @@ import PackagePlugin -enum SwiftLintPluginError: Error, CustomStringConvertible { +enum SwiftLintBuildToolPluginError: Error, CustomStringConvertible { case pathNotInDirectory(path: Path, directory: Path) case swiftFilesNotInProjectDirectory(Path) case swiftFilesNotInWorkingDirectory(Path) diff --git a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift new file mode 100644 index 0000000000..7ad7275dd5 --- /dev/null +++ b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift @@ -0,0 +1,40 @@ +import Foundation +import PackagePlugin + +@main +struct SwiftLintCommandPlugin: CommandPlugin { + func performCommand( + context: PluginContext, + arguments: [String] + ) throws { + let tool: PluginContext.Tool = try context.tool(named: "swiftlint") + // Caching is managed internally because the cache must be located within the `pluginWorkDirectory`. + if arguments.contains("--cache-path") { + Diagnostics.error("Setting Cache Path Not Allowed") + return + } + let process: Process = .init() + process.currentDirectoryURL = URL(fileURLWithPath: context.package.directory.string) + process.executableURL = URL(fileURLWithPath: tool.path.string) + // The analyze command does not support the `--cache-path` argument + if arguments.contains("analyze") { + process.arguments = arguments + } else { + process.arguments = arguments + ["--cache-path", "\(context.pluginWorkDirectory.string)"] + } + try process.run() + process.waitUntilExit() + switch process.terminationReason { + case .exit: + break + case .uncaughtSignal: + Diagnostics.error("Uncaught Signal") + @unknown default: + Diagnostics.error("Unexpected Termination Reason") + } + guard process.terminationStatus == EXIT_SUCCESS else { + Diagnostics.error("Command Failed") + return + } + } +} diff --git a/README.md b/README.md index b011d96131..ae15b1c192 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,16 @@ unacceptable behavior to [info@realm.io](mailto:info@realm.io). ## Installation +### Using [Swift Package Manager](https://github.com/apple/swift-package-manager): + +> Replace `` with the desired minimum version. + +```swift +.package(url: "https://github.com/realm/SwiftLint.git", from: "") +``` + +SwiftLint can be used as a [command plugin](#swift-package-command-plugin) or a [build tool plugin](#swift-package-build-tool-plugins). + ### Using [Homebrew](http://brew.sh/): ``` @@ -138,7 +148,7 @@ we encourage you to watch this presentation or read the transcript: [![Presentation](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/presentation.svg)](https://youtu.be/9Z1nTMTejqU) -### Xcode +### Xcode Run Script Build Phase Integrate SwiftLint into your Xcode project to get warnings and errors displayed in the issue navigator. @@ -198,10 +208,18 @@ If you've installed SwiftLint via CocoaPods the script should look like this: "${PODS_ROOT}/SwiftLint/swiftlint" ``` -### Plug-in Support +### Swift Package Command Plugin + +The command plugin enables running SwiftLint from the command line as follows: + +```shell +swift package plugin swiftlint +``` + +### Swift Package Build Tool Plugins -SwiftLint can be used as a build tool plugin for both Swift Package projects -and Xcode projects. +SwiftLint can be used as a build tool plugin for both [Xcode projects](#xcode-projects) and +[Swift Package projects](#swift-package-projects). The build tool plugin determines the SwiftLint working directory by locating the topmost config file within the package/project directory. If a config file @@ -231,17 +249,17 @@ plugin, please consider one of the following options: - You can also consider the use of a Run Script Build Phase in place of the build tool plugin. -#### Xcode +#### Xcode Projects -You can integrate SwiftLint as an Xcode Build Tool Plug-in if you're working +You can integrate SwiftLint as an Xcode Build Tool Plugin if you're working with a project in Xcode. Add SwiftLint as a package dependency to your project without linking any of the products. Select the target you want to add linting to and open the `Build Phases` inspector. -Open `Run Build Tool Plug-ins` and select the `+` button. -Select `SwiftLintPlugin` from the list and add it to the project. +Open `Run Build Tool Plugins` and select the `+` button. +Select `SwiftLintBuildToolPlugin` from the list and add it to the project. ![](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/select-swiftlint-plugin.png) @@ -254,9 +272,9 @@ For unattended use (e.g. on CI), you can disable the package and macro validatio _Note: This implicitly trusts all Xcode package plugins and macros in packages and bypasses Xcode's package validation dialogs, which has security implications._ -#### Swift Package +#### Swift Package Projects -You can integrate SwiftLint as a Swift Package Manager Plug-in if you're working with +You can integrate SwiftLint as a Swift Package Manager Plugin if you're working with a Swift Package with a `Package.swift` manifest. Add SwiftLint as a package dependency to your `Package.swift` file. @@ -265,7 +283,7 @@ Add SwiftLint to a target using the `plugins` parameter. ```swift .target( ... - plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")] + plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLint")] ), ``` From 082adfaed78cf6786adf28adc41f022344e221ae Mon Sep 17 00:00:00 2001 From: deterclosed <164524498+deterclosed@users.noreply.github.com> Date: Sat, 23 Mar 2024 22:25:16 +0800 Subject: [PATCH 012/265] Fix some typos (#5504) --- CHANGELOG.md | 2 +- .../Rules/Lint/UnusedCaptureListRule.swift | 2 +- .../Performance/ContainsOverRangeNilComparisonRule.swift | 2 +- .../Rules/Style/NonOverridableClassDeclarationRule.swift | 2 +- Source/SwiftLintCore/Models/Issue.swift | 2 +- .../ConfigurationTests+MultipleConfigs.swift | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cfb3a49ff..185efe4076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1478,7 +1478,7 @@ accordingly._ progress bar instead of each file being processed. [JP Simard](https://github.com/jpsim) -* `--fix` now works with `--use-stdin`, printing the output to to STDOUT instead +* `--fix` now works with `--use-stdin`, printing the output to STDOUT instead of crashing. [SimplyDanny](https://github.com/SimplyDanny) [#4127](https://github.com/realm/SwiftLint/issues/4127) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift index a23b4ece77..d913a685c8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift @@ -134,7 +134,7 @@ struct UnusedCaptureListRule: SwiftSyntaxRule, OptInRule { Example("{ [↓foo] in _ }()"), Example(""" let closure = { [↓weak a] in - // The new `a` immediatly shadows the captured `a` which thus isn't needed. + // The new `a` immediately shadows the captured `a` which thus isn't needed. guard let a = getOptionalValue() else { return } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift index 51577058a5..71088d6e2d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift @@ -6,7 +6,7 @@ struct ContainsOverRangeNilComparisonRule: OptInRule { static let description = RuleDescription( identifier: "contains_over_range_nil_comparison", - name: "Contains over Range Comparision to Nil", + name: "Contains over Range Comparison to Nil", description: "Prefer `contains` over `range(of:) != nil` and `range(of:) == nil`", kind: .performance, nonTriggeringExamples: [ diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift index fa407544c9..bec336d152 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift @@ -9,7 +9,7 @@ struct NonOverridableClassDeclarationRule: SwiftSyntaxCorrectableRule, OptInRule name: "Class Declaration in Final Class", description: """ Class methods and properties in final classes should themselves be final, just as if the declarations - are private. In both cases, they cannot be overriden. Using `final class` or `static` makes this explicit. + are private. In both cases, they cannot be overridden. Using `final class` or `static` makes this explicit. """, kind: .style, nonTriggeringExamples: [ diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 77c5bcf33f..276352b104 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -60,7 +60,7 @@ public enum Issue: LocalizedError, Equatable { /// /// - parameter error: Any `Error`. /// - /// - returns: A `SwiftLintError.genericWarning` containig the message of the `error` argument. + /// - returns: A `SwiftLintError.genericWarning` containing the message of the `error` argument. static func wrap(error: some Error) -> Self { error as? Issue ?? Self.genericWarning(error.localizedDescription) } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index 52d197d4f0..10cf217fbc 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -467,7 +467,7 @@ extension ConfigurationTests { // If the remote file is not allowed to reference a local file, the config should equal the default config. XCTAssertEqual( Configuration( - configurationFiles: [], // not specifiying a file means the .swiftlint.yml will be used + configurationFiles: [], // not specifying a file means the .swiftlint.yml will be used mockedNetworkResults: [ "https://www.mock.com": """ @@ -487,7 +487,7 @@ extension ConfigurationTests { // If the cycle is properly detected, the config should equal the default config. XCTAssertEqual( Configuration( - configurationFiles: [], // not specifiying a file means the .swiftlint.yml will be used + configurationFiles: [], // not specifying a file means the .swiftlint.yml will be used mockedNetworkResults: [ "https://www.mock.com": """ From 82cad0bfffb2bbc042592faf164ab06f7ae9db23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 23 Mar 2024 18:54:39 +0100 Subject: [PATCH 013/265] Allow to infer option names (#5505) This allows to infer names of options from their names in a configuration. CamelCase is translated into snake_case automatically when `apply` is triggered. * Don't have all `RuleConfiguration`s conform to `InlinableOptionType`. Mark types that must have this capability explicitly. Same for `AcceptableByConfigurationElement`. * A type being an `InlinableOptionType` doesn't mean it's automatically inlined. This also doesn't depend on the fact of having a name for its key configured any longer. Instead, an `inline` attribute must explicitly be set to `true` in `@ConfigurationElement`. * Key name inference is optional and can be overwritten by specifying a key name in the attribute. * Inlined configurations only fail in `apply` when they are really sure that something is odd. Otherwise, they accept to not being updated. --- .../CyclomaticComplexityConfiguration.swift | 2 +- .../FileLengthConfiguration.swift | 2 +- .../FunctionParameterCountConfiguration.swift | 2 +- .../IdentifierNameConfiguration.swift | 2 +- .../LineLengthConfiguration.swift | 2 +- .../NameConfiguration.swift | 2 +- .../TypeNameConfiguration.swift | 2 +- .../ChildOptionSeverityConfiguration.swift | 2 +- .../Models/RuleConfigurationDescription.swift | 109 +++++++++++++----- .../Models/SeverityConfiguration.swift | 12 +- .../Protocols/RuleConfiguration.swift | 2 +- .../RegexConfiguration.swift | 3 +- .../SeverityLevelsConfiguration.swift | 4 +- .../RuleConfigurationMacros.swift | 54 ++++++--- Tests/MacroTests/AutoApplyTests.swift | 69 +++++++---- ...licitTypeInterfaceConfigurationTests.swift | 2 +- .../LineLengthConfigurationTests.swift | 2 +- .../RuleConfigurationDescriptionTests.swift | 51 ++++---- .../RuleConfigurationTests.swift | 9 +- 19 files changed, 213 insertions(+), 120 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift index c7fc2d380a..bb396f6c51 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift @@ -5,7 +5,7 @@ import SwiftLintCore struct CyclomaticComplexityConfiguration: RuleConfiguration { typealias Parent = CyclomaticComplexityRule - @ConfigurationElement + @ConfigurationElement(inline: true) private(set) var length = SeverityLevelsConfiguration(warning: 10, error: 20) @ConfigurationElement(key: "ignores_case_statements") private(set) var ignoresCaseStatements = false diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift index f32ea9cd78..fab9eff557 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift @@ -4,7 +4,7 @@ import SwiftLintCore struct FileLengthConfiguration: RuleConfiguration { typealias Parent = FileLengthRule - @ConfigurationElement + @ConfigurationElement(inline: true) private(set) var severityConfiguration = SeverityLevelsConfiguration(warning: 400, error: 1000) @ConfigurationElement(key: "ignore_comment_only_lines") private(set) var ignoreCommentOnlyLines = false diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift index aedea8a3ad..f964487b69 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift @@ -4,7 +4,7 @@ import SwiftLintCore struct FunctionParameterCountConfiguration: RuleConfiguration { typealias Parent = FunctionParameterCountRule - @ConfigurationElement + @ConfigurationElement(inline: true) private(set) var severityConfiguration = SeverityLevelsConfiguration(warning: 5, error: 8) @ConfigurationElement(key: "ignores_default_parameters") private(set) var ignoresDefaultParameters = true diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift index f5550b8085..7f8a98b1ad 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift @@ -6,7 +6,7 @@ struct IdentifierNameConfiguration: RuleConfiguration { private static let defaultOperators = ["/", "=", "-", "+", "!", "*", "|", "^", "~", "?", ".", "%", "<", ">", "&"] - @ConfigurationElement + @ConfigurationElement(inline: true) private(set) var nameConfiguration = NameConfiguration(minLengthWarning: 3, minLengthError: 2, maxLengthWarning: 40, diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift index e8354a08d8..af1845eb9e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift @@ -4,7 +4,7 @@ import SwiftLintCore struct LineLengthConfiguration: RuleConfiguration { typealias Parent = LineLengthRule - @ConfigurationElement + @ConfigurationElement(inline: true) private(set) var length = SeverityLevelsConfiguration(warning: 120, error: 200) @ConfigurationElement(key: "ignores_urls") private(set) var ignoresURLs = false diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift index dd952e3992..c1a5e24c14 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift @@ -1,7 +1,7 @@ import Foundation import SwiftLintCore -struct NameConfiguration: RuleConfiguration { +struct NameConfiguration: RuleConfiguration, InlinableOptionType { typealias Severity = SeverityConfiguration typealias SeverityLevels = SeverityLevelsConfiguration typealias StartWithLowercaseConfiguration = ChildOptionSeverityConfiguration diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift index 8d56cbf5e5..ff21a9eee0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift @@ -4,7 +4,7 @@ import SwiftLintCore struct TypeNameConfiguration: RuleConfiguration { typealias Parent = TypeNameRule - @ConfigurationElement + @ConfigurationElement(inline: true) private(set) var nameConfiguration = NameConfiguration(minLengthWarning: 3, minLengthError: 0, maxLengthWarning: 40, diff --git a/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift b/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift index 3c867c6bb7..b1c6eaa40f 100644 --- a/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift +++ b/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift @@ -1,6 +1,6 @@ /// A rule configuration that allows to disable (`off`) an option of a rule or specify its severity level in which /// case it's active. -public struct ChildOptionSeverityConfiguration: RuleConfiguration { +public struct ChildOptionSeverityConfiguration: RuleConfiguration, AcceptableByConfigurationElement { /// Configuration with a warning severity. public static var error: Self { Self(optionSeverity: .error) } /// Configuration with an error severity. diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index afc3ea5330..3929aba064 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -332,7 +332,7 @@ public protocol AcceptableByConfigurationElement { func asDescription(with key: String) -> RuleConfigurationDescription /// Update the object. - /// + /// /// - Parameter value: New underlying data for the object. mutating func apply(_ value: Any?, ruleID: String) throws } @@ -350,45 +350,69 @@ public extension AcceptableByConfigurationElement { } } -/// An option type that does not need a key when used in a ``ConfigurationElement``. Its value will be inlined. +/// An option type that can appear inlined into its using configuration. +/// +/// The ``ConfigurationElement`` must opt into this behavior. In this case, the option does not have a key. This is +/// almost exclusively useful for common ``RuleConfiguration``s that are used in many other rules as child +/// configurations. +/// +/// > Warning: A type conforming to this protocol is assumed to throw an issue in its `apply` method only when it's +/// absolutely clear that there is an error in the YAML configuration passed in. Since it may be used in a nested +/// context and doesn't know about the outer configuration, it's not always clear if a certain key-value is really +/// unacceptable. public protocol InlinableOptionType: AcceptableByConfigurationElement {} /// A single parameter of a rule configuration. /// /// Apply it to a simple (e.g. boolean) property like /// ```swift -/// @ConfigurationElement(key: "name") +/// @ConfigurationElement +/// var property = true +/// ``` +/// to add a (boolean) option to a configuration. The name of the option will be inferred from the name of the property. +/// In this case, it's just `property`. CamelCase names will translated into snake_case, i.e. `myOption` is going to be +/// translated into `my_option` in the `.swiftlint.yml` configuration file. +/// +/// This mechanism may be overwritten with an explicitly set key: +/// ```swift +/// @ConfigurationElement(key: "foo_bar") /// var property = true /// ``` -/// If the wrapped element is an ``InlinableOptionType``, there are two options for its representation -/// in the documentation: /// -/// 1. It can be inlined into the parent configuration. For that, do not provide a name as an argument. E.g. +/// If the wrapped element is an ``InlinableOptionType``, there are three ways to represent it in the documentation: +/// +/// 1. It can be inlined into the parent configuration. For that, add the parameter `inline: true`. E.g. /// ```swift -/// @ConfigurationElement(key: "name") -/// var property = true -/// @ConfigurationElement +/// @ConfigurationElement(inline: true) /// var levels = SeverityLevelsConfiguration(warning: 1, error: 2) /// ``` /// will be documented as a linear list: /// ``` -/// name: true /// warning: 1 /// error: 2 /// ``` -/// 2. It can be represented as a separate nested configuration. In this case, it must have a name. E.g. +/// 2. It can be represented as a separate nested configuration. In this case, it must not have set the `inline` flag to +/// `true`. E.g. /// ```swift -/// @ConfigurationElement(key: "name") -/// var property = true -/// @ConfigurationElement(key: "levels") +/// @ConfigurationElement /// var levels = SeverityLevelsConfiguration(warning: 1, error: 2) /// ``` /// will have a nested configuration section: /// ``` -/// name: true /// levels: warning: 1 /// error: 2 /// ``` +/// 3. As mentioned in the beginning, the implict key inference meachnism can be overruled by specifying a `key` as in: +/// ```swift +/// @ConfigurationElement(key: "foo") +/// var levels = SeverityLevelsConfiguration(warning: 1, error: 2) +/// ``` +/// It will appear in the documentation as: +/// ``` +/// foo: warning: 1 +/// error: 2 +/// ``` +/// @propertyWrapper public struct ConfigurationElement: Equatable { /// Wrapped option value. @@ -402,7 +426,10 @@ public struct ConfigurationElement Void @@ -410,12 +437,12 @@ public struct ConfigurationElement Void = { _ in }) { - self.wrappedValue = value - self.key = key - self.postprocessor = postprocessor + public init(wrappedValue value: T, + key: String = "", + postprocessor: @escaping (inout T) throws -> Void = { _ in }) { + self.init(wrappedValue: value, key: key, inline: false, postprocessor: postprocessor) // Validate and modify the set value immediately. An exception means invalid defaults. try! performAfterParseOperations() // swiftlint:disable:this force_try @@ -423,22 +450,42 @@ public struct ConfigurationElement(key: String) where T == Wrapped? { - self.init(wrappedValue: nil, key: key) + /// - Parameters: + /// - key: Optional name of the option. If not specified, it will be inferred from the attributed property. + public init(key: String = "") where T == Wrapped? { + self.init(wrappedValue: nil, key: key, inline: false) } - /// Constructor for a ``ConfigurationElement`` without a key. + /// Constructor for an ``InlinableOptionType`` without a key. /// - /// ``InlinableOptionType``s are allowed to have an empty key. The configuration will be inlined into its - /// parent configuration in this specific case. + /// - Parameters: + /// - value: Value to be wrapped. + /// - inline: If `true`, the option will be handled as it would be part of its parent. All of its options + /// will be inlined. Otherwise, it will be treated as a normal nested configuration with its name + /// inferred from the name of the attributed property. + public init(wrappedValue value: T, inline: Bool) where T: InlinableOptionType { + self.init(wrappedValue: value, key: "", inline: inline) + } + + /// Constructor for an ``InlinableOptionType`` with a name. The configuration will explicitly not be inlined. /// /// - Parameters: /// - value: Value to be wrapped. - public init(wrappedValue value: T) where T: InlinableOptionType { - self.init(wrappedValue: value, key: "") + /// - key: Name of the option. + public init(wrappedValue value: T, key: String) where T: InlinableOptionType { + self.init(wrappedValue: value, key: key, inline: false) + } + + private init(wrappedValue: T, + key: String, + inline: Bool, + postprocessor: @escaping (inout T) throws -> Void = { _ in }) { + self.wrappedValue = wrappedValue + self.key = key + self.inline = inline + self.postprocessor = postprocessor } /// Run operations to validate and modify the parsed value. @@ -575,7 +622,7 @@ extension RegularExpression: AcceptableByConfigurationElement { // MARK: RuleConfiguration conformances -public extension RuleConfiguration { +public extension AcceptableByConfigurationElement where Self: RuleConfiguration { func asOption() -> OptionType { .nested(.from(configuration: self)) } diff --git a/Source/SwiftLintCore/Models/SeverityConfiguration.swift b/Source/SwiftLintCore/Models/SeverityConfiguration.swift index 7e44821f68..a26e670ef7 100644 --- a/Source/SwiftLintCore/Models/SeverityConfiguration.swift +++ b/Source/SwiftLintCore/Models/SeverityConfiguration.swift @@ -1,5 +1,5 @@ /// A rule configuration that allows specifying the desired severity level for violations. -public struct SeverityConfiguration: SeverityBasedRuleConfiguration { +public struct SeverityConfiguration: SeverityBasedRuleConfiguration, InlinableOptionType { /// Configuration with a warning severity. public static var error: Self { Self(.error) } /// Configuration with an error severity. @@ -22,10 +22,12 @@ public struct SeverityConfiguration: SeverityBasedRuleConfiguratio public mutating func apply(configuration: Any) throws { let configString = configuration as? String let configDict = configuration as? [String: Any] - guard let severityString: String = configString ?? configDict?[$severity.key] as? String, - let severity = ViolationSeverity(rawValue: severityString.lowercased()) else { - throw Issue.unknownConfiguration(ruleID: Parent.description.identifier) + if let severityString: String = configString ?? configDict?[$severity.key] as? String { + if let severity = ViolationSeverity(rawValue: severityString.lowercased()) { + self.severity = severity + } else { + throw Issue.unknownConfiguration(ruleID: Parent.description.identifier) + } } - self.severity = severity } } diff --git a/Source/SwiftLintCore/Protocols/RuleConfiguration.swift b/Source/SwiftLintCore/Protocols/RuleConfiguration.swift index 8f5a32f516..acdd2b6359 100644 --- a/Source/SwiftLintCore/Protocols/RuleConfiguration.swift +++ b/Source/SwiftLintCore/Protocols/RuleConfiguration.swift @@ -1,5 +1,5 @@ /// A configuration value for a rule to allow users to modify its behavior. -public protocol RuleConfiguration: InlinableOptionType, Equatable { +public protocol RuleConfiguration: Equatable { /// The type of the rule that's using this configuration. associatedtype Parent: Rule diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index 7f696694ee..46adbaa092 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -2,7 +2,8 @@ import Foundation import SourceKittenFramework /// A rule configuration used for defining custom rules in yaml. -public struct RegexConfiguration: SeverityBasedRuleConfiguration, Hashable, CacheDescriptionProvider { +public struct RegexConfiguration: SeverityBasedRuleConfiguration, Hashable, + CacheDescriptionProvider, InlinableOptionType { /// The identifier for this custom rule. public let identifier: String /// The name for this custom rule. diff --git a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift index 8bfcdc8639..688abc290c 100644 --- a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift @@ -1,5 +1,5 @@ /// A rule configuration that allows specifying thresholds for `warning` and `error` severities. -public struct SeverityLevelsConfiguration: RuleConfiguration { +public struct SeverityLevelsConfiguration: RuleConfiguration, InlinableOptionType { /// The threshold for a violation to be a warning. @ConfigurationElement(key: "warning") public var warning: Int = 12 @@ -48,8 +48,6 @@ public struct SeverityLevelsConfiguration: RuleConfiguration { } else { self.error = nil } - } else { - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) } } } diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index f9df158831..b623049140 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -1,3 +1,4 @@ +import Foundation import SwiftSyntax import SwiftSyntaxMacros @@ -22,37 +23,41 @@ enum AutoApply: MemberMacro { let firstIndexWithoutKey = annotatedVarDecls .partition { _, annotation in if case let .argumentList(arguments) = annotation.arguments { - return arguments.contains { $0.label?.text == "key" } == true + return arguments.contains { + $0.label?.text == "inline" + && $0.expression.as(BooleanLiteralExprSyntax.self)?.literal.text == "true" + } } return false } let elementNames = annotatedVarDecls.compactMap { $0.0.bindings.first?.pattern.as(IdentifierPatternSyntax.self)?.identifier.text } - let elementsWithoutKeyUpdate = elementNames[.. = [1, 2, 3] - @ConfigurationElement + @ConfigurationElement(inline: true) var severityConfig = SeverityConfiguration(.error) @ConfigurationElement(key: "SEVERITY") var renamedSeverityConfig = SeverityConfiguration(.warning) - @ConfigurationElement - var inlinedSeverityLevels = SeverityLevelsConfiguration(warning: 1, error: 2) + @ConfigurationElement(inline: true) + var inlinedSeverityLevels = SeverityLevelsConfiguration(warning: 1, error: nil) @ConfigurationElement(key: "levels") - var nestedSeverityLevels = SeverityLevelsConfiguration(warning: 3, error: nil) + var nestedSeverityLevels = SeverityLevelsConfiguration(warning: 3, error: 2) func isEqualTo(_ ruleConfiguration: some RuleConfiguration) -> Bool { false } } // swiftlint:disable:next function_body_length - func testDescriptionFromConfiguration() { - let description = RuleConfigurationDescription.from(configuration: TestConfiguration()) + func testDescriptionFromConfiguration() throws { + var configuration = TestConfiguration() + try configuration.apply(configuration: [:]) + let description = RuleConfigurationDescription.from(configuration: configuration) XCTAssertEqual(description.oneLiner(), """ flag: true; \ string: "value"; \ symbol: value; \ integer: 2; \ - double: 2.1; \ + my_double: 2.1; \ severity: warning; \ list: ["STRING1", "STRING2"]; \ set: [1, 2, 3]; \ severity: error; \ SEVERITY: warning; \ warning: 1; \ - error: 2; \ - levels: warning: 3 + levels: warning: 3, error: 2 """) XCTAssertEqual(description.markdown(), """ @@ -103,7 +104,7 @@ class RuleConfigurationDescriptionTests: XCTestCase { - double + my_double 2.1 @@ -159,14 +160,6 @@ class RuleConfigurationDescriptionTests: XCTestCase { - error - - - 2 - - - - levels @@ -183,6 +176,14 @@ class RuleConfigurationDescriptionTests: XCTestCase { 3 + + + error + + + 2 + + @@ -196,16 +197,16 @@ class RuleConfigurationDescriptionTests: XCTestCase { string: "value" symbol: value integer: 2 - double: 2.1 + my_double: 2.1 severity: warning list: ["STRING1", "STRING2"] set: [1, 2, 3] severity: error SEVERITY: warning warning: 1 - error: 2 levels: warning: 3 + error: 2 """) } @@ -465,7 +466,7 @@ class RuleConfigurationDescriptionTests: XCTestCase { "symbol": "new symbol", "integer": 5, "null": 0, - "double": 5.1, + "my_double": 5.1, "severity": "error", "list": ["string3", "string4"], "set": [4, 5, 6], @@ -479,7 +480,7 @@ class RuleConfigurationDescriptionTests: XCTestCase { XCTAssertEqual(configuration.symbol, try Symbol(fromAny: "new symbol", context: "rule")) XCTAssertEqual(configuration.integer, 5) XCTAssertEqual(configuration.null, 0) - XCTAssertEqual(configuration.double, 5.1) + XCTAssertEqual(configuration.myDouble, 5.1) XCTAssertEqual(configuration.severity, .error) XCTAssertEqual(configuration.list, ["STRING3", "STRING4"]) XCTAssertEqual(configuration.set, [4, 5, 6]) diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift index 2d2f2a029c..51407fd0d8 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift @@ -66,8 +66,15 @@ class RuleConfigurationTests: SwiftLintTestCase { } } - func testSeverityConfigurationThrowsOnBadConfig() { + func testSeverityConfigurationDoesNotChangeOnBadConfig() throws { let config = 17 + var severityConfig = SeverityConfiguration(.error) + try severityConfig.apply(configuration: config) + XCTAssertEqual(severityConfig.severity, .error) + } + + func testSeverityConfigurationThrowsOnBadConfig() { + let config = "foo" var severityConfig = SeverityConfiguration(.warning) checkError(Issue.unknownConfiguration(ruleID: RuleMock.description.identifier)) { try severityConfig.apply(configuration: config) From ccd50e8c68fe0f3ea3cc3d01e7a2fd91c345f6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 23 Mar 2024 19:01:12 +0100 Subject: [PATCH 014/265] Merge duplicated issues --- .../DeploymentTargetConfiguration.swift | 8 ++++---- .../RuleConfigurations/FileHeaderConfiguration.swift | 2 +- .../RuleConfigurations/MissingDocsConfiguration.swift | 6 +++--- .../RuleConfigurations/ModifierOrderConfiguration.swift | 2 +- .../Rules/RuleConfigurations/NameConfiguration.swift | 2 +- .../PrivateUnitTestConfiguration.swift | 2 +- .../RequiredEnumCaseConfiguration.swift | 2 +- .../RuleConfigurations/UnusedImportConfiguration.swift | 2 +- .../Models/ChildOptionSeverityConfiguration.swift | 2 +- Source/SwiftLintCore/Models/Issue.swift | 9 ++------- Source/SwiftLintCore/Models/SeverityConfiguration.swift | 2 +- .../RuleConfigurations/RegexConfiguration.swift | 6 +++--- Source/SwiftLintCore/Rules/CustomRules.swift | 2 +- Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift | 2 +- .../MakeAcceptableByConfigurationElementTests.swift | 4 ++-- Tests/SwiftLintFrameworkTests/CustomRulesTests.swift | 2 +- .../DeploymentTargetConfigurationTests.swift | 2 +- .../ExplicitTypeInterfaceConfigurationTests.swift | 2 +- .../ImplicitReturnConfigurationTests.swift | 2 +- .../ImplicitlyUnwrappedOptionalConfigurationTests.swift | 2 +- .../SwiftLintFrameworkTests/NameConfigurationTests.swift | 2 +- .../SwiftLintFrameworkTests/RuleConfigurationTests.swift | 8 ++++---- 22 files changed, 34 insertions(+), 39 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift index ca8b32a157..8490c18a99 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift @@ -62,7 +62,7 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { private static func parseVersion(string: String) throws -> (Int, Int, Int) { func parseNumber(_ string: String) throws -> Int { guard let number = Int(string) else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } return number } @@ -70,7 +70,7 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { let parts = string.components(separatedBy: ".") switch parts.count { case 0: - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) case 1: return (try parseNumber(parts[0]), 0, 0) case 2: @@ -131,7 +131,7 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { mutating func apply(configuration: Any) throws { guard let configuration = configuration as? [String: Any] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } for (key, value) in configuration { if key == "severity", let value = value as? String { @@ -139,7 +139,7 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { continue } guard let target = targets[key] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } try target.update(using: value) if let extensionConfigurationKey = target.platform.appExtensionCounterpart?.configurationKey, diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift index 48706f9722..fd0557b99a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift @@ -28,7 +28,7 @@ struct FileHeaderConfiguration: SeverityBasedRuleConfiguration { mutating func apply(configuration: Any) throws { guard let configuration = configuration as? [String: String] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } // Cache the created regexes if possible. diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift index a497952ce5..4f506391e7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift @@ -30,7 +30,7 @@ struct MissingDocsConfiguration: RuleConfiguration { mutating func apply(configuration: Any) throws { guard let dict = configuration as? [String: Any] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } if let shouldExcludeExtensions = dict[$excludesExtensions.key] as? Bool { @@ -62,7 +62,7 @@ struct MissingDocsConfiguration: RuleConfiguration { let rules: [RuleParameter] = try array .map { val -> RuleParameter in guard let acl = AccessControlLevel(description: val) else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } return RuleParameter(severity: severity, value: acl) } @@ -76,7 +76,7 @@ struct MissingDocsConfiguration: RuleConfiguration { } guard parameters.count == parameters.map({ $0.value }).unique.count else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } return parameters.isNotEmpty ? parameters : nil diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift index 05ef0cba4e..70338e61ed 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift @@ -28,7 +28,7 @@ extension SwiftDeclarationAttributeKind.ModifierGroup: AcceptableByConfiguration if let value = value as? String, let newSelf = Self(rawValue: value), newSelf != .atPrefixed { self = newSelf } else { - throw Issue.unknownConfiguration(ruleID: ruleID) + throw Issue.invalidConfiguration(ruleID: ruleID) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift index c1a5e24c14..0cf9e7ced7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift @@ -51,7 +51,7 @@ struct NameConfiguration: RuleConfiguration, InlinableOptionType { mutating func apply(configuration: Any) throws { guard let configurationDict = configuration as? [String: Any] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } if let minLengthConfiguration = configurationDict[$minLength.key] { diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateUnitTestConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateUnitTestConfiguration.swift index 9a67e2bd6c..65b14cdcfe 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateUnitTestConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateUnitTestConfiguration.swift @@ -14,7 +14,7 @@ struct PrivateUnitTestConfiguration: SeverityBasedRuleConfiguration { mutating func apply(configuration: Any) throws { guard let configurationDict = configuration as? [String: Any] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } if let extraTestParentClasses = configurationDict[$testParentClasses.key] as? [String] { self.testParentClasses.formUnion(extraTestParentClasses) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RequiredEnumCaseConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RequiredEnumCaseConfiguration.swift index 7a3184a68a..2402ed84d3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RequiredEnumCaseConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RequiredEnumCaseConfiguration.swift @@ -32,7 +32,7 @@ struct RequiredEnumCaseConfiguration: RuleConfiguration { mutating func apply(configuration: Any) throws { guard let config = configuration as? [String: [String: String]] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } register(protocols: config) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift index 57aa628523..5e9f2eec69 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift @@ -14,7 +14,7 @@ struct TransitiveModuleConfiguration: Equatable, AcceptableByConfi let importedModule = configurationDict["module"] as? String, let transitivelyImportedModules = configurationDict["allowed_transitive_imports"] as? [String] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } self.importedModule = importedModule self.transitivelyImportedModules = transitivelyImportedModules diff --git a/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift b/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift index b1c6eaa40f..fb4aed94b8 100644 --- a/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift +++ b/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift @@ -23,7 +23,7 @@ public struct ChildOptionSeverityConfiguration: RuleConfiguration, public mutating func apply(configuration: Any) throws { guard let configString = configuration as? String, let optionSeverity = ChildOptionSeverity(rawValue: configString.lowercased()) else { - throw Issue.unknownConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) } self.optionSeverity = optionSeverity } diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 276352b104..12fbb39e8d 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -3,7 +3,7 @@ import Foundation /// All possible SwiftLint issues which are printed as warnings by default. public enum Issue: LocalizedError, Equatable { /// The configuration didn't match internal expectations. - case unknownConfiguration(ruleID: String) + case invalidConfiguration(ruleID: String) /// Rule is listed multiple times in the configuration. case listedMultipleTime(ruleID: String, times: Int) @@ -11,9 +11,6 @@ public enum Issue: LocalizedError, Equatable { /// An identifier `old` has been renamed to `new`. case renamedIdentifier(old: String, new: String) - /// Configuration for a rule is invalid. - case invalidConfiguration(ruleID: String) - /// Some configuration keys are invalid. case invalidConfigurationKeys(ruleID: String, keys: Set) @@ -92,14 +89,12 @@ public enum Issue: LocalizedError, Equatable { private var message: String { switch self { - case let .unknownConfiguration(id): + case let .invalidConfiguration(id): return "Invalid configuration for '\(id)' rule. Falling back to default." case let .listedMultipleTime(id, times): return "'\(id)' is listed \(times) times in the configuration." case let .renamedIdentifier(old, new): return "'\(old)' has been renamed to '\(new)' and will be completely removed in a future release." - case let .invalidConfiguration(id): - return "Invalid configuration for '\(id)'. Falling back to default." case let .invalidConfigurationKeys(id, keys): return "Configuration for '\(id)' rule contains the invalid key(s) \(keys.formatted)." case let .invalidRuleIDs(ruleIDs): diff --git a/Source/SwiftLintCore/Models/SeverityConfiguration.swift b/Source/SwiftLintCore/Models/SeverityConfiguration.swift index a26e670ef7..e8038af660 100644 --- a/Source/SwiftLintCore/Models/SeverityConfiguration.swift +++ b/Source/SwiftLintCore/Models/SeverityConfiguration.swift @@ -26,7 +26,7 @@ public struct SeverityConfiguration: SeverityBasedRuleConfiguratio if let severity = ViolationSeverity(rawValue: severityString.lowercased()) { self.severity = severity } else { - throw Issue.unknownConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) } } } diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index 46adbaa092..8a4f354629 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -59,7 +59,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, public mutating func apply(configuration: Any) throws { guard let configurationDict = configuration as? [String: Any], let regexString = configurationDict[$regex.key] as? String else { - throw Issue.unknownConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) } regex = try RegularExpression(pattern: regexString) @@ -91,7 +91,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, } if let captureGroup = configurationDict["capture_group"] as? Int { guard (0 ... regex.numberOfCaptureGroups).contains(captureGroup) else { - throw Issue.unknownConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) } self.captureGroup = captureGroup } @@ -141,7 +141,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, if let kind = SyntaxKind(shortName: $0) { return kind } - throw Issue.unknownConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) } return Set(kinds) } diff --git a/Source/SwiftLintCore/Rules/CustomRules.swift b/Source/SwiftLintCore/Rules/CustomRules.swift index d7831979d8..8eca8e70b8 100644 --- a/Source/SwiftLintCore/Rules/CustomRules.swift +++ b/Source/SwiftLintCore/Rules/CustomRules.swift @@ -16,7 +16,7 @@ struct CustomRulesConfiguration: RuleConfiguration, CacheDescriptionProvider { mutating func apply(configuration: Any) throws { guard let configurationDict = configuration as? [String: Any] else { - throw Issue.unknownConfiguration(ruleID: Parent.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } for (key, value) in configurationDict { diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index b623049140..40b324e941 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -93,7 +93,7 @@ enum MakeAcceptableByConfigurationElement: ExtensionMacro { if let value = value as? String, let newSelf = Self(rawValue: value) { self = newSelf } else { - throw Issue.unknownConfiguration(ruleID: ruleID) + throw Issue.invalidConfiguration(ruleID: ruleID) } } } diff --git a/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift b/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift index 041d80443b..37bc9053e0 100644 --- a/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift +++ b/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift @@ -64,7 +64,7 @@ final class MakeAcceptableByConfigurationElementTests: XCTestCase { if let value = value as? String, let newSelf = Self (rawValue: value) { self = newSelf } else { - throw Issue.unknownConfiguration(ruleID: ruleID) + throw Issue.invalidConfiguration(ruleID: ruleID) } } } @@ -92,7 +92,7 @@ final class MakeAcceptableByConfigurationElementTests: XCTestCase { if let value = value as? String, let newSelf = Self (rawValue: value) { self = newSelf } else { - throw Issue.unknownConfiguration(ruleID: ruleID) + throw Issue.invalidConfiguration(ruleID: ruleID) } } } diff --git a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift index 94ddf5e49e..169310247b 100644 --- a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift @@ -61,7 +61,7 @@ class CustomRulesTests: SwiftLintTestCase { func testCustomRuleConfigurationThrows() { let config = 17 var customRulesConfig = CustomRulesConfiguration() - checkError(Issue.unknownConfiguration(ruleID: CustomRules.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: CustomRules.description.identifier)) { try customRulesConfig.apply(configuration: config) } } diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift index 370d85c03e..d3619248b0 100644 --- a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift @@ -137,7 +137,7 @@ class DeploymentTargetConfigurationTests: SwiftLintTestCase { for badConfig in badConfigs { var configuration = DeploymentTargetConfiguration() - checkError(Issue.unknownConfiguration(ruleID: DeploymentTargetRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: DeploymentTargetRule.description.identifier)) { try configuration.apply(configuration: badConfig) } } diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift index a58610d1cb..5affea03a3 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift @@ -35,7 +35,7 @@ class ExplicitTypeInterfaceConfigurationTests: SwiftLintTestCase { func testInvalidTypeOfValueInCustomConfiguration() { var config = ExplicitTypeInterfaceConfiguration() - checkError(Issue.unknownConfiguration(ruleID: ExplicitTypeInterfaceRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ExplicitTypeInterfaceRule.description.identifier)) { try config.apply(configuration: ["severity": "foo"]) } } diff --git a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift index 82e34d95a5..cf72c7363d 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift @@ -31,7 +31,7 @@ class ImplicitReturnConfigurationTests: SwiftLintTestCase { var configuration = ImplicitReturnConfiguration() let config = ["included": ["foreach"]] as [String: any Sendable] - checkError(Issue.unknownConfiguration(ruleID: ImplicitReturnRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ImplicitReturnRule.description.identifier)) { try configuration.apply(configuration: config) } } diff --git a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift index bfffed210f..1ce962efcb 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift @@ -39,7 +39,7 @@ class ImplicitlyUnwrappedOptionalConfigurationTests: SwiftLintTestCase { mode: .allExceptIBOutlets ) - checkError(Issue.unknownConfiguration(ruleID: ImplicitlyUnwrappedOptionalRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ImplicitlyUnwrappedOptionalRule.description.identifier)) { try configuration.apply(configuration: badConfig) } } diff --git a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift index 6dc803762f..6fdf3f1b37 100644 --- a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift @@ -65,7 +65,7 @@ class NameConfigurationTests: SwiftLintTestCase { minLengthError: 0, maxLengthWarning: 0, maxLengthError: 0) - checkError(Issue.unknownConfiguration(ruleID: RuleMock.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: RuleMock.description.identifier)) { try nameConfig.apply(configuration: config) } } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift index 51407fd0d8..f171e7c83a 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift @@ -76,7 +76,7 @@ class RuleConfigurationTests: SwiftLintTestCase { func testSeverityConfigurationThrowsOnBadConfig() { let config = "foo" var severityConfig = SeverityConfiguration(.warning) - checkError(Issue.unknownConfiguration(ruleID: RuleMock.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: RuleMock.description.identifier)) { try severityConfig.apply(configuration: config) } } @@ -107,7 +107,7 @@ class RuleConfigurationTests: SwiftLintTestCase { func testRegexConfigurationThrows() { let config = 17 var regexConfig = RegexConfiguration(identifier: "") - checkError(Issue.unknownConfiguration(ruleID: RuleMock.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: RuleMock.description.identifier)) { try regexConfig.apply(configuration: config) } } @@ -311,7 +311,7 @@ class RuleConfigurationTests: SwiftLintTestCase { var configuration = ModifierOrderConfiguration() let config = ["severity": "warning", "preferred_modifier_order": ["specialize"]] as [String: any Sendable] - checkError(Issue.unknownConfiguration(ruleID: ModifierOrderRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ModifierOrderRule.description.identifier)) { try configuration.apply(configuration: config) } } @@ -319,7 +319,7 @@ class RuleConfigurationTests: SwiftLintTestCase { func testModifierOrderConfigurationThrowsOnNonModifiableGroup() { var configuration = ModifierOrderConfiguration() let config = ["severity": "warning", "preferred_modifier_order": ["atPrefixed"]] as [String: any Sendable] - checkError(Issue.unknownConfiguration(ruleID: ModifierOrderRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ModifierOrderRule.description.identifier)) { try configuration.apply(configuration: config) } } From e6bb6734444c1ff7ee17033b8ea6cc40a47e7fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 23 Mar 2024 19:44:34 +0100 Subject: [PATCH 015/265] Handle issues in nested contexts gracefully while still throwing standalone Use different issues to make inlineable configurations work in both scenarios, namely being used standalone and nested as part of another configuration. In the latter case, finding no values to parse in a raw configuration is okay, while as a standalone configuration it's not. --- Source/SwiftLintCore/Models/Issue.swift | 5 +++++ .../SwiftLintCore/Models/SeverityConfiguration.swift | 4 +++- .../SeverityLevelsConfiguration.swift | 6 ++++-- .../SwiftLintCoreMacros/RuleConfigurationMacros.swift | 9 +++++++-- Tests/MacroTests/AutoApplyTests.swift | 4 ++++ .../RuleConfigurationTests.swift | 11 ++++++----- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 12fbb39e8d..26ff56ef8e 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -5,6 +5,9 @@ public enum Issue: LocalizedError, Equatable { /// The configuration didn't match internal expectations. case invalidConfiguration(ruleID: String) + /// Used in configuration parsing when no changes have been applied. Use only internally! + case nothingApplied(ruleID: String) + /// Rule is listed multiple times in the configuration. case listedMultipleTime(ruleID: String, times: Int) @@ -91,6 +94,8 @@ public enum Issue: LocalizedError, Equatable { switch self { case let .invalidConfiguration(id): return "Invalid configuration for '\(id)' rule. Falling back to default." + case let .nothingApplied(ruleID: id): + return Self.invalidConfiguration(ruleID: id).message case let .listedMultipleTime(id, times): return "'\(id)' is listed \(times) times in the configuration." case let .renamedIdentifier(old, new): diff --git a/Source/SwiftLintCore/Models/SeverityConfiguration.swift b/Source/SwiftLintCore/Models/SeverityConfiguration.swift index e8038af660..3dfea575c9 100644 --- a/Source/SwiftLintCore/Models/SeverityConfiguration.swift +++ b/Source/SwiftLintCore/Models/SeverityConfiguration.swift @@ -26,8 +26,10 @@ public struct SeverityConfiguration: SeverityBasedRuleConfiguratio if let severity = ViolationSeverity(rawValue: severityString.lowercased()) { self.severity = severity } else { - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } + } else { + throw Issue.nothingApplied(ruleID: Parent.identifier) } } } diff --git a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift index 688abc290c..1e6e2c7937 100644 --- a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift @@ -34,7 +34,7 @@ public struct SeverityLevelsConfiguration: RuleConfiguration, Inli if let warning = warningValue as? Int { self.warning = warning } else { - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } } if let errorValue = configDict[$error.key] { @@ -43,11 +43,13 @@ public struct SeverityLevelsConfiguration: RuleConfiguration, Inli } else if let error = errorValue as? Int { self.error = error } else { - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } } else { self.error = nil } + } else { + throw Issue.nothingApplied(ruleID: Parent.identifier) } } } diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index 40b324e941..92da708016 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -3,6 +3,7 @@ import SwiftSyntax import SwiftSyntaxMacros enum AutoApply: MemberMacro { + // swiftlint:disable:next function_body_length static func expansion( of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, @@ -35,8 +36,12 @@ enum AutoApply: MemberMacro { } let inlinedOptionsUpdate = elementNames[firstIndexWithoutKey...].map { """ - try \($0).apply(configuration, ruleID: Parent.identifier) - try $\($0).performAfterParseOperations() + do { + try \($0).apply(configuration, ruleID: Parent.identifier) + try $\($0).performAfterParseOperations() + } catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) { + // Acceptable. Continue. + } """ } let nonInlinedOptionsUpdate = elementNames[..(.error) - try severityConfig.apply(configuration: config) - XCTAssertEqual(severityConfig.severity, .error) + checkError(Issue.nothingApplied(ruleID: RuleMock.identifier)) { + try severityConfig.apply(configuration: config) + } } - func testSeverityConfigurationThrowsOnBadConfig() { + func testSeverityConfigurationThrowsInvalidConfiguration() { let config = "foo" var severityConfig = SeverityConfiguration(.warning) - checkError(Issue.invalidConfiguration(ruleID: RuleMock.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: RuleMock.identifier)) { try severityConfig.apply(configuration: config) } } From dfa7f2fd4d3065140dec82313f5df54cdf9e1adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 24 Mar 2024 10:04:36 +0100 Subject: [PATCH 016/265] Use result builder to fix indentation (#5507) --- .../RuleConfigurationMacros.swift | 58 ++++++++++--------- Tests/MacroTests/AutoApplyTests.swift | 15 ++--- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index 92da708016..7767063454 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -1,5 +1,6 @@ import Foundation import SwiftSyntax +import SwiftSyntaxBuilder import SwiftSyntaxMacros enum AutoApply: MemberMacro { @@ -34,41 +35,46 @@ enum AutoApply: MemberMacro { let elementNames = annotatedVarDecls.compactMap { $0.0.bindings.first?.pattern.as(IdentifierPatternSyntax.self)?.identifier.text } - let inlinedOptionsUpdate = elementNames[firstIndexWithoutKey...].map { - """ - do { - try \($0).apply(configuration, ruleID: Parent.identifier) - try $\($0).performAfterParseOperations() - } catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) { - // Acceptable. Continue. - } - """ - } - let nonInlinedOptionsUpdate = elementNames[.. Date: Mon, 25 Mar 2024 20:39:22 +0000 Subject: [PATCH 017/265] Fix warnings about configured rules that are not enabled, when they are enabled in a parent config (#4864) --- CHANGELOG.md | 11 +- .../Extensions/Configuration+FileGraph.swift | 1 + .../Extensions/Configuration+Merging.swift | 2 +- .../Extensions/Configuration+Parsing.swift | 111 ++++++++++++-- .../Extensions/Configuration+RulesMode.swift | 2 +- .../SwiftLintCore/Models/Configuration.swift | 3 +- Source/SwiftLintCore/Models/Issue.swift | 29 ++++ .../ConfigurationTests+MultipleConfigs.swift | 143 ++++++++++++++++-- 8 files changed, 272 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 185efe4076..a0a222d6d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,8 +119,8 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5418](https://github.com/realm/SwiftLint/pull/5418) -* Add new `non_optional_string_data_conversion` rule to enforce - non-failable conversions of UTF-8 `String` <-> `Data`. +* Add new `non_optional_string_data_conversion` rule to enforce + non-failable conversions of UTF-8 `String` <-> `Data`. [Ben P](https://github.com/ben-p-commits) [#5263](https://github.com/realm/SwiftLint/issues/5263) @@ -194,7 +194,7 @@ are defined in a tuple like `let (a, b) = (5, 10)` or `let a = (2, 3)`. [Martin Redington](https://github.com/mildm8nnered) [#5305](https://github.com/realm/SwiftLint/pull/5305) - + * Silence `pattern_matching_keywords` rule when an identifier is referenced in the argument list of a matching enum case. [SimplyDanny](https://github.com/SimplyDanny) @@ -203,6 +203,11 @@ * Don't trigger the `return_value_from_void_function` warning from initializers. [mrbkap](https://github.com/mrbkap) +* Fixes superfluous warnings about configurations for rules that were not + enabled, when the rules were enabled in a parent configuration. + [Martin Redington](https://github.com/mildm8nnered) + [#4858](https://github.com/realm/SwiftLint/issues/4858) + ## 0.54.0: Macro-Economic Forces #### Breaking diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift index 6193feca49..379b6cfcd8 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift @@ -273,6 +273,7 @@ package extension Configuration { // Build succeeding configurations return try configurationData.reduce(firstConfiguration) { var childConfiguration = try Configuration( + parentConfiguration: $0, dict: $1.configurationDict, enableAllRules: enableAllRules, cachePath: cachePath diff --git a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift index 45a871873a..0273b25ea2 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift @@ -8,7 +8,7 @@ extension Configuration { // MARK: - Methods: Merging package func merged( withChild childConfiguration: Configuration, - rootDirectory: String + rootDirectory: String = "" ) -> Configuration { let mergedIncludedAndExcluded = self.mergedIncludedAndExcluded( with: childConfiguration, diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 0b06fbc495..5040ef8500 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -27,6 +27,7 @@ extension Configuration { // MARK: - Initializers /// Creates a Configuration value based on the specified parameters. /// + /// - parameter parentConfiguration: The parent configuration, if any. /// - parameter dict: The untyped dictionary to serve as the input for this typed configuration. /// Typically generated from a YAML-formatted file. /// - parameter ruleList: The list of rules to be available to this configuration. @@ -34,6 +35,7 @@ extension Configuration { /// settings in `dict`. /// - parameter cachePath: The location of the persisted cache on disk. public init( + parentConfiguration: Configuration? = nil, dict: [String: Any], ruleList: RuleList = RuleRegistry.shared.list, enableAllRules: Bool = false, @@ -75,7 +77,10 @@ extension Configuration { ) Self.validateConfiguredRulesAreEnabled( - configurationDictionary: dict, ruleList: ruleList, rulesMode: rulesMode + parentConfiguration: parentConfiguration, + configurationDictionary: dict, + ruleList: ruleList, + rulesMode: rulesMode ) self.init( @@ -147,35 +152,115 @@ extension Configuration { } private static func validateConfiguredRulesAreEnabled( + parentConfiguration: Configuration?, configurationDictionary dict: [String: Any], ruleList: RuleList, rulesMode: RulesMode ) { for key in dict.keys where !validGlobalKeys.contains(key) { guard let identifier = ruleList.identifier(for: key), - let rule = ruleList.list[identifier] else { + let ruleType = ruleList.list[identifier] else { continue } - let message = "Found a configuration for '\(identifier)' rule" - switch rulesMode { case .allEnabled: return - case .only(let onlyRules): - if Set(onlyRules).isDisjoint(with: rule.description.allIdentifiers) { - Issue.genericWarning("\(message), but it is not present on '\(Key.onlyRules.rawValue)'.").print() - } - + let issue = validateConfiguredRuleIsEnabled(onlyRules: onlyRules, ruleType: ruleType) + issue?.print() case let .default(disabled: disabledRules, optIn: optInRules): - if rule is any OptInRule.Type, Set(optInRules).isDisjoint(with: rule.description.allIdentifiers) { - Issue.genericWarning("\(message), but it is not enabled on '\(Key.optInRules.rawValue)'.").print() - } else if Set(disabledRules).isSuperset(of: rule.description.allIdentifiers) { - Issue.genericWarning("\(message), but it is disabled on '\(Key.disabledRules.rawValue)'.").print() + let issue = validateConfiguredRuleIsEnabled( + parentConfiguration: parentConfiguration, + disabledRules: disabledRules, + optInRules: optInRules, + ruleType: ruleType + ) + issue?.print() + } + } + } + + static func validateConfiguredRuleIsEnabled( + parentConfiguration: Configuration?, + disabledRules: Set, + optInRules: Set, + ruleType: any Rule.Type + ) -> Issue? { + var enabledInParentRules: Set = [] + var disabledInParentRules: Set = [] + var allEnabledRules: Set = [] + + if case .only(let onlyRules) = parentConfiguration?.rulesMode { + enabledInParentRules = onlyRules + } else if case .default(let parentDisabledRules, let parentOptInRules) = parentConfiguration?.rulesMode { + enabledInParentRules = parentOptInRules + disabledInParentRules = parentDisabledRules + } + allEnabledRules = enabledInParentRules + .subtracting(disabledInParentRules) + .union(optInRules) + .subtracting(disabledRules) + + return validateConfiguredRuleIsEnabled( + parentConfiguration: parentConfiguration, + enabledInParentRules: enabledInParentRules, + disabledInParentRules: disabledInParentRules, + disabledRules: disabledRules, + optInRules: optInRules, + allEnabledRules: allEnabledRules, + ruleType: ruleType + ) + } + + static func validateConfiguredRuleIsEnabled( + onlyRules: Set, + ruleType: any Rule.Type + ) -> Issue? { + if onlyRules.isDisjoint(with: ruleType.description.allIdentifiers) { + return Issue.ruleNotPresentInOnlyRules(ruleID: ruleType.identifier) + } + return nil + } + + // swiftlint:disable:next function_parameter_count + static func validateConfiguredRuleIsEnabled( + parentConfiguration: Configuration?, + enabledInParentRules: Set, + disabledInParentRules: Set, + disabledRules: Set, + optInRules: Set, + allEnabledRules: Set, + ruleType: any Rule.Type + ) -> Issue? { + if case .allEnabled = parentConfiguration?.rulesMode { + if disabledRules.contains(ruleType.identifier) { + return Issue.ruleDisabledInDisabledRules(ruleID: ruleType.identifier) + } + return nil + } + + let allIdentifiers = ruleType.description.allIdentifiers + + if allEnabledRules.isDisjoint(with: allIdentifiers) { + if !disabledRules.isDisjoint(with: allIdentifiers) { + return Issue.ruleDisabledInDisabledRules(ruleID: ruleType.identifier) + } + if !disabledInParentRules.isDisjoint(with: allIdentifiers) { + return Issue.ruleDisabledInParentConfiguration(ruleID: ruleType.identifier) + } + + if ruleType is any OptInRule.Type { + if enabledInParentRules.union(optInRules).isDisjoint(with: allIdentifiers) { + return Issue.ruleNotEnabledInOptInRules(ruleID: ruleType.identifier) } + } else if case .only(let enabledInParentRules) = parentConfiguration?.rulesMode, + enabledInParentRules.isDisjoint(with: allIdentifiers) { + return Issue.ruleNotEnabledInParentOnlyRules(ruleID: ruleType.identifier) } } + + return nil } private static func warnAboutMisplacedAnalyzerRules(optInRules: [String], ruleList: RuleList) { diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift index 941cb7e124..0bc021705c 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift @@ -17,7 +17,7 @@ public extension Configuration { } /// Represents how a Configuration object can be configured with regards to rules. - enum RulesMode { + enum RulesMode: Equatable { /// The default rules mode, which will enable all rules that aren't defined as being opt-in /// (conforming to the `OptInRule` protocol), minus the rules listed in `disabled`, plus the rules listed in /// `optIn`. diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 1ee5344b70..fe7db20701 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -285,7 +285,8 @@ extension Configuration: Hashable { lhs.rules == rhs.rules && lhs.fileGraph == rhs.fileGraph && lhs.allowZeroLintableFiles == rhs.allowZeroLintableFiles && - lhs.strict == rhs.strict + lhs.strict == rhs.strict && + lhs.rulesMode == rhs.rulesMode } } diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 26ff56ef8e..cb2cbc2471 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -20,6 +20,21 @@ public enum Issue: LocalizedError, Equatable { /// Used rule IDs are invalid. case invalidRuleIDs(Set) + /// Found a rule configuration for a rule that is not present in `only_rules`. + case ruleNotPresentInOnlyRules(ruleID: String) + + /// Found a rule configuration for a rule that is disabled. + case ruleDisabledInDisabledRules(ruleID: String) + + /// Found a rule configuration for a rule that is disabled in the parent configuration. + case ruleDisabledInParentConfiguration(ruleID: String) + + /// Found a rule configuration for a rule that is not enabled in `opt_in_rules`. + case ruleNotEnabledInOptInRules(ruleID: String) + + /// Found a rule configuration for a rule that is not enabled in parent `only_rules`. + case ruleNotEnabledInParentOnlyRules(ruleID: String) + /// A generic warning specified by a string. case genericWarning(String) @@ -104,6 +119,20 @@ public enum Issue: LocalizedError, Equatable { return "Configuration for '\(id)' rule contains the invalid key(s) \(keys.formatted)." case let .invalidRuleIDs(ruleIDs): return "The key(s) \(ruleIDs.formatted) used as rule identifier(s) is/are invalid." + case let .ruleNotPresentInOnlyRules(id): + return "Found a configuration for '\(id)' rule, but it is not present in " + + "'\(Configuration.Key.onlyRules.rawValue)'." + case let .ruleDisabledInDisabledRules(id): + return "Found a configuration for '\(id)' rule, but it is disabled in " + + "'\(Configuration.Key.disabledRules.rawValue)'." + case let .ruleDisabledInParentConfiguration(id): + return "Found a configuration for '\(id)' rule, but it is disabled in a parent configuration." + case let .ruleNotEnabledInOptInRules(id): + return "Found a configuration for '\(id)' rule, but it is not enabled in " + + "'\(Configuration.Key.optInRules.rawValue)'." + case let .ruleNotEnabledInParentOnlyRules(id): + return "Found a configuration for '\(id)' rule, but it is not present in the parent's " + + "'\(Configuration.Key.onlyRules.rawValue)'." case let .genericWarning(message), let .genericError(message): return message case let .ruleDeprecated(id): diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index 10cf217fbc..d0220008a3 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -13,7 +13,7 @@ private extension Configuration { extension ConfigurationTests { // MARK: - Rules Merging func testMerge() { - let config0Merge2 = Mock.Config._0.merged(withChild: Mock.Config._2, rootDirectory: "") + let config0Merge2 = Mock.Config._0.merged(withChild: Mock.Config._2) XCTAssertFalse(Mock.Config._0.contains(rule: ForceCastRule.self)) XCTAssertTrue(Mock.Config._2.contains(rule: ForceCastRule.self)) @@ -25,7 +25,7 @@ extension ConfigurationTests { XCTAssertFalse(Mock.Config._3.contains(rule: TodoRule.self)) XCTAssertFalse( - config0Merge2.merged(withChild: Mock.Config._3, rootDirectory: "").contains(rule: TodoRule.self) + config0Merge2.merged(withChild: Mock.Config._3).contains(rule: TodoRule.self) ) } @@ -38,16 +38,16 @@ extension ConfigurationTests { ) } XCTAssertEqual(configuration(forWarningThreshold: 3) - .merged(withChild: configuration(forWarningThreshold: 2), rootDirectory: "").warningThreshold, + .merged(withChild: configuration(forWarningThreshold: 2)).warningThreshold, 2) XCTAssertEqual(configuration(forWarningThreshold: nil) - .merged(withChild: configuration(forWarningThreshold: 2), rootDirectory: "").warningThreshold, + .merged(withChild: configuration(forWarningThreshold: 2)).warningThreshold, 2) XCTAssertEqual(configuration(forWarningThreshold: 3) - .merged(withChild: configuration(forWarningThreshold: nil), rootDirectory: "").warningThreshold, + .merged(withChild: configuration(forWarningThreshold: nil)).warningThreshold, 3) XCTAssertNil(configuration(forWarningThreshold: nil) - .merged(withChild: configuration(forWarningThreshold: nil), rootDirectory: "").warningThreshold) + .merged(withChild: configuration(forWarningThreshold: nil)).warningThreshold) } func testOnlyRulesMerging() { @@ -59,12 +59,12 @@ extension ConfigurationTests { XCTAssertEqual(onlyConfiguration.rules.count, 1) XCTAssertTrue(onlyConfiguration.rules[0] is TodoRule) - let mergedConfiguration1 = baseConfiguration.merged(withChild: onlyConfiguration, rootDirectory: "") + let mergedConfiguration1 = baseConfiguration.merged(withChild: onlyConfiguration) XCTAssertEqual(mergedConfiguration1.rules.count, 1) XCTAssertTrue(mergedConfiguration1.rules[0] is TodoRule) // Also test the other way around - let mergedConfiguration2 = onlyConfiguration.merged(withChild: baseConfiguration, rootDirectory: "") + let mergedConfiguration2 = onlyConfiguration.merged(withChild: baseConfiguration) XCTAssertEqual(mergedConfiguration2.rules.count, 3) // 2 opt-ins + 1 from the only rules XCTAssertTrue(mergedConfiguration2.contains(rule: TodoRule.self)) XCTAssertTrue(mergedConfiguration2.contains(rule: ForceCastRule.self)) @@ -347,7 +347,7 @@ extension ConfigurationTests { disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: testCase.optedInInChild ? [ruleIdentifier] : [] )) - let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration, rootDirectory: "") + let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration) let isEnabled = mergedConfiguration.contains(rule: ruleType) XCTAssertEqual(isEnabled, testCase.isEnabled, testCase.message) } @@ -379,7 +379,7 @@ extension ConfigurationTests { let childConfiguration = Configuration( rulesMode: .default(disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: []) ) - let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration, rootDirectory: "") + let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration) let isEnabled = mergedConfiguration.contains(rule: ruleType) XCTAssertEqual(isEnabled, testCase.isEnabled, testCase.message) } @@ -410,12 +410,113 @@ extension ConfigurationTests { disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: testCase.optedInInChild ? [ruleIdentifier] : [] )) - let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration, rootDirectory: "") + let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration) let isEnabled = mergedConfiguration.contains(rule: ruleType) XCTAssertEqual(isEnabled, testCase.isEnabled, testCase.message) } } + // MARK: Warnings about configurations for disabled rules + func testDefaultConfigurationDisabledRuleWarnings() { + let optInRuleType = ImplicitReturnRule.self + XCTAssertTrue((optInRuleType as Any) is any OptInRule.Type) + testDefaultConfigurationDisabledRuleWarnings(for: optInRuleType) + + let defaultRuleType = BlockBasedKVORule.self + XCTAssertFalse((defaultRuleType as Any) is any OptInRule.Type) + testDefaultConfigurationDisabledRuleWarnings(for: defaultRuleType) + } + + private func testDefaultConfigurationDisabledRuleWarnings(for ruleType: any Rule.Type) { + let ruleIdentifier = ruleType.identifier + + let parentConfigurations = [ + nil, + Configuration.emptyDefaultConfiguration(), + Configuration.optInDefaultConfiguration(ruleIdentifier), + Configuration.optInDisabledDefaultConfiguration(ruleIdentifier), + Configuration.disabledDefaultConfiguration(ruleIdentifier), + Configuration.emptyOnlyConfiguration(), + Configuration.enabledOnlyConfiguration(ruleIdentifier), + Configuration.allEnabledConfiguration() + ] + + let configurations = [ + Configuration(rulesMode: .default(disabled: [], optIn: [])), + Configuration(rulesMode: .default(disabled: [], optIn: [ruleIdentifier])), + Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [ruleIdentifier])), + Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [])) + ] + + for parentConfiguration in parentConfigurations { + for configuration in configurations { + testParentConfiguration(parentConfiguration, configuration: configuration, ruleType: ruleType) + } + } + } + + private func testParentConfiguration( + _ parentConfiguration: Configuration?, + configuration: Configuration, + ruleType: any Rule.Type + ) { + guard case .default(let disabledRules, let optInRules) = configuration.rulesMode else { + XCTFail("Configuration rulesMode was not the default") + return + } + + let mergedConfiguration = parentConfiguration?.merged(withChild: configuration) ?? configuration + let isEnabled = mergedConfiguration.contains(rule: ruleType) + let issue = Configuration.validateConfiguredRuleIsEnabled( + parentConfiguration: parentConfiguration, + disabledRules: disabledRules, + optInRules: optInRules, + ruleType: ruleType + ) + XCTAssertEqual(isEnabled, issue == nil) + guard let issue else { + return + } + let ruleIdentifier = ruleType.identifier + + guard disabledRules.isEmpty, optInRules.isEmpty else { + XCTAssertEqual(issue, Issue.ruleDisabledInDisabledRules(ruleID: ruleIdentifier)) + return + } + + if parentConfiguration == nil || + parentConfiguration == Configuration.emptyDefaultConfiguration() { + XCTAssertEqual(issue, Issue.ruleNotEnabledInOptInRules(ruleID: ruleIdentifier)) + } else if parentConfiguration == Configuration.emptyOnlyConfiguration() { + if ruleType is any OptInRule.Type { + XCTAssertEqual(issue, Issue.ruleNotEnabledInOptInRules(ruleID: ruleIdentifier)) + } else { + XCTAssertEqual(issue, Issue.ruleNotEnabledInParentOnlyRules(ruleID: ruleIdentifier)) + } + } else if parentConfiguration == Configuration.optInDisabledDefaultConfiguration(ruleIdentifier) || + parentConfiguration == Configuration.disabledDefaultConfiguration(ruleIdentifier) { + XCTAssertEqual(issue, Issue.ruleDisabledInParentConfiguration(ruleID: ruleIdentifier)) + } + } + + func testOnlyConfigurationDisabledRulesWarnings() { + let optInRuleType = ImplicitReturnRule.self + XCTAssertTrue((optInRuleType as Any) is any OptInRule.Type) + testOnlyConfigurationDisabledRulesWarnings(ruleType: optInRuleType) + + let defaultRuleType = BlockBasedKVORule.self + XCTAssertFalse((defaultRuleType as Any) is any OptInRule.Type) + testOnlyConfigurationDisabledRulesWarnings(ruleType: defaultRuleType) + } + + private func testOnlyConfigurationDisabledRulesWarnings(ruleType: any Rule.Type) { + let issue = Configuration.validateConfiguredRuleIsEnabled(onlyRules: [], ruleType: ruleType) + XCTAssertEqual(issue, Issue.ruleNotPresentInOnlyRules(ruleID: ruleType.identifier)) + XCTAssertNil( + Configuration.validateConfiguredRuleIsEnabled(onlyRules: [ruleType.identifier], ruleType: ruleType) + ) + } + // MARK: - Remote Configs func testValidRemoteChildConfig() { FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigChild) @@ -523,3 +624,23 @@ extension ConfigurationTests { XCTAssertEqual(Set(configuration1.excludedPaths), Set(configuration2.excludedPaths)) } } + +private extension Configuration { + static func emptyDefaultConfiguration() -> Self { + Configuration(rulesMode: .default(disabled: [], optIn: [])) + } + static func optInDefaultConfiguration(_ ruleIdentifier: String) -> Self { + Configuration(rulesMode: .default(disabled: [], optIn: [ruleIdentifier])) + } + static func optInDisabledDefaultConfiguration(_ ruleIdentifier: String) -> Self { + Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [ruleIdentifier])) + } + static func disabledDefaultConfiguration(_ ruleIdentifier: String) -> Self { + Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [])) + } + static func emptyOnlyConfiguration() -> Self { Configuration(rulesMode: .only([])) } + static func enabledOnlyConfiguration(_ ruleIdentifier: String) -> Self { + Configuration(rulesMode: .only([ruleIdentifier])) + } + static func allEnabledConfiguration() -> Self { Configuration(rulesMode: .allEnabled)} +} From 299042a2333007cfdd95085567674cf87f01b0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 25 Mar 2024 21:40:56 +0100 Subject: [PATCH 018/265] Allow to configure only severity in a short form for every rule with a severity (#5509) The README states that a configuration like `attributes: error` is valid to only set a different severity level for a rule (the `attributes` rule here). This was previously only possible for rules that were accompanied by a plain severity configuration. I don't think this broke with the automatic parsing code generation. For some rules it might have worked before, for others not. This change makes it consistently working for all rules. --- CHANGELOG.md | 5 + .../RuleConfigurationMacros.swift | 29 +++-- .../SwiftLintCoreMacros.swift | 3 + Tests/MacroTests/AutoApplyTests.swift | 112 +++++++++++++++--- .../RuleConfigurationDescriptionTests.swift | 2 +- .../RuleConfigurationTests.swift | 7 ++ 6 files changed, 135 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0a222d6d2..77fddc3f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,11 @@ [Julien Baillon](https://github.com/julien-baillon) [#5372](https://github.com/realm/SwiftLint/issues/5372) +* Allow to set the severity of rules (if they have one) in the short form + `rule_name: warning|error` provided that no other attributes need to be + configured. + [SimplyDanny](https://github.com/SimplyDanny) + * Add new `ignore_one_liners` option to `switch_case_alignment` rule to ignore switch statements written in a single line. [tonell-m](https://github.com/tonell-m) diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index 7767063454..029d449f0b 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -35,9 +35,27 @@ enum AutoApply: MemberMacro { let elementNames = annotatedVarDecls.compactMap { $0.0.bindings.first?.pattern.as(IdentifierPatternSyntax.self)?.identifier.text } + let nonInlinedOptions = elementNames[..(.warning) From 1c0d28fd0debeb72134e586b6b031167dd2d5fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 26 Mar 2024 19:07:39 +0100 Subject: [PATCH 019/265] Compare rule IDs and configurations with reference (#5510) This new test ensures that rule IDs and their option names do not get changed inadvertently. The file can easily be updated by running: ```bash swift run swiftlint rules --config-only --default-config > Tests/IntegrationTests/default_rule_configurations.yml ``` --- Package.swift | 3 + Tests/BUILD | 5 +- Tests/IntegrationTests/IntegrationTests.swift | 17 + .../default_rule_configurations.yml | 631 ++++++++++++++++++ 4 files changed, 655 insertions(+), 1 deletion(-) create mode 100644 Tests/IntegrationTests/default_rule_configurations.yml diff --git a/Package.swift b/Package.swift index 2fd4bc541a..73a30a47ca 100644 --- a/Package.swift +++ b/Package.swift @@ -131,6 +131,9 @@ let package = Package( "SwiftLintFramework", "SwiftLintTestHelpers" ], + exclude: [ + "default_rule_configurations.yml" + ], swiftSettings: swiftFeatures ), .testTarget( diff --git a/Tests/BUILD b/Tests/BUILD index 9da3ceebdc..509bce099d 100644 --- a/Tests/BUILD +++ b/Tests/BUILD @@ -141,7 +141,10 @@ swift_library( swift_test( name = "IntegrationTests", - data = ["//:LintInputs"], + data = [ + "//:LintInputs", + "IntegrationTests/default_rule_configurations.yml" + ], visibility = ["//visibility:public"], deps = [":IntegrationTests.library"], ) diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index 8efc30b891..2f99ce541b 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -53,6 +53,23 @@ class IntegrationTests: SwiftLintTestCase { } } + func testDefaultConfigurations() { + let defaultConfig = Configuration(rulesMode: .allEnabled).rules + .map { type(of: $0) } + .filter { $0.identifier != "custom_rules" } + .map { + """ + \($0.identifier): + \($0.init().configurationDescription.yaml().indent(by: 2)) + """ + } + .joined(separator: "\n") + let referenceFile = URL(fileURLWithPath: #file) + .deletingLastPathComponent() + .appendingPathComponent("default_rule_configurations.yml") + XCTAssertEqual(defaultConfig + "\n", try String(contentsOf: referenceFile)) + } + func testSimulateHomebrewTest() { // Since this test uses the `swiftlint` binary built while building `SwiftLintPackageTests`, // we run it only on macOS using SwiftPM. diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml new file mode 100644 index 0000000000..7607bb6ab0 --- /dev/null +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -0,0 +1,631 @@ +accessibility_label_for_image: + severity: warning +accessibility_trait_for_button: + severity: warning +anonymous_argument_in_multiline_closure: + severity: warning +anyobject_protocol: + severity: warning +array_init: + severity: warning +attributes: + severity: warning + attributes_with_arguments_always_on_line_above: true + always_on_same_line: ["@IBAction", "@NSManaged"] + always_on_line_above: [] +balanced_xctest_lifecycle: + severity: warning + test_parent_classes: ["QuickSpec", "XCTestCase"] +blanket_disable_command: + severity: warning + allowed_rules: ["file_header", "file_length", "file_name", "file_name_no_space", "single_test_class"] + always_blanket_disable: [] +block_based_kvo: + severity: warning +capture_variable: + severity: warning +class_delegate_protocol: + severity: warning +closing_brace: + severity: warning +closure_body_length: + warning: 30 + error: 100 +closure_end_indentation: + severity: warning +closure_parameter_position: + severity: warning +closure_spacing: + severity: warning +collection_alignment: + severity: warning + align_colons: false +colon: + severity: warning + flexible_right_spacing: false + apply_to_dictionaries: true +comma: + severity: warning +comma_inheritance: + severity: warning +comment_spacing: + severity: warning +compiler_protocol_init: + severity: warning +computed_accessors_order: + severity: warning + order: get_set +conditional_returns_on_newline: + severity: warning + if_only: false +contains_over_filter_count: + severity: warning +contains_over_filter_is_empty: + severity: warning +contains_over_first_not_nil: + severity: warning +contains_over_range_nil_comparison: + severity: warning +control_statement: + severity: warning +convenience_type: + severity: warning +cyclomatic_complexity: + warning: 10 + error: 20 + ignores_case_statements: false +deployment_target: + severity: warning + iOSApplicationExtension_deployment_target: 7.0 + iOS_deployment_target: 7.0 + macOSApplicationExtension_deployment_target: 10.9 + macOS_deployment_target: 10.9 + tvOSApplicationExtension_deployment_target: 9.0 + tvOS_deployment_target: 9.0 + watchOSApplicationExtension_deployment_target: 1.0 + watchOS_deployment_target: 1.0 +direct_return: + severity: warning +discarded_notification_center_observer: + severity: warning +discouraged_assert: + severity: warning +discouraged_direct_init: + severity: warning + types: ["Bundle", "Bundle.init", "NSError", "NSError.init", "UIDevice", "UIDevice.init"] +discouraged_none_name: + severity: warning +discouraged_object_literal: + severity: warning + image_literal: true + color_literal: true +discouraged_optional_boolean: + severity: warning +discouraged_optional_collection: + severity: warning +duplicate_conditions: + severity: error +duplicate_enum_cases: + severity: error +duplicate_imports: + severity: warning +duplicated_key_in_dictionary_literal: + severity: warning +dynamic_inline: + severity: error +empty_collection_literal: + severity: warning +empty_count: + severity: error + only_after_dot: false +empty_enum_arguments: + severity: warning +empty_parameters: + severity: warning +empty_parentheses_with_trailing_closure: + severity: warning +empty_string: + severity: warning +empty_xctest_method: + severity: warning + test_parent_classes: ["QuickSpec", "XCTestCase"] +enum_case_associated_values_count: + warning: 5 + error: 6 +expiring_todo: + approaching_expiry_severity: warning + expired_severity: error + bad_formatting_severity: error + approaching_expiry_threshold: 15 + date_delimiters: + opening: "[" + closing: "]" + date_format: "MM/dd/yyyy" + date_separator: "/" +explicit_acl: + severity: warning +explicit_enum_raw_value: + severity: warning +explicit_init: + severity: warning + include_bare_init: false +explicit_self: + severity: warning +explicit_top_level_acl: + severity: warning +explicit_type_interface: + severity: warning + excluded: [] + allow_redundancy: false +extension_access_modifier: + severity: warning +fallthrough: + severity: warning +fatal_error_message: + severity: warning +file_header: + severity: warning +file_length: + warning: 400 + error: 1000 + ignore_comment_only_lines: false +file_name: + severity: warning + excluded: ["LinuxMain.swift", "main.swift"] + prefix_pattern: "" + suffix_pattern: "\+.*" + nested_type_separator: "." +file_name_no_space: + severity: warning + excluded: [] +file_types_order: + severity: warning + order: [[supporting_type], [main_type], [extension], [preview_provider], [library_content_provider]] +final_test_case: + severity: warning + test_parent_classes: ["QuickSpec", "XCTestCase"] +first_where: + severity: warning +flatmap_over_map_reduce: + severity: warning +for_where: + severity: warning + allow_for_as_filter: false +force_cast: + severity: error +force_try: + severity: error +force_unwrapping: + severity: warning +function_body_length: + warning: 50 + error: 100 +function_default_parameter_at_end: + severity: warning +function_parameter_count: + warning: 5 + error: 8 + ignores_default_parameters: true +generic_type_name: + min_length: + warning: 1 + error: 0 + max_length: + warning: 20 + error: 1000 + excluded: [] + allowed_symbols: [] + unallowed_symbols_severity: error + validates_start_with_lowercase: error +ibinspectable_in_extension: + severity: warning +identical_operands: + severity: warning +identifier_name: + min_length: + warning: 3 + error: 2 + max_length: + warning: 40 + error: 60 + excluded: ["^id$"] + allowed_symbols: [] + unallowed_symbols_severity: error + validates_start_with_lowercase: error + additional_operators: ["!", "%", "&", "*", "+", "-", ".", "/", "<", "=", ">", "?", "^", "|", "~"] +implicit_getter: + severity: warning +implicit_return: + severity: warning + included: [closure, function, getter, initializer, subscript] +implicitly_unwrapped_optional: + severity: warning + mode: all_except_iboutlets +inclusive_language: + severity: warning +indentation_width: + severity: warning + indentation_width: 4 + include_comments: true + include_compiler_directives: true + include_multiline_strings: true +inert_defer: + severity: warning +invalid_swiftlint_command: + severity: warning +is_disjoint: + severity: warning +joined_default_parameter: + severity: warning +large_tuple: + warning: 2 + error: 3 +last_where: + severity: warning +leading_whitespace: + severity: warning +legacy_cggeometry_functions: + severity: warning +legacy_constant: + severity: warning +legacy_constructor: + severity: warning +legacy_hashing: + severity: warning +legacy_multiple: + severity: warning +legacy_nsgeometry_functions: + severity: warning +legacy_objc_type: + severity: warning +legacy_random: + severity: warning +let_var_whitespace: + severity: warning +line_length: + warning: 120 + error: 200 + ignores_urls: false + ignores_function_declarations: false + ignores_comments: false + ignores_interpolated_strings: false + excluded_lines_patterns: [] +literal_expression_end_indentation: + severity: warning +local_doc_comment: + severity: warning +lower_acl_than_parent: + severity: warning +mark: + severity: warning +missing_docs: + warning: [open, public] + excludes_extensions: true + excludes_inherited_types: true + excludes_trivial_init: false +modifier_order: + severity: warning + preferred_modifier_order: [override, acl, setterACL, dynamic, mutators, lazy, final, required, convenience, typeMethods, owned] +multiline_arguments: + severity: warning + first_argument_location: any_line + only_enforce_after_first_closure_on_first_line: false +multiline_arguments_brackets: + severity: warning +multiline_function_chains: + severity: warning +multiline_literal_brackets: + severity: warning +multiline_parameters: + severity: warning + allows_single_line: true +multiline_parameters_brackets: + severity: warning +multiple_closures_with_trailing_closure: + severity: warning +nesting: + type_level: + warning: 1 + function_level: + warning: 2 + check_nesting_in_closures_and_statements: true + always_allow_one_type_in_functions: false + ignore_typealiases_and_associatedtypes: false +nimble_operator: + severity: warning +no_extension_access_modifier: + severity: error +no_fallthrough_only: + severity: warning +no_grouping_extension: + severity: warning +no_magic_numbers: + severity: warning + test_parent_classes: ["QuickSpec", "XCTestCase"] +no_space_in_method_call: + severity: warning +non_optional_string_data_conversion: + severity: warning +non_overridable_class_declaration: + severity: warning + final_class_modifier: final class +notification_center_detachment: + severity: warning +ns_number_init_as_function_reference: + severity: warning +nslocalizedstring_key: + severity: warning +nslocalizedstring_require_bundle: + severity: warning +nsobject_prefer_isequal: + severity: warning +number_separator: + severity: warning + minimum_length: 0 + exclude_ranges: [] +object_literal: + severity: warning + image_literal: true + color_literal: true +one_declaration_per_file: + severity: warning +opening_brace: + severity: warning + allow_multiline_func: false +operator_usage_whitespace: + severity: warning + lines_look_around: 2 + skip_aligned_constants: true + allowed_no_space_operators: ["...", "..<"] +operator_whitespace: + severity: warning +optional_enum_case_matching: + severity: warning +orphaned_doc_comment: + severity: warning +overridden_super_call: + severity: warning + excluded: [] + included: ["*"] +override_in_extension: + severity: warning +pattern_matching_keywords: + severity: warning +period_spacing: + severity: warning +prefer_nimble: + severity: warning +prefer_self_in_static_references: + severity: warning +prefer_self_type_over_type_of_self: + severity: warning +prefer_zero_over_explicit_init: + severity: warning +prefixed_toplevel_constant: + severity: warning + only_private: false +private_action: + severity: warning +private_outlet: + severity: warning + allow_private_set: false +private_over_fileprivate: + severity: warning + validate_extensions: false +private_subject: + severity: warning +private_swiftui_state: + severity: warning +private_unit_test: + severity: warning + test_parent_classes: ["QuickSpec", "XCTestCase"] + regex: "XCTestCase" +prohibited_interface_builder: + severity: warning +prohibited_super_call: + severity: warning + excluded: [] + included: ["*"] +protocol_property_accessors_order: + severity: warning +quick_discouraged_call: + severity: warning +quick_discouraged_focused_test: + severity: warning +quick_discouraged_pending_test: + severity: warning +raw_value_for_camel_cased_codable_enum: + severity: warning +reduce_boolean: + severity: warning +reduce_into: + severity: warning +redundant_discardable_let: + severity: warning +redundant_nil_coalescing: + severity: warning +redundant_objc_attribute: + severity: warning +redundant_optional_initialization: + severity: warning +redundant_self_in_closure: + severity: warning +redundant_set_access_control: + severity: warning +redundant_string_enum_value: + severity: warning +redundant_type_annotation: + severity: warning +redundant_void_return: + severity: warning + include_closures: true +required_deinit: + severity: warning +required_enum_case: + {Protocol Name}: + {Case Name 1}: {warning|error} + {Case Name 2}: {warning|error} +return_arrow_whitespace: + severity: warning +return_value_from_void_function: + severity: warning +self_binding: + severity: warning + bind_identifier: "self" +self_in_property_initialization: + severity: warning +shorthand_argument: + severity: warning + allow_until_line_after_opening_brace: 4 + always_disallow_more_than_one: false + always_disallow_member_access: false +shorthand_operator: + severity: error +shorthand_optional_binding: + severity: warning +single_test_class: + severity: warning + test_parent_classes: ["QuickSpec", "XCTestCase"] +sorted_enum_cases: + severity: warning +sorted_first_last: + severity: warning +sorted_imports: + severity: warning + grouping: names +statement_position: + severity: warning + statement_mode: default +static_operator: + severity: warning +static_over_final_class: + severity: warning +strict_fileprivate: + severity: warning +strong_iboutlet: + severity: warning +superfluous_disable_command: + severity: warning +superfluous_else: + severity: warning +switch_case_alignment: + severity: warning + indented_cases: false + ignore_one_liners: false +switch_case_on_newline: + severity: warning +syntactic_sugar: + severity: warning +test_case_accessibility: + severity: warning + allowed_prefixes: [] + test_parent_classes: ["QuickSpec", "XCTestCase"] +todo: + severity: warning + only: [TODO, FIXME] +toggle_bool: + severity: warning +trailing_closure: + severity: warning + only_single_muted_parameter: false +trailing_comma: + severity: warning + mandatory_comma: false +trailing_newline: + severity: warning +trailing_semicolon: + severity: warning +trailing_whitespace: + severity: warning + ignores_empty_lines: false + ignores_comments: true +type_body_length: + warning: 250 + error: 350 +type_contents_order: + severity: warning + order: [[case], [type_alias, associated_type], [subtype], [type_property], [instance_property], [ib_inspectable], [ib_outlet], [initializer], [type_method], [view_life_cycle_method], [ib_action], [other_method], [subscript], [deinitializer]] +type_name: + min_length: + warning: 3 + error: 0 + max_length: + warning: 40 + error: 1000 + excluded: [] + allowed_symbols: [] + unallowed_symbols_severity: error + validates_start_with_lowercase: error + validate_protocols: true +typesafe_array_init: + severity: warning +unavailable_condition: + severity: warning +unavailable_function: + severity: warning +unhandled_throwing_task: + severity: error +unneeded_break_in_switch: + severity: warning +unneeded_override: + severity: warning + affect_initializers: false +unneeded_parentheses_in_closure_argument: + severity: warning +unneeded_synthesized_initializer: + severity: warning +unowned_variable_capture: + severity: warning +untyped_error_in_catch: + severity: warning +unused_capture_list: + severity: warning +unused_closure_parameter: + severity: warning +unused_control_flow_label: + severity: warning +unused_declaration: + severity: error + include_public_and_open: false + related_usrs_to_skip: ["s:7SwiftUI15PreviewProviderP"] +unused_enumerated: + severity: warning +unused_import: + severity: warning + require_explicit_imports: false + allowed_transitive_imports: [] + always_keep_imports: [] +unused_optional_binding: + severity: warning + ignore_optional_try: false +unused_setter_value: + severity: warning +valid_ibinspectable: + severity: warning +vertical_parameter_alignment: + severity: warning +vertical_parameter_alignment_on_call: + severity: warning +vertical_whitespace: + severity: warning + max_empty_lines: 1 +vertical_whitespace_between_cases: + severity: warning +vertical_whitespace_closing_braces: + severity: warning + only_enforce_before_trivial_lines: false +vertical_whitespace_opening_braces: + severity: warning +void_function_in_ternary: + severity: warning +void_return: + severity: warning +weak_delegate: + severity: warning +xct_specific_matcher: + severity: warning + matchers: [one-argument-asserts, two-argument-asserts] +xctfail_message: + severity: warning +yoda_condition: + severity: warning From 758c22e7cb3f60bc4da4f31dfa5a0815d1404756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 28 Mar 2024 00:08:59 +0100 Subject: [PATCH 020/265] Prohibit configuration key inference (#5513) While this is already implemented, it only works when a configuration is updated by calling `apply(configuration:)` on it somewhere. This imperceptible detail could lead to confusing. So better prohibit the use of the feature for the time being as long as a good solution is found. So far, no explicit configuration keys have been removed. --- .../SwiftLintCore/Models/RuleConfigurationDescription.swift | 5 +++-- .../RuleConfigurationDescriptionTests.swift | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index 3929aba064..d09de4729b 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -440,7 +440,7 @@ public struct ConfigurationElement Void = { _ in }) { self.init(wrappedValue: value, key: key, inline: false, postprocessor: postprocessor) @@ -454,7 +454,7 @@ public struct ConfigurationElement(key: String = "") where T == Wrapped? { + public init(key: String) where T == Wrapped? { self.init(wrappedValue: nil, key: key, inline: false) } @@ -466,6 +466,7 @@ public struct ConfigurationElement Date: Tue, 2 Apr 2024 08:34:17 +0100 Subject: [PATCH 021/265] Add `all` analyzer pseudo-rule (#5519) --- CHANGELOG.md | 6 ++++++ README.md | 3 ++- .../Extensions/Configuration+RulesMode.swift | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77fddc3f2c..5fc00ff80c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -213,6 +213,12 @@ [Martin Redington](https://github.com/mildm8nnered) [#4858](https://github.com/realm/SwiftLint/issues/4858) +* Add `all` pseudo-rule for `analyzer_rules` - enables all analyzer rules + that are not listed in `disabled_rules`. + [woxtu](https://github.com/woxtu) + [Martin Redington](https://github.com/mildm8nnered) + [#4999](https://github.com/realm/SwiftLint/issues/4999) + ## 0.54.0: Macro-Economic Forces #### Breaking diff --git a/README.md b/README.md index ae15b1c192..3abca7de11 100644 --- a/README.md +++ b/README.md @@ -535,7 +535,8 @@ Rule inclusion: * `analyzer_rules`: This is an entirely separate list of rules that are only run by the `analyze` command. All analyzer rules are opt-in, so this is the only configurable rule list, there are no equivalents for `disabled_rules` - `only_rules`. + and `only_rules`. The special `all` identifier can also be used here to enable + all analyzer rules, except the ones listed in `disabled_rules`. ```yaml # By default, SwiftLint uses a set of sensible default rules you can adjust: diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift index 0bc021705c..71de532588 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift @@ -72,8 +72,18 @@ public extension Configuration { effectiveOptInRules = optInRules } - warnAboutDuplicates(in: effectiveOptInRules + analyzerRules) - self = .default(disabled: Set(disabledRules), optIn: Set(effectiveOptInRules + analyzerRules)) + let effectiveAnalyzerRules: [String] + if analyzerRules.contains(RuleIdentifier.all.stringRepresentation) { + let allAnalyzerRules = RuleRegistry.shared.list.list.compactMap { ruleID, ruleType in + ruleType is any AnalyzerRule.Type ? ruleID : nil + } + effectiveAnalyzerRules = allAnalyzerRules + } else { + effectiveAnalyzerRules = analyzerRules + } + + warnAboutDuplicates(in: effectiveOptInRules + effectiveAnalyzerRules) + self = .default(disabled: Set(disabledRules), optIn: Set(effectiveOptInRules + effectiveAnalyzerRules)) } } From dfb09820d3d75be4fc2218834499f9633b5f73a4 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 3 Apr 2024 19:27:21 +0100 Subject: [PATCH 022/265] Enable `superfluous_disable_command` rule for analyzer rules (#5522) --- CHANGELOG.md | 8 +++++- Source/SwiftLintCore/Models/Linter.swift | 2 +- .../CommandTests.swift | 26 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fc00ff80c..07ad5a2c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,18 @@ * Rewrite `SwiftLintPlugin` using `BUILD_WORKSPACE_DIRECTORY` without relying on the `--config` option. [Garric Nahapetian](https://github.com/garricn) - + * Introduce SwiftLintCommandPlugin. Rename SwiftLintBuildToolPlugin. Add Swift Package Manager installation instructions. [garricn](https://github.com/garricn) +* The `superfluous_disable_command` rule will now be enabled for the `analyze` + command, unless it has been disabled, and will warn about superfluous + disablement of analyzer rules. + [Martin Redington](https://github.com/mildm8nnered) + [#4792](https://github.com/realm/SwiftLint/issues/4792) + #### Experimental * None. diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index 5fee18ad6c..f2d202977c 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -160,7 +160,7 @@ public struct Linter { if compilerArguments.isEmpty { return !(rule is any AnalyzerRule) } - return rule is any AnalyzerRule + return rule is any AnalyzerRule || rule is SuperfluousDisableCommandRule } self.rules = rules self.isCollecting = rules.contains(where: { $0 is any AnyCollectingRule }) diff --git a/Tests/SwiftLintFrameworkTests/CommandTests.swift b/Tests/SwiftLintFrameworkTests/CommandTests.swift index f4e697f321..f53bf9dbe8 100644 --- a/Tests/SwiftLintFrameworkTests/CommandTests.swift +++ b/Tests/SwiftLintFrameworkTests/CommandTests.swift @@ -1,6 +1,7 @@ // swiftlint:disable file_length import Foundation import SourceKittenFramework +@testable import SwiftLintBuiltInRules @testable import SwiftLintCore import XCTest @@ -454,4 +455,29 @@ class CommandTests: SwiftLintTestCase { [] ) } + + func testSuperfluousDisableCommandsEnabledForAnalyzer() { + let configuration = Configuration( + rulesMode: .default(disabled: [], optIn: [UnusedDeclarationRule.description.identifier]) + ) + let violations = violations( + Example(""" + public class Foo { + // swiftlint:disable:next unused_declaration + func foo() -> Int { + 1 + } + // swiftlint:disable:next unused_declaration + func bar() { + foo() + } + } + """), + config: configuration, + requiresFileOnDisk: true + ) + XCTAssertEqual(violations.count, 1) + XCTAssertEqual(violations.first?.ruleIdentifier, "superfluous_disable_command") + XCTAssertEqual(violations.first?.location.line, 3) + } } From dd8789b53011377188ce0e2d928735f93c48b71b Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Thu, 4 Apr 2024 17:25:06 +0100 Subject: [PATCH 023/265] Update `blanket_disable_command` rule reason and description (#5518) --- CHANGELOG.md | 6 ++++++ .../Rules/Lint/BlanketDisableCommandRule.swift | 13 ++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07ad5a2c52..e03927a7e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -225,6 +225,12 @@ [Martin Redington](https://github.com/mildm8nnered) [#4999](https://github.com/realm/SwiftLint/issues/4999) +* Updates the reasons provided by violations of the `blanket_disable_command` + to omit language about the end of the file, and to direct users to + re-enable the rule as soon as possible. + [Martin Redington](https://github.com/mildm8nnered) + [#5450](https://github.com/realm/SwiftLint/issues/5450) + ## 0.54.0: Macro-Economic Forces #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift index 3229b27f30..b0508d2049 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift @@ -4,7 +4,11 @@ struct BlanketDisableCommandRule: Rule, SourceKitFreeRule { static let description = RuleDescription( identifier: "blanket_disable_command", name: "Blanket Disable Command", - description: "swiftlint:disable commands should be re-enabled before the end of the file", + description: """ + `swiftlint:disable` commands should use `next`, `this` or `previous` to disable rules for a \ + single line, or `swiftlint:enable` to re-enable the rules immediately after the violations \ + to be ignored, instead of disabling the rule for the rest of the file. + """, kind: .lint, nonTriggeringExamples: [ Example(""" @@ -144,8 +148,11 @@ struct BlanketDisableCommandRule: Rule, SourceKitFreeRule { } if let command = ruleIdentifierToCommandMap[disabledRuleIdentifier] { - let reason = "The disabled '\(disabledRuleIdentifier.stringRepresentation)' rule " + - "should be re-enabled before the end of the file" + let reason = """ + Use 'next', 'this' or 'previous' instead to disable the \ + '\(disabledRuleIdentifier.stringRepresentation)' rule once, \ + or re-enable it as soon as possible` + """ return violation(for: command, ruleIdentifier: disabledRuleIdentifier, in: file, reason: reason) } return nil From 745aec5903678b49c07302e3810dfc85f55b941d Mon Sep 17 00:00:00 2001 From: waitbutY Date: Sun, 7 Apr 2024 05:39:08 -0500 Subject: [PATCH 024/265] Adjust case of severity in Code Climate reporter (#5523) --- CHANGELOG.md | 4 ++++ Source/SwiftLintCore/Reporters/CodeClimateReporter.swift | 2 +- .../Resources/CannedCodeClimateReporterOutput.json | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03927a7e5..4d7c05e1bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ Rename SwiftLintBuildToolPlugin. Add Swift Package Manager installation instructions. [garricn](https://github.com/garricn) + +* Fix Code Climate reporter output by having lower case severity + values to comply with the Code Climate specification. + [waitButY](https://github.com/waitbutY) * The `superfluous_disable_command` rule will now be enabled for the `analyze` command, unless it has been disabled, and will warn about superfluous diff --git a/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift b/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift index 829e3ae234..1c5e57658b 100644 --- a/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift +++ b/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift @@ -32,7 +32,7 @@ struct CodeClimateReporter: Reporter { "end": violation.location.line ?? NSNull() as Any ] ], - "severity": violation.severity == .error ? "MAJOR" : "MINOR", + "severity": violation.severity == .error ? "major" : "minor", "type": "issue" ] } diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json index a091aa6bd7..9e50e3d701 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json @@ -11,7 +11,7 @@ }, "path" : "filename" }, - "severity" : "MINOR", + "severity" : "minor", "type" : "issue" }, { @@ -26,7 +26,7 @@ }, "path" : "filename" }, - "severity" : "MAJOR", + "severity" : "major", "type" : "issue" }, { @@ -41,7 +41,7 @@ }, "path" : "filename" }, - "severity" : "MAJOR", + "severity" : "major", "type" : "issue" }, { @@ -56,7 +56,7 @@ }, "path" : null }, - "severity" : "MAJOR", + "severity" : "major", "type" : "issue" } ] \ No newline at end of file From 2d4f0bc85abb67f2d8069a50b2cc0c5928cd6d41 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 13 Apr 2024 09:33:36 +0100 Subject: [PATCH 025/265] Extend `unused_enumerated` rule to chained calls with closures (#5498) --- CHANGELOG.md | 6 + .../Idiomatic/UnusedEnumeratedRule.swift | 206 ++++++++++++++++-- 2 files changed, 195 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d7c05e1bb..de115b722d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -164,6 +164,12 @@ [phlippieb](https://github.com/phlippieb) [#5471](https://github.com/realm/SwiftLint/issues/5471) +* Extends `unused_enumerated` rule to cover closure parameters, to + detect cases like `list.enumerated().map { idx, _ in idx }` and + `list.enumerated().map { $1 }`. + [Martin Redington](https://github.com/mildm8nnered) + [#5470](https://github.com/realm/SwiftLint/issues/5470) + #### Bug Fixes * Silence `discarded_notification_center_observer` rule in closures. Furthermore, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift index f3a2de8d99..55d94c785e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift @@ -18,57 +18,223 @@ struct UnusedEnumeratedRule: Rule { Example("for (idx, _) in bar.enumerated().something() { }"), Example("for (idx, _) in bar.something() { }"), Example("for idx in bar.indices { }"), - Example("for (section, (event, _)) in data.enumerated() {}") + Example("for (section, (event, _)) in data.enumerated() {}"), + Example("list.enumerated().map { idx, elem in \"\\(idx): \\(elem)\" }"), + Example("list.enumerated().map { $0 + $1 }"), + Example("list.enumerated().something().map { _, elem in elem }"), + Example("list.enumerated().map { ($0.offset, $0.element) }"), + Example("list.enumerated().map { ($0.0, $0.1) }"), + Example(""" + list.enumerated().map { + $1.enumerated().forEach { print($0, $1) } + return $0 + } + """) ], triggeringExamples: [ Example("for (↓_, foo) in bar.enumerated() { }"), Example("for (↓_, foo) in abc.bar.enumerated() { }"), Example("for (↓_, foo) in abc.something().enumerated() { }"), - Example("for (idx, ↓_) in bar.enumerated() { }") + Example("for (idx, ↓_) in bar.enumerated() { }"), + Example("list.enumerated().map { idx, ↓_ in idx }"), + Example("list.enumerated().map { ↓_, elem in elem }"), + Example("list.↓enumerated().forEach { print($0) }"), + Example("list.↓enumerated().map { $1 }"), + Example(""" + list.enumerated().map { + $1.↓enumerated().forEach { print($1) } + return $0 + } + """), + Example(""" + list.↓enumerated().map { + $1.enumerated().forEach { print($0, $1) } + return 1 + } + """), + Example(""" + list.enumerated().map { + $1.enumerated().filter { + print($0, $1) + $1.↓enumerated().forEach { + if $1 == 2 { + return true + } + } + return false + } + return $0 + } + """, excludeFromDocumentation: true) + , + Example(""" + list.↓enumerated().map { + $1.forEach { print($0) } + return $1 + } + """, excludeFromDocumentation: true) ] ) } private extension UnusedEnumeratedRule { + private struct Closure { + let enumeratedPosition: AbsolutePosition? + var zeroPosition: AbsolutePosition? + var onePosition: AbsolutePosition? + + init(enumeratedPosition: AbsolutePosition? = nil) { + self.enumeratedPosition = enumeratedPosition + } + } + final class Visitor: ViolationsSyntaxVisitor { + private var nextClosureId: SyntaxIdentifier? + private var lastEnumeratedPosition: AbsolutePosition? + private var closures = Stack() + override func visitPost(_ node: ForStmtSyntax) { guard let tuplePattern = node.pattern.as(TuplePatternSyntax.self), tuplePattern.elements.count == 2, let functionCall = node.sequence.asFunctionCall, functionCall.isEnumerated, let firstElement = tuplePattern.elements.first, - let secondElement = tuplePattern.elements.last, - case let firstTokenIsUnderscore = firstElement.isUnderscore, - case let lastTokenIsUnderscore = secondElement.isUnderscore, - firstTokenIsUnderscore || lastTokenIsUnderscore else { + let secondElement = tuplePattern.elements.last + else { return } - let position: AbsolutePosition - let reason: String - if firstTokenIsUnderscore { - position = firstElement.positionAfterSkippingLeadingTrivia - reason = "When the index is not used, `.enumerated()` can be removed" + let firstTokenIsUnderscore = firstElement.isUnderscore + let lastTokenIsUnderscore = secondElement.isUnderscore + guard firstTokenIsUnderscore || lastTokenIsUnderscore else { + return + } + + addViolation( + zeroPosition: firstTokenIsUnderscore ? firstElement.positionAfterSkippingLeadingTrivia : nil, + onePosition: firstTokenIsUnderscore ? nil : secondElement.positionAfterSkippingLeadingTrivia + ) + } + + override func visit(_ node: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind { + guard node.isEnumerated, + let parent = node.parent, + parent.as(MemberAccessExprSyntax.self)?.declName.baseName.text != "filter", + let trailingClosure = parent.parent?.as(FunctionCallExprSyntax.self)?.trailingClosure + else { + return .visitChildren + } + + if let parameterClause = trailingClosure.signature?.parameterClause { + guard let parameterClause = parameterClause.as(ClosureShorthandParameterListSyntax.self), + parameterClause.count == 2, + let firstElement = parameterClause.first, + let secondElement = parameterClause.last + else { + return .visitChildren + } + + let firstTokenIsUnderscore = firstElement.isUnderscore + let lastTokenIsUnderscore = secondElement.isUnderscore + guard firstTokenIsUnderscore || lastTokenIsUnderscore else { + return .visitChildren + } + + addViolation( + zeroPosition: firstTokenIsUnderscore ? firstElement.positionAfterSkippingLeadingTrivia : nil, + onePosition: firstTokenIsUnderscore ? nil : secondElement.positionAfterSkippingLeadingTrivia + ) + } else { + nextClosureId = trailingClosure.id + lastEnumeratedPosition = node.enumeratedPosition + } + + return .visitChildren + } + + override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + if let nextClosureId, nextClosureId == node.id, let lastEnumeratedPosition { + closures.push(Closure(enumeratedPosition: lastEnumeratedPosition)) + self.nextClosureId = nil + self.lastEnumeratedPosition = nil } else { - position = secondElement.positionAfterSkippingLeadingTrivia + closures.push(Closure()) + } + return .visitChildren + } + + override func visitPost(_ node: ClosureExprSyntax) { + if let closure = closures.pop(), (closure.zeroPosition != nil) != (closure.onePosition != nil) { + addViolation( + zeroPosition: closure.onePosition, + onePosition: closure.zeroPosition, + enumeratedPosition: closure.enumeratedPosition + ) + } + } + + override func visitPost(_ node: DeclReferenceExprSyntax) { + guard + let closure = closures.peek(), + closure.enumeratedPosition != nil, + node.baseName.text == "$0" || node.baseName.text == "$1" + else { + return + } + closures.modifyLast { + if node.baseName.text == "$0" { + let member = node.parent?.as(MemberAccessExprSyntax.self)?.declName.baseName.text + if member == "element" || member == "1" { + $0.onePosition = node.positionAfterSkippingLeadingTrivia + } else { + $0.zeroPosition = node.positionAfterSkippingLeadingTrivia + } + } else { + $0.onePosition = node.positionAfterSkippingLeadingTrivia + } + } + } + + private func addViolation( + zeroPosition: AbsolutePosition?, + onePosition: AbsolutePosition?, + enumeratedPosition: AbsolutePosition? = nil + ) { + var position: AbsolutePosition? + var reason: String? + if let zeroPosition { + position = zeroPosition + reason = "When the index is not used, `.enumerated()` can be removed" + } else if let onePosition { + position = onePosition reason = "When the item is not used, `.indices` should be used instead of `.enumerated()`" } - violations.append(ReasonedRuleViolation(position: position, reason: reason)) + if let enumeratedPosition { + position = enumeratedPosition + } + + if let position, let reason { + violations.append(ReasonedRuleViolation(position: position, reason: reason)) + } } } } private extension FunctionCallExprSyntax { var isEnumerated: Bool { - guard let memberAccess = calledExpression.as(MemberAccessExprSyntax.self), + enumeratedPosition != nil + } + + var enumeratedPosition: AbsolutePosition? { + if let memberAccess = calledExpression.as(MemberAccessExprSyntax.self), memberAccess.base != nil, memberAccess.declName.baseName.text == "enumerated", - hasNoArguments else { - return false + hasNoArguments { + return memberAccess.declName.positionAfterSkippingLeadingTrivia } - return true + return nil } var hasNoArguments: Bool { @@ -83,3 +249,9 @@ private extension TuplePatternElementSyntax { pattern.is(WildcardPatternSyntax.self) } } + +private extension ClosureShorthandParameterSyntax { + var isUnderscore: Bool { + name.tokenKind == .wildcard + } +} From 5315c3d1b68ebae7bf3a5871c22e096d67c32e6e Mon Sep 17 00:00:00 2001 From: waitbutY Date: Sat, 13 Apr 2024 04:49:57 -0500 Subject: [PATCH 026/265] Add SARIF reporter (#5516) --- CHANGELOG.md | 4 + .../SwiftLintCore/Models/ReportersList.swift | 1 + .../Reporters/SARIFReporter.swift | 75 +++++++++++++++ .../ReporterTests.swift | 6 ++ .../Resources/CannedSARIFReporterOutput.json | 93 +++++++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 Source/SwiftLintCore/Reporters/SARIFReporter.swift create mode 100644 Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json diff --git a/CHANGELOG.md b/CHANGELOG.md index de115b722d..9c8062c8f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ #### Enhancements +* Add a reporter that outputs violations in the Static + Analysis Results Interchange Format (SARIF). + [waitButY](https://github.com/waitbutY) + * Ignore absence of a non-initial local config instead of falling back to default. [kohtenko](https://github.com/kohtenko) diff --git a/Source/SwiftLintCore/Models/ReportersList.swift b/Source/SwiftLintCore/Models/ReportersList.swift index 53c89305f6..1c7d8c2ebe 100644 --- a/Source/SwiftLintCore/Models/ReportersList.swift +++ b/Source/SwiftLintCore/Models/ReportersList.swift @@ -14,6 +14,7 @@ public let reportersList: [any Reporter.Type] = [ JUnitReporter.self, MarkdownReporter.self, RelativePathReporter.self, + SARIFReporter.self, SonarQubeReporter.self, SummaryReporter.self, XcodeReporter.self diff --git a/Source/SwiftLintCore/Reporters/SARIFReporter.swift b/Source/SwiftLintCore/Reporters/SARIFReporter.swift new file mode 100644 index 0000000000..4bcda874af --- /dev/null +++ b/Source/SwiftLintCore/Reporters/SARIFReporter.swift @@ -0,0 +1,75 @@ +import Foundation +import SourceKittenFramework + +/// To some tools (i.e. Datadog), code quality findings are reported in the SARIF format: +/// - Full Spec: https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html +/// - Samples: https://github.com/microsoft/sarif-tutorials/blob/main/samples/ +/// - JSON Validator: https://sarifweb.azurewebsites.net/Validation +struct SARIFReporter: Reporter { + // MARK: - Reporter Conformance + static let identifier = "sarif" + static let isRealtime = false + static let description = "Reports violations in the Static Analysis Results Interchange Format (SARIF)" + static let swiftlintVersion = "https://github.com/realm/SwiftLint/blob/\(Version.current.value)/README.md" + + static func generateReport(_ violations: [StyleViolation]) -> String { + let SARIFJson = [ + "version": "2.1.0", + "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json", + "runs": [ + [ + "tool": [ + "driver": [ + "name": "SwiftLint", + "semanticVersion": Version.current.value, + "informationUri": swiftlintVersion + ] + ], + "results": violations.map(dictionary(for:)) + ] + ] + ] as [String: Any] + + return toJSON(SARIFJson) + } + + // MARK: - Private + + private static func dictionary(for violation: StyleViolation) -> [String: Any] { + return [ + "level": violation.severity.rawValue, + "ruleId": violation.ruleIdentifier, + "message": [ + "text": violation.reason + ], + "locations": [ + dictionary(for: violation.location) + ] + ] + } + + private static func dictionary(for location: Location) -> [String: Any] { + // According to SARIF specification JSON1008, minimum value for line is 1 + if let line = location.line, line > 0 { + return [ + "physicalLocation": [ + "artifactLocation": [ + "uri": location.file ?? "" + ], + "region": [ + "startLine": line, + "startColumn": location.character ?? "1" + ] + ] + ] + } + + return [ + "physicalLocation": [ + "artifactLocation": [ + "uri": location.file ?? "" + ] + ] + ] + } +} diff --git a/Tests/SwiftLintFrameworkTests/ReporterTests.swift b/Tests/SwiftLintFrameworkTests/ReporterTests.swift index 10ae241ccb..c7c2e230f3 100644 --- a/Tests/SwiftLintFrameworkTests/ReporterTests.swift +++ b/Tests/SwiftLintFrameworkTests/ReporterTests.swift @@ -97,6 +97,12 @@ class ReporterTests: SwiftLintTestCase { XCTAssertEqual(result, expectedOutput) } + func testSARIFReporter() { + let expectedOutput = stringFromFile("CannedSARIFReporterOutput.json") + let result = SARIFReporter.generateReport(generateViolations()) + XCTAssertEqual(expectedOutput, result) + } + func testJunitReporter() { let expectedOutput = stringFromFile("CannedJunitReporterOutput.xml") let result = JUnitReporter.generateReport(generateViolations()) diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json new file mode 100644 index 0000000000..e353071a66 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json @@ -0,0 +1,93 @@ +{ + "$schema" : "https:\/\/docs.oasis-open.org\/sarif\/sarif\/v2.1.0\/cos02\/schemas\/sarif-schema-2.1.0.json", + "runs" : [ + { + "results" : [ + { + "level" : "warning", + "locations" : [ + { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "filename" + }, + "region" : { + "startColumn" : 2, + "startLine" : 1 + } + } + } + ], + "message" : { + "text" : "Violation Reason" + }, + "ruleId" : "line_length" + }, + { + "level" : "error", + "locations" : [ + { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "filename" + }, + "region" : { + "startColumn" : 2, + "startLine" : 1 + } + } + } + ], + "message" : { + "text" : "Violation Reason" + }, + "ruleId" : "line_length" + }, + { + "level" : "error", + "locations" : [ + { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "filename" + }, + "region" : { + "startColumn" : 2, + "startLine" : 1 + } + } + } + ], + "message" : { + "text" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array" + }, + "ruleId" : "syntactic_sugar" + }, + { + "level" : "error", + "locations" : [ + { + "physicalLocation" : { + "artifactLocation" : { + "uri" : "" + } + } + } + ], + "message" : { + "text" : "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals" + }, + "ruleId" : "colon" + } + ], + "tool" : { + "driver" : { + "informationUri" : "https:\/\/github.com\/realm\/SwiftLint\/blob\/0.54.0\/README.md", + "name" : "SwiftLint", + "semanticVersion" : "0.54.0" + } + } + } + ], + "version" : "2.1.0" +} \ No newline at end of file From b3dd89088e0bbf61887dfcb736ad5e87d6ffcd5b Mon Sep 17 00:00:00 2001 From: Marceau TONELLI Date: Sun, 21 Apr 2024 17:46:29 +0200 Subject: [PATCH 027/265] Rewrite `redundant_type_annotation` with SwiftSyntax (#5389) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 8 + .../RedundantTypeAnnotationRule.swift | 266 +++++++++++++----- ...RedundantTypeAnnotationConfiguration.swift | 11 + .../default_rule_configurations.yml | 1 + 4 files changed, 208 insertions(+), 78 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c8062c8f6..cf6cc96e4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,12 @@ [Muhammad Zeeshan](https://github.com/mzeeshanid) [#2802](https://github.com/realm/SwiftLint/issues/2802) +* Add new `ignore_attributes` option to `redundant_type_annotation` rule + that allows disabling the rule for properties that are marked with at least + one of the configured attributes. + [tonell-m](https://github.com/tonell-m) + [#5366](https://github.com/realm/SwiftLint/issues/5366) + * Rewrite the following rules with SwiftSyntax: * `explicit_acl` * `extension_access_modifier` @@ -83,6 +89,7 @@ * `nimble_operator` * `opening_brace` * `orphaned_doc_comment` + * `redundant_type_annotation` * `trailing_closure` * `void_return` @@ -91,6 +98,7 @@ [Marcelo Fabri](https://github.com/marcelofabri) [swiftty](https://github.com/swiftty) [KS1019](https://github.com/KS1019) + [tonell-m](https://github.com/tonell-m) * Print invalid keys when configuration parsing fails. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index 130066ede8..c797fa5aab 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -1,8 +1,9 @@ -import Foundation -import SourceKittenFramework +import SwiftLintCore +import SwiftSyntax -struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule { - var configuration = SeverityConfiguration(.warning) +@SwiftSyntaxRule +struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { + var configuration = RedundantTypeAnnotationConfiguration() static let description = RuleDescription( identifier: "redundant_type_annotation", @@ -12,7 +13,23 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule { nonTriggeringExamples: [ Example("var url = URL()"), Example("var url: CustomStringConvertible = URL()"), - Example("@IBInspectable var color: UIColor = UIColor.white"), + Example("var one: Int = 1, two: Int = 2, three: Int"), + Example("guard let url = URL() else { return }"), + Example("if let url = URL() { return }"), + Example("let alphanumerics = CharacterSet.alphanumerics"), + Example("var set: Set = Set([])"), + Example("var set: Set = Set.init([])"), + Example("var set = Set([])"), + Example("var set = Set.init([])"), + Example("guard var set: Set = Set([]) else { return }"), + Example("if var set: Set = Set.init([]) { return }"), + Example("guard var set = Set([]) else { return }"), + Example("if var set = Set.init([]) { return }"), + Example("var one: A = B()"), + Example("var one: A = B()"), + Example("var one: A = B()"), + Example("let a = A.b.c.d"), + Example("let a: B = A.b.c.d"), Example(""" enum Direction { case up @@ -28,7 +45,14 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule { } var direction = Direction.up - """) + """), + Example("@IgnoreMe var a: Int = Int(5)", configuration: ["ignore_attributes": ["IgnoreMe"]]), + Example(""" + var a: Int { + @IgnoreMe let i: Int = Int(1) + return i + } + """, configuration: ["ignore_attributes": ["IgnoreMe"]]) ], triggeringExamples: [ Example("var url↓:URL=URL()"), @@ -36,7 +60,23 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule { Example("var url↓: URL = URL()"), Example("let url↓: URL = URL()"), Example("lazy var url↓: URL = URL()"), + Example("let url↓: URL = URL()!"), + Example("var one: Int = 1, two↓: Int = Int(5), three: Int"), + Example("guard let url↓: URL = URL() else { return }"), + Example("if let url↓: URL = URL() { return }"), Example("let alphanumerics↓: CharacterSet = CharacterSet.alphanumerics"), + Example("var set↓: Set = Set([])"), + Example("var set↓: Set = Set.init([])"), + Example("var set↓: Set = Set([])"), + Example("var set↓: Set = Set.init([])"), + Example("guard var set↓: Set = Set([]) else { return }"), + Example("if var set↓: Set = Set.init([]) { return }"), + Example("guard var set↓: Set = Set([]) else { return }"), + Example("if var set↓: Set = Set.init([]) { return }"), + Example("var set↓: Set = Set([]), otherSet: Set"), + Example("var num↓: Int = Int.random(0..<10)"), + Example("let a↓: A = A.b.c.d"), + Example("let a↓: A = A.f().b"), Example(""" class ViewController: UIViewController { func someMethod() { @@ -52,13 +92,43 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule { } var direction↓: Direction = Direction.up - """) + """), + Example("@DontIgnoreMe var a↓: Int = Int(5)", configuration: ["ignore_attributes": ["IgnoreMe"]]), + Example(""" + @IgnoreMe + var a: Int { + let i↓: Int = Int(1) + return i + } + """, configuration: ["ignore_attributes": ["IgnoreMe"]]) ], corrections: [ Example("var url↓: URL = URL()"): Example("var url = URL()"), Example("let url↓: URL = URL()"): Example("let url = URL()"), + Example("var one: Int = 1, two↓: Int = Int(5), three: Int"): + Example("var one: Int = 1, two = Int(5), three: Int"), + Example("guard let url↓: URL = URL() else { return }"): + Example("guard let url = URL() else { return }"), + Example("if let url↓: URL = URL() { return }"): + Example("if let url = URL() { return }"), Example("let alphanumerics↓: CharacterSet = CharacterSet.alphanumerics"): Example("let alphanumerics = CharacterSet.alphanumerics"), + Example("var set↓: Set = Set([])"): + Example("var set = Set([])"), + Example("var set↓: Set = Set.init([])"): + Example("var set = Set.init([])"), + Example("var set↓: Set = Set([])"): + Example("var set = Set([])"), + Example("var set↓: Set = Set.init([])"): + Example("var set = Set.init([])"), + Example("guard var set↓: Set = Set([]) else { return }"): + Example("guard var set = Set([]) else { return }"), + Example("if var set↓: Set = Set.init([]) { return }"): + Example("if var set = Set.init([]) { return }"), + Example("var set↓: Set = Set([]), otherSet: Set"): + Example("var set = Set([]), otherSet: Set"), + Example("let a↓: A = A.b.c.d"): + Example("let a = A.b.c.d"), Example(""" class ViewController: UIViewController { func someMethod() { @@ -72,97 +142,137 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule { let myVar = Int(5) } } + """), + Example("var num: Int = Int.random(0..<10)"): Example("var num = Int.random(0..<10)"), + Example(""" + @IgnoreMe + var a: Int { + let i↓: Int = Int(1) + return i + } + """, configuration: ["ignore_attributes": ["IgnoreMe"]]): + Example(""" + @IgnoreMe + var a: Int { + let i = Int(1) + return i + } """) ] ) +} - func validate(file: SwiftLintFile) -> [StyleViolation] { - return violationRanges(in: file).map { range in - StyleViolation( - ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: file, characterOffset: range.location) - ) +private extension RedundantTypeAnnotationRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: PatternBindingSyntax) { + if node.parentDoesNotContainIgnoredAttributes(for: configuration), + let typeAnnotation = node.typeAnnotation, + let initializer = node.initializer?.value, + typeAnnotation.isRedundant(with: initializer) { + violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) + violationCorrections.append(ViolationCorrection( + start: typeAnnotation.position, + end: typeAnnotation.endPositionBeforeTrailingTrivia, + replacement: "" + )) + } } - } - func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { - return (violationRange, "") + override func visitPost(_ node: OptionalBindingConditionSyntax) { + if let typeAnnotation = node.typeAnnotation, + let initializer = node.initializer?.value, + typeAnnotation.isRedundant(with: initializer) { + violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) + violationCorrections.append(ViolationCorrection( + start: typeAnnotation.position, + end: typeAnnotation.endPositionBeforeTrailingTrivia, + replacement: "" + )) + } + } } +} - private let typeAnnotationPattern: String - private let expressionPattern: String - - init() { - typeAnnotationPattern = - ":\\s*" + // semicolon and any number of whitespaces - "\\w+" // type name - - expressionPattern = - "(var|let)" + // var or let - "\\s+" + // at least single whitespace - "\\w+" + // variable name - "\\s*" + // possible whitespaces - typeAnnotationPattern + - "\\s*=\\s*" + // assignment operator with possible surrounding whitespaces - "\\w+" + // assignee name (type or keyword) - "[\\(\\.]?" // possible opening parenthesis or dot - } +private extension TypeAnnotationSyntax { + func isRedundant(with initializerExpr: ExprSyntax) -> Bool { + // Extract type and type name from type annotation + guard let type = type.as(IdentifierTypeSyntax.self) else { + return false + } + let typeName = type.trimmedDescription - func violationRanges(in file: SwiftLintFile) -> [NSRange] { - return file - .match(pattern: expressionPattern) - .filter { - $0.1 == [.keyword, .identifier, .typeidentifier, .identifier] || - $0.1 == [.keyword, .identifier, .typeidentifier, .keyword] - } - .filter { !isFalsePositive(file: file, range: $0.0) } - .filter { !isIBInspectable(file: file, range: $0.0) } - .compactMap { - file.match(pattern: typeAnnotationPattern, - excludingSyntaxKinds: SyntaxKind.commentAndStringKinds, range: $0.0).first - } - } + var initializer = initializerExpr + if let forceUnwrap = initializer.as(ForceUnwrapExprSyntax.self) { + initializer = forceUnwrap.expression + } - private func isFalsePositive(file: SwiftLintFile, range: NSRange) -> Bool { - guard let typeNames = getPartsOfExpression(in: file, range: range) else { return false } + // If the initializer is a boolean expression, we consider using the `Bool` type + // annotation as redundant. + if initializer.is(BooleanLiteralExprSyntax.self) { + return typeName == "Bool" + } - let lhs = typeNames.variableTypeName - let rhs = typeNames.assigneeName + // If the initializer is a function call (generally a constructor or static builder), + // check if the base type is the same as the one from the type annotation. + if let functionCall = initializer.as(FunctionCallExprSyntax.self) { + if let calledExpression = functionCall.calledExpression.as(DeclReferenceExprSyntax.self) { + return calledExpression.baseName.text == typeName + } + // Parse generic arguments in the intializer if there are any (e.g. var s = Set(...)) + if let genericSpecialization = functionCall.calledExpression.as(GenericSpecializationExprSyntax.self) { + // In this case it should be considered redundant if the type name is the same in the type annotation + // E.g. var s: Set = Set() should trigger a violation + return genericSpecialization.expression.trimmedDescription == type.typeName + } - if lhs == rhs || (lhs == "Bool" && (rhs == "true" || rhs == "false")) { - return false + // If the function call is a member access expression, check if it is a violation + return isMemberAccessViolation(node: functionCall.calledExpression, type: type) } - return true - } - private func getPartsOfExpression( - in file: SwiftLintFile, range: NSRange - ) -> (variableTypeName: String, assigneeName: String)? { - let substring = file.stringView.substring(with: range) - let components = substring.components(separatedBy: "=") + // If the initializer is a member access, check if the base type name is the same as + // the type annotation + return isMemberAccessViolation(node: initializer, type: type) + } - guard - components.count == 2, - let variableTypeName = components[0].components(separatedBy: ":").last?.trimmingCharacters(in: .whitespaces) + /// Checks if the given node is a member access (i.e. an enum case or a static property or function) + /// and if so checks if the base type is the same as the given type name. + private func isMemberAccessViolation(node: ExprSyntax, type: IdentifierTypeSyntax) -> Bool { + guard let memberAccess = node.as(MemberAccessExprSyntax.self), + let base = memberAccess.base else { - return nil + // If the type is implicit, `base` will be nil, meaning there is no redundancy. + return false } - let charactersToTrimFromRhs = CharacterSet(charactersIn: ".(").union(.whitespaces) - let assigneeName = components[1].trimmingCharacters(in: charactersToTrimFromRhs) + // Parse generic arguments in the intializer if there are any (e.g. var s = Set(...)) + if let genericSpecialization = base.as(GenericSpecializationExprSyntax.self) { + // In this case it should be considered redundant if the type name is the same in the type annotation + // E.g. var s: Set = Set() should trigger a violation + return genericSpecialization.expression.trimmedDescription == type.typeName + } - return (variableTypeName, assigneeName) + // In the case of chained MemberAccessExprSyntax (e.g. let a: A = A.b.c), call this function recursively + // with the base sequence as root node (in this case A.b). + if base.is(MemberAccessExprSyntax.self) { + return isMemberAccessViolation(node: base, type: type) + } + // Same for FunctionCallExprSyntax ... + if let call = base.as(FunctionCallExprSyntax.self) { + return isMemberAccessViolation(node: call.calledExpression, type: type) + } + return base.trimmedDescription == type.trimmedDescription } +} - private func isIBInspectable(file: SwiftLintFile, range: NSRange) -> Bool { - guard - let byteRange = file.stringView.NSRangeToByteRange(start: range.location, length: range.length), - let dict = file.structureDictionary.structures(forByteOffset: byteRange.location).last, - let kind = dict.declarationKind, - SwiftDeclarationKind.variableKinds.contains(kind) - else { return false } - - return dict.enclosedSwiftAttributes.contains(.ibinspectable) +private extension PatternBindingSyntax { + /// Checks if none of the attributes flagged as ignored in the configuration + /// are set for this node's parent's parent, if it's a variable declaration + func parentDoesNotContainIgnoredAttributes(for configuration: RedundantTypeAnnotationConfiguration) -> Bool { + guard let variableDecl = parent?.parent?.as(VariableDeclSyntax.self) else { + return true + } + return configuration.ignoreAttributes.allSatisfy { + !variableDecl.attributes.contains(attributeNamed: $0) + } } } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift new file mode 100644 index 0000000000..01c22d6005 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift @@ -0,0 +1,11 @@ +import SwiftLintCore + +@AutoApply +struct RedundantTypeAnnotationConfiguration: SeverityBasedRuleConfiguration { + typealias Parent = RedundantTypeAnnotationRule + + @ConfigurationElement(key: "severity") + var severityConfiguration = SeverityConfiguration(.warning) + @ConfigurationElement(key: "ignore_attributes") + var ignoreAttributes = Set(["IBInspectable"]) +} diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 7607bb6ab0..a8796526ee 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -456,6 +456,7 @@ redundant_string_enum_value: severity: warning redundant_type_annotation: severity: warning + ignore_attributes: ["IBInspectable"] redundant_void_return: severity: warning include_closures: true From e643f210c5615306464d68fd245f0fc3fb97ca8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 21 Apr 2024 19:39:54 +0200 Subject: [PATCH 028/265] Respect array types in `redundant_type_annotation` rule (#5536) --- CHANGELOG.md | 4 + .../RedundantTypeAnnotationRule.swift | 91 +++++++------------ 2 files changed, 37 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf6cc96e4d..fedbf77308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -228,6 +228,10 @@ [Martin Redington](https://github.com/mildm8nnered) [#5305](https://github.com/realm/SwiftLint/pull/5305) +* Take array types into account in `redundant_type_annotation` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#3141](https://github.com/realm/SwiftLint/pull/3141) + * Silence `pattern_matching_keywords` rule when an identifier is referenced in the argument list of a matching enum case. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index c797fa5aab..14dde5c060 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -85,6 +85,7 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { } """), Example("var isEnabled↓: Bool = true"), + Example("let a↓: [Int] = [Int]()"), Example(""" enum Direction { case up @@ -165,8 +166,11 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { private extension RedundantTypeAnnotationRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: PatternBindingSyntax) { - if node.parentDoesNotContainIgnoredAttributes(for: configuration), - let typeAnnotation = node.typeAnnotation, + guard let varDecl = node.parent?.parent?.as(VariableDeclSyntax.self), + configuration.ignoreAttributes.allSatisfy({ !varDecl.attributes.contains(attributeNamed: $0) }) else { + return + } + if let typeAnnotation = node.typeAnnotation, let initializer = node.initializer?.value, typeAnnotation.isRedundant(with: initializer) { violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) @@ -195,12 +199,9 @@ private extension RedundantTypeAnnotationRule { private extension TypeAnnotationSyntax { func isRedundant(with initializerExpr: ExprSyntax) -> Bool { - // Extract type and type name from type annotation - guard let type = type.as(IdentifierTypeSyntax.self) else { + guard let typeName = type.name else { return false } - let typeName = type.trimmedDescription - var initializer = initializerExpr if let forceUnwrap = initializer.as(ForceUnwrapExprSyntax.self) { initializer = forceUnwrap.expression @@ -211,68 +212,42 @@ private extension TypeAnnotationSyntax { if initializer.is(BooleanLiteralExprSyntax.self) { return typeName == "Bool" } - - // If the initializer is a function call (generally a constructor or static builder), - // check if the base type is the same as the one from the type annotation. - if let functionCall = initializer.as(FunctionCallExprSyntax.self) { - if let calledExpression = functionCall.calledExpression.as(DeclReferenceExprSyntax.self) { - return calledExpression.baseName.text == typeName - } - // Parse generic arguments in the intializer if there are any (e.g. var s = Set(...)) - if let genericSpecialization = functionCall.calledExpression.as(GenericSpecializationExprSyntax.self) { - // In this case it should be considered redundant if the type name is the same in the type annotation - // E.g. var s: Set = Set() should trigger a violation - return genericSpecialization.expression.trimmedDescription == type.typeName - } - - // If the function call is a member access expression, check if it is a violation - return isMemberAccessViolation(node: functionCall.calledExpression, type: type) - } - - // If the initializer is a member access, check if the base type name is the same as - // the type annotation - return isMemberAccessViolation(node: initializer, type: type) + return initializer.firstAccessNames.contains(typeName) } +} - /// Checks if the given node is a member access (i.e. an enum case or a static property or function) - /// and if so checks if the base type is the same as the given type name. - private func isMemberAccessViolation(node: ExprSyntax, type: IdentifierTypeSyntax) -> Bool { - guard let memberAccess = node.as(MemberAccessExprSyntax.self), - let base = memberAccess.base - else { - // If the type is implicit, `base` will be nil, meaning there is no redundancy. - return false +private extension ExprSyntax { + /// An expression can represent an access to an identifier in one or another way depending on the exact underlying + /// expression type. E.g. the expression `A` accesses `A` while `f()` accesses `f` and `a.b.c` accesses `a` in the + /// sense of this property. In the context of this rule, `Set()` accesses `Set` as well as `Set`. + var firstAccessNames: [String] { + if let declRef = `as`(DeclReferenceExprSyntax.self) { + return [declRef.trimmedDescription] } - - // Parse generic arguments in the intializer if there are any (e.g. var s = Set(...)) - if let genericSpecialization = base.as(GenericSpecializationExprSyntax.self) { - // In this case it should be considered redundant if the type name is the same in the type annotation - // E.g. var s: Set = Set() should trigger a violation - return genericSpecialization.expression.trimmedDescription == type.typeName + if let memberAccess = `as`(MemberAccessExprSyntax.self) { + return memberAccess.base?.firstAccessNames ?? [] } - - // In the case of chained MemberAccessExprSyntax (e.g. let a: A = A.b.c), call this function recursively - // with the base sequence as root node (in this case A.b). - if base.is(MemberAccessExprSyntax.self) { - return isMemberAccessViolation(node: base, type: type) + if let genericSpecialization = `as`(GenericSpecializationExprSyntax.self) { + return [genericSpecialization.trimmedDescription] + genericSpecialization.expression.firstAccessNames + } + if let call = `as`(FunctionCallExprSyntax.self) { + return call.calledExpression.firstAccessNames } - // Same for FunctionCallExprSyntax ... - if let call = base.as(FunctionCallExprSyntax.self) { - return isMemberAccessViolation(node: call.calledExpression, type: type) + if let arrayExpr = `as`(ArrayExprSyntax.self) { + return [arrayExpr.trimmedDescription] } - return base.trimmedDescription == type.trimmedDescription + return [] } } -private extension PatternBindingSyntax { - /// Checks if none of the attributes flagged as ignored in the configuration - /// are set for this node's parent's parent, if it's a variable declaration - func parentDoesNotContainIgnoredAttributes(for configuration: RedundantTypeAnnotationConfiguration) -> Bool { - guard let variableDecl = parent?.parent?.as(VariableDeclSyntax.self) else { - return true +private extension TypeSyntax { + var name: String? { + if let idType = `as`(IdentifierTypeSyntax.self) { + return idType.trimmedDescription } - return configuration.ignoreAttributes.allSatisfy { - !variableDecl.attributes.contains(attributeNamed: $0) + if let arrayType = `as`(ArrayTypeSyntax.self) { + return arrayType.trimmedDescription } + return nil } } From 327626671643373ba98ff5412bd99613e739f155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 21 Apr 2024 21:15:01 +0200 Subject: [PATCH 029/265] Respect nested types in `redundant_type_annotation` rule (#5537) --- CHANGELOG.md | 3 +- .../RedundantTypeAnnotationRule.swift | 47 ++++++------------- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fedbf77308..5d1ba8a71a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -228,9 +228,10 @@ [Martin Redington](https://github.com/mildm8nnered) [#5305](https://github.com/realm/SwiftLint/pull/5305) -* Take array types into account in `redundant_type_annotation` rule. +* Take array and nested types into account in `redundant_type_annotation` rule. [SimplyDanny](https://github.com/SimplyDanny) [#3141](https://github.com/realm/SwiftLint/pull/3141) + [#3146](https://github.com/realm/SwiftLint/pull/3146) * Silence `pattern_matching_keywords` rule when an identifier is referenced in the argument list of a matching enum case. diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index 14dde5c060..a75b3be334 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -86,6 +86,7 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { """), Example("var isEnabled↓: Bool = true"), Example("let a↓: [Int] = [Int]()"), + Example("let a↓: A.B = A.B()"), Example(""" enum Direction { case up @@ -199,9 +200,6 @@ private extension RedundantTypeAnnotationRule { private extension TypeAnnotationSyntax { func isRedundant(with initializerExpr: ExprSyntax) -> Bool { - guard let typeName = type.name else { - return false - } var initializer = initializerExpr if let forceUnwrap = initializer.as(ForceUnwrapExprSyntax.self) { initializer = forceUnwrap.expression @@ -210,9 +208,9 @@ private extension TypeAnnotationSyntax { // If the initializer is a boolean expression, we consider using the `Bool` type // annotation as redundant. if initializer.is(BooleanLiteralExprSyntax.self) { - return typeName == "Bool" + return type.trimmedDescription == "Bool" } - return initializer.firstAccessNames.contains(typeName) + return initializer.accessedNames.contains(type.trimmedDescription) } } @@ -220,34 +218,19 @@ private extension ExprSyntax { /// An expression can represent an access to an identifier in one or another way depending on the exact underlying /// expression type. E.g. the expression `A` accesses `A` while `f()` accesses `f` and `a.b.c` accesses `a` in the /// sense of this property. In the context of this rule, `Set()` accesses `Set` as well as `Set`. - var firstAccessNames: [String] { + var accessedNames: [String] { if let declRef = `as`(DeclReferenceExprSyntax.self) { - return [declRef.trimmedDescription] - } - if let memberAccess = `as`(MemberAccessExprSyntax.self) { - return memberAccess.base?.firstAccessNames ?? [] - } - if let genericSpecialization = `as`(GenericSpecializationExprSyntax.self) { - return [genericSpecialization.trimmedDescription] + genericSpecialization.expression.firstAccessNames - } - if let call = `as`(FunctionCallExprSyntax.self) { - return call.calledExpression.firstAccessNames - } - if let arrayExpr = `as`(ArrayExprSyntax.self) { - return [arrayExpr.trimmedDescription] - } - return [] - } -} - -private extension TypeSyntax { - var name: String? { - if let idType = `as`(IdentifierTypeSyntax.self) { - return idType.trimmedDescription - } - if let arrayType = `as`(ArrayTypeSyntax.self) { - return arrayType.trimmedDescription + [declRef.trimmedDescription] + } else if let memberAccess = `as`(MemberAccessExprSyntax.self) { + (memberAccess.base?.accessedNames ?? []) + [memberAccess.trimmedDescription] + } else if let genericSpecialization = `as`(GenericSpecializationExprSyntax.self) { + [genericSpecialization.trimmedDescription] + genericSpecialization.expression.accessedNames + } else if let call = `as`(FunctionCallExprSyntax.self) { + call.calledExpression.accessedNames + } else if let arrayExpr = `as`(ArrayExprSyntax.self) { + [arrayExpr.trimmedDescription] + } else { + [] } - return nil } } From 1b7fbc4bcdc3199a5516c3734a1ff4b2032e7276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 23 Apr 2024 22:45:59 +0200 Subject: [PATCH 030/265] Make postprocessors non-throwing (#5539) Failing immediately when a property is invalid is too strict. It feels sufficient to allow to report an issue but otherwise continue with a default value instead of stopping execution completely. --- .../IndentationWidthConfiguration.swift | 9 +++++++- .../Models/RuleConfigurationDescription.swift | 23 ++++++++++--------- .../RuleConfigurationMacros.swift | 4 ---- Tests/MacroTests/AutoApplyTests.swift | 8 ------- .../IndentationWidthRuleTests.swift | 10 ++++---- 5 files changed, 26 insertions(+), 28 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift index 8f78f761b4..9e6e1be378 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift @@ -4,11 +4,18 @@ import SwiftLintCore struct IndentationWidthConfiguration: SeverityBasedRuleConfiguration { typealias Parent = IndentationWidthRule + private static let defaultIndentationWidth = 4 + @ConfigurationElement(key: "severity") private(set) var severityConfiguration = SeverityConfiguration.warning @ConfigurationElement( key: "indentation_width", - postprocessor: { if $0 < 1 { throw Issue.invalidConfiguration(ruleID: Parent.identifier) } } + postprocessor: { + if $0 < 1 { + Issue.invalidConfiguration(ruleID: Parent.identifier).print() + $0 = Self.defaultIndentationWidth + } + } ) private(set) var indentationWidth = 4 @ConfigurationElement(key: "include_comments") diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index d09de4729b..be0cc48e18 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -416,7 +416,13 @@ public protocol InlinableOptionType: AcceptableByConfigurationElement {} @propertyWrapper public struct ConfigurationElement: Equatable { /// Wrapped option value. - public var wrappedValue: T + public var wrappedValue: T { + didSet { + if wrappedValue != oldValue { + postprocessor(&wrappedValue) + } + } + } /// The wrapper itself providing access to all its data. This field can only be accessed by the /// element's name prefixed with a `$`. @@ -431,7 +437,7 @@ public struct ConfigurationElement Void + private let postprocessor: (inout T) -> Void /// Default constructor. /// @@ -441,11 +447,11 @@ public struct ConfigurationElement Void = { _ in }) { + postprocessor: @escaping (inout T) -> Void = { _ in }) { self.init(wrappedValue: value, key: key, inline: false, postprocessor: postprocessor) - // Validate and modify the set value immediately. An exception means invalid defaults. - try! performAfterParseOperations() // swiftlint:disable:this force_try + // Modify the set value immediately. + postprocessor(&wrappedValue) } /// Constructor for optional values. @@ -482,18 +488,13 @@ public struct ConfigurationElement Void = { _ in }) { + postprocessor: @escaping (inout T) -> Void = { _ in }) { self.wrappedValue = wrappedValue self.key = key self.inline = inline self.postprocessor = postprocessor } - /// Run operations to validate and modify the parsed value. - public mutating func performAfterParseOperations() throws { - try postprocessor(&wrappedValue) - } - public static func == (lhs: ConfigurationElement, rhs: ConfigurationElement) -> Bool { lhs.wrappedValue == rhs.wrappedValue && lhs.key == rhs.key } diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index 029d449f0b..f303ab22b8 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -60,7 +60,6 @@ enum AutoApply: MemberMacro { """ do { try \(raw: option).apply(configuration, ruleID: Parent.identifier) - try $\(raw: option).performAfterParseOperations() } catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) { // Acceptable. Continue. } @@ -77,9 +76,6 @@ enum AutoApply: MemberMacro { """ try \(raw: option).apply(configuration[$\(raw: option).key], ruleID: Parent.identifier) """ - """ - try $\(raw: option).performAfterParseOperations() - """ } """ if !supportedKeys.isSuperset(of: configuration.keys) { diff --git a/Tests/MacroTests/AutoApplyTests.swift b/Tests/MacroTests/AutoApplyTests.swift index 45b132e668..93b39f60fa 100644 --- a/Tests/MacroTests/AutoApplyTests.swift +++ b/Tests/MacroTests/AutoApplyTests.swift @@ -81,9 +81,7 @@ final class AutoApplyTests: XCTestCase { throw Issue.invalidConfiguration(ruleID: Parent.identifier) } try eA.apply(configuration[$eA.key], ruleID: Parent.identifier) - try $eA.performAfterParseOperations() try eB.apply(configuration[$eB.key], ruleID: Parent.identifier) - try $eB.performAfterParseOperations() if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) @@ -127,7 +125,6 @@ final class AutoApplyTests: XCTestCase { } do { try eB.apply(configuration, ruleID: Parent.identifier) - try $eB.performAfterParseOperations() } catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) { // Acceptable. Continue. } @@ -135,9 +132,7 @@ final class AutoApplyTests: XCTestCase { return } try eA.apply(configuration[$eA.key], ruleID: Parent.identifier) - try $eA.performAfterParseOperations() try eC.apply(configuration[$eC.key], ruleID: Parent.identifier) - try $eC.performAfterParseOperations() if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) @@ -210,7 +205,6 @@ final class AutoApplyTests: XCTestCase { } do { try severityConfiguration.apply(configuration, ruleID: Parent.identifier) - try $severityConfiguration.performAfterParseOperations() } catch let issue as Issue where issue == Issue.nothingApplied(ruleID: Parent.identifier) { // Acceptable. Continue. } @@ -218,9 +212,7 @@ final class AutoApplyTests: XCTestCase { return } try severityConfiguration.apply(configuration[$severityConfiguration.key], ruleID: Parent.identifier) - try $severityConfiguration.performAfterParseOperations() try foo.apply(configuration[$foo.key], ruleID: Parent.identifier) - try $foo.performAfterParseOperations() if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) diff --git a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift index 4b5597d142..b0287c482a 100644 --- a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift @@ -3,12 +3,14 @@ import SwiftLintTestHelpers import XCTest class IndentationWidthRuleTests: SwiftLintTestCase { - func testInvalidIndentation() { + func testInvalidIndentation() throws { var testee = IndentationWidthConfiguration() + let defaultValue = testee.indentationWidth for indentation in [0, -1, -5] { - checkError(Issue.invalidConfiguration(ruleID: IndentationWidthRule.description.identifier)) { - try testee.apply(configuration: ["indentation_width": indentation]) - } + try testee.apply(configuration: ["indentation_width": indentation]) + + // Value remains the default. + XCTAssertEqual(testee.indentationWidth, defaultValue) } } From 04678a1d792c17be23c4bb4d6f6a34f9efaa115c Mon Sep 17 00:00:00 2001 From: Diggory Laycock Date: Thu, 25 Apr 2024 20:32:26 +0100 Subject: [PATCH 031/265] Fix plugin name (#5542) --- CHANGELOG.md | 2 +- README_CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d1ba8a71a..d9949e3025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ #### Breaking -* Rewrite `SwiftLintPlugin` using `BUILD_WORKSPACE_DIRECTORY` without relying +* Rewrite `SwiftLintBuildToolPlugin` using `BUILD_WORKSPACE_DIRECTORY` without relying on the `--config` option. [Garric Nahapetian](https://github.com/garricn) diff --git a/README_CN.md b/README_CN.md index afc8083e36..4b622bbbb6 100644 --- a/README_CN.md +++ b/README_CN.md @@ -193,7 +193,7 @@ Xcode 构建工具插件。 选择要添加修正的目标,打开 `Build Phases` 检查器。 打开 `Run Build Tool Plug-ins` 并选择 `+` 按钮。 -从列表中选择 `SwiftLintPlugin` 并将其添加到项目中。 +从列表中选择 `SwiftLintBuildToolPlugin` 并将其添加到项目中。 ![](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/select-swiftlint-plugin.png) From 5bbdf7f4e69a879961ff0a040cd4ef2e6b2db4b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 25 Apr 2024 21:37:04 +0200 Subject: [PATCH 032/265] Allow to set configuration elements as deprecated (#5540) Automatically print an appropriate warning to the console. --- Source/SwiftLintCore/Models/Issue.swift | 32 ++++++++++++++++++- .../Models/RuleConfigurationDescription.swift | 23 ++++++++++++- .../IndentationWidthRuleTests.swift | 8 +++-- .../RuleConfigurationDescriptionTests.swift | 11 ++++++- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index cb2cbc2471..b7ee200f28 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -5,6 +5,9 @@ public enum Issue: LocalizedError, Equatable { /// The configuration didn't match internal expectations. case invalidConfiguration(ruleID: String) + /// Issued when an option is deprecated. Suggests an alternative optionally. + case deprecatedConfigurationOption(ruleID: String, key: String, alternative: String? = nil) + /// Used in configuration parsing when no changes have been applied. Use only internally! case nothingApplied(ruleID: String) @@ -71,6 +74,23 @@ public enum Issue: LocalizedError, Equatable { /// Flag to enable warnings for deprecations being printed to the console. Printing is enabled by default. public static var printDeprecationWarnings = true + /// Hook used to capture all messages normally printed to stdout and return them back to the caller. + /// + /// > Warning: Shall only be used in tests to verify console output. + /// + /// - parameter runner: The code to run. Messages printed during the execution are collected. + /// + /// - returns: The collected messages produced while running the code in the runner. + static func captureConsole(runner: () throws -> Void) rethrows -> String { + var console = "" + messageConsumer = { console += $0 } + defer { messageConsumer = nil } + try runner() + return console + } + + private static var messageConsumer: ((String) -> Void)? + /// Wraps any `Error` into a `SwiftLintError.genericWarning` if it is not already a `SwiftLintError`. /// /// - parameter error: Any `Error`. @@ -102,13 +122,23 @@ public enum Issue: LocalizedError, Equatable { if case .ruleDeprecated = self, !Self.printDeprecationWarnings { return } - queuedPrintError(errorDescription) + if let consumer = Self.messageConsumer { + consumer(errorDescription) + } else { + queuedPrintError(errorDescription) + } } private var message: String { switch self { case let .invalidConfiguration(id): return "Invalid configuration for '\(id)' rule. Falling back to default." + case let .deprecatedConfigurationOption(id, key, alternative): + let baseMessage = "Configuration option '\(key)' in '\(id)' rule is deprecated." + if let alternative { + return baseMessage + " Use the option '\(alternative)' instead." + } + return baseMessage case let .nothingApplied(ruleID: id): return Self.invalidConfiguration(ruleID: id).message case let .listedMultipleTime(id, times): diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index be0cc48e18..022800c0fc 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -415,9 +415,18 @@ public protocol InlinableOptionType: AcceptableByConfigurationElement {} /// @propertyWrapper public struct ConfigurationElement: Equatable { + /// A deprecation notice. + public enum DeprecationNotice { + /// Warning suggesting an alternative option. + case suggestAlternative(ruleID: String, name: String) + } + /// Wrapped option value. public var wrappedValue: T { didSet { + if case let .suggestAlternative(id, name) = deprecationNotice { + Issue.deprecatedConfigurationOption(ruleID: id, key: key, alternative: name).print() + } if wrappedValue != oldValue { postprocessor(&wrappedValue) } @@ -437,6 +446,7 @@ public struct ConfigurationElement Void /// Default constructor. @@ -444,11 +454,20 @@ public struct ConfigurationElement Void = { _ in }) { - self.init(wrappedValue: value, key: key, inline: false, postprocessor: postprocessor) + self.init( + wrappedValue: value, + key: key, + inline: false, + deprecationNotice: deprecationNotice, + postprocessor: postprocessor + ) // Modify the set value immediately. postprocessor(&wrappedValue) @@ -488,10 +507,12 @@ public struct ConfigurationElement Void = { _ in }) { self.wrappedValue = wrappedValue self.key = key self.inline = inline + self.deprecationNotice = deprecationNotice self.postprocessor = postprocessor } diff --git a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift index b0287c482a..85b5401496 100644 --- a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift @@ -1,4 +1,5 @@ @testable import SwiftLintBuiltInRules +@testable import SwiftLintCore import SwiftLintTestHelpers import XCTest @@ -6,9 +7,12 @@ class IndentationWidthRuleTests: SwiftLintTestCase { func testInvalidIndentation() throws { var testee = IndentationWidthConfiguration() let defaultValue = testee.indentationWidth - for indentation in [0, -1, -5] { - try testee.apply(configuration: ["indentation_width": indentation]) + for indentation in [0, -1, -5] { + XCTAssertEqual( + try Issue.captureConsole { try testee.apply(configuration: ["indentation_width": indentation]) }, + "warning: Invalid configuration for 'indentation_width' rule. Falling back to default." + ) // Value remains the default. XCTAssertEqual(testee.indentationWidth, defaultValue) } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index c8719cc7f1..eee9cce120 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -29,7 +29,7 @@ class RuleConfigurationDescriptionTests: XCTestCase { postprocessor: { list in list = list.map { $0.uppercased() } } ) var list = ["string1", "string2"] - @ConfigurationElement(key: "set") + @ConfigurationElement(key: "set", deprecationNotice: .suggestAlternative(ruleID: "my_rule", name: "other_opt")) var set: Set = [1, 2, 3] @ConfigurationElement(inline: true) var severityConfig = SeverityConfiguration(.error) @@ -490,6 +490,15 @@ class RuleConfigurationDescriptionTests: XCTestCase { XCTAssertEqual(configuration.nestedSeverityLevels, SeverityLevelsConfiguration(warning: 6, error: 7)) } + func testDeprecationWarning() throws { + var configuration = TestConfiguration() + + XCTAssertEqual( + try Issue.captureConsole { try configuration.apply(configuration: ["set": [6, 7]]) }, + "warning: Configuration option 'set' in 'my_rule' rule is deprecated. Use the option 'other_opt' instead." + ) + } + func testInvalidKeys() throws { var configuration = TestConfiguration() From 7623f1e7308470b34fd86f5b97b468a94101c4fe Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 27 Apr 2024 17:43:08 +0100 Subject: [PATCH 033/265] Enable more rules in SwiftLint's own .swiftlint.yml (#5532) --- .sourcery/GeneratedTests.stencil | 2 +- .swiftlint.yml | 7 +- .../Rules/Lint/ExpiringTodoRule.swift | 4 +- .../Rules/Style/TypeContentsOrderRule.swift | 2 +- .../Configuration+FileGraphSubtypes.swift | 2 + Source/SwiftLintCore/Models/Linter.swift | 8 +- .../Models/RuleConfigurationDescription.swift | 5 +- .../Reporters/SummaryReporter.swift | 10 +- .../RegexConfiguration.swift | 2 +- .../Helpers/CompilerArgumentsExtractor.swift | 12 +- Tests/GeneratedTests/GeneratedTests.swift | 472 +++++++++--------- Tests/IntegrationTests/IntegrationTests.swift | 2 +- .../AccessControlLevelTests.swift | 2 +- .../AttributesRuleTests.swift | 2 +- .../BlanketDisableCommandRuleTests.swift | 2 +- ...hildOptionSeverityConfigurationTests.swift | 2 +- .../CodeIndentingRewriterTests.swift | 2 +- .../CollectingRuleTests.swift | 2 +- .../CollectionAlignmentRuleTests.swift | 2 +- .../ColonRuleTests.swift | 2 +- .../CommandTests.swift | 2 +- .../CompilerProtocolInitRuleTests.swift | 2 +- .../ComputedAccessorsOrderRuleTests.swift | 2 +- ...ConditionalReturnsOnNewlineRuleTests.swift | 2 +- .../ConfigurationTests.swift | 4 +- .../ContainsOverFirstNotNilRuleTests.swift | 2 +- .../CustomRulesTests.swift | 2 +- ...clomaticComplexityConfigurationTests.swift | 2 +- .../CyclomaticComplexityRuleTests.swift | 2 +- .../DeploymentTargetConfigurationTests.swift | 2 +- .../DeploymentTargetRuleTests.swift | 2 +- .../DisableAllTests.swift | 2 +- .../DiscouragedDirectInitRuleTests.swift | 2 +- .../DiscouragedObjectLiteralRuleTests.swift | 2 +- .../DuplicateImportsRuleTests.swift | 2 +- .../EmptyCountRuleTests.swift | 2 +- .../ExampleTests.swift | 2 +- .../ExpiringTodoRuleTests.swift | 2 +- .../ExplicitInitRuleTests.swift | 2 +- ...licitTypeInterfaceConfigurationTests.swift | 2 +- .../ExplicitTypeInterfaceRuleTests.swift | 2 +- .../ExtendedNSStringTests.swift | 2 +- .../ExtendedStringTests.swift | 2 +- .../FileHeaderRuleTests.swift | 2 +- .../FileLengthRuleTests.swift | 2 +- .../FileNameNoSpaceRuleTests.swift | 2 +- .../FileNameRuleTests.swift | 2 +- .../FileTypesOrderRuleTests.swift | 2 +- .../FunctionBodyLengthRuleTests.swift | 2 +- .../FunctionParameterCountRuleTests.swift | 2 +- .../GenericTypeNameRuleTests.swift | 2 +- .../IdentifierNameRuleTests.swift | 2 +- .../ImplicitReturnConfigurationTests.swift | 2 +- .../ImplicitReturnRuleTests.swift | 2 +- ...yUnwrappedOptionalConfigurationTests.swift | 2 +- ...ImplicitlyUnwrappedOptionalRuleTests.swift | 2 +- .../InclusiveLanguageRuleTests.swift | 2 +- .../IndentationWidthRuleTests.swift | 2 +- .../LineEndingTests.swift | 2 +- .../LineLengthConfigurationTests.swift | 2 +- .../LineLengthRuleTests.swift | 2 +- .../LinterCacheTests.swift | 2 +- .../MissingDocsRuleTests.swift | 2 +- .../ModifierOrderTests.swift | 2 +- .../MultilineArgumentsRuleTests.swift | 2 +- .../NameConfigurationTests.swift | 2 +- .../NestingRuleTests.swift | 2 +- .../NumberSeparatorRuleTests.swift | 2 +- .../ObjectLiteralRuleTests.swift | 2 +- .../OpeningBraceRuleTests.swift | 2 +- .../PrivateOverFilePrivateRuleTests.swift | 2 +- .../RegexConfigurationTests.swift | 2 +- .../SwiftLintFrameworkTests/RegionTests.swift | 2 +- .../ReporterTests.swift | 2 +- .../RequiredEnumCaseConfigurationTests.swift | 2 +- .../BoolExtensionTests.swift | 2 +- .../RuleConfigurationDescriptionTests.swift | 2 +- .../RuleConfigurationTests.swift | 2 +- Tests/SwiftLintFrameworkTests/RuleTests.swift | 2 +- .../SwiftLintFrameworkTests/RulesTests.swift | 2 +- .../SourceKitCrashTests.swift | 2 +- .../StatementPositionRuleTests.swift | 2 +- .../SwiftLintFileTests.swift | 2 +- .../SwitchCaseAlignmentRuleTests.swift | 2 +- .../TodoRuleTests.swift | 2 +- .../TrailingClosureConfigurationTests.swift | 2 +- .../TrailingClosureRuleTests.swift | 2 +- .../TrailingCommaRuleTests.swift | 2 +- .../TrailingWhitespaceRuleTests.swift | 2 +- .../TypeContentsOrderRuleTests.swift | 2 +- .../TypeNameRuleTests.swift | 2 +- .../UnneededOverrideRuleTests.swift | 2 +- .../UnusedDeclarationConfigurationTests.swift | 2 +- .../UnusedOptionalBindingRuleTests.swift | 2 +- .../VerticalWhitespaceRuleTests.swift | 2 +- .../XCTSpecificMatcherRuleTests.swift | 2 +- .../YamlParserTests.swift | 2 +- .../YamlSwiftLintTests.swift | 2 +- 98 files changed, 348 insertions(+), 354 deletions(-) diff --git a/.sourcery/GeneratedTests.stencil b/.sourcery/GeneratedTests.stencil index 6b9dc8a71e..cd6f14c0fc 100644 --- a/.sourcery/GeneratedTests.stencil +++ b/.sourcery/GeneratedTests.stencil @@ -7,7 +7,7 @@ import SwiftLintTestHelpers {% for rule in types.structs %} {% if rule.name|hasSuffix:"Rule" %} -class {{ rule.name }}GeneratedTests: SwiftLintTestCase { +final class {{ rule.name }}GeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule({{ rule.name }}.description) } diff --git a/.swiftlint.yml b/.swiftlint.yml index 0cf6fd23ee..beb81d93dd 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -21,11 +21,9 @@ disabled_rules: - explicit_top_level_acl - explicit_type_interface - file_types_order - - final_test_case - force_unwrapping - function_default_parameter_at_end - implicit_return - - implicitly_unwrapped_optional - indentation_width - inert_defer - missing_docs @@ -43,11 +41,8 @@ disabled_rules: - prefer_nimble - prefer_self_in_static_references - prefixed_toplevel_constant - - redundant_self_in_closure - required_deinit - - self_binding - static_over_final_class - - shorthand_argument - sorted_enum_cases - strict_fileprivate - switch_case_on_newline @@ -84,7 +79,7 @@ balanced_xctest_lifecycle: &unit_test_configuration - XCTestCase empty_xctest_method: *unit_test_configuration single_test_class: *unit_test_configuration - +final_test_case: *unit_test_configuration function_body_length: 60 type_body_length: 400 diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift index 851128a234..3e395a3bf6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift @@ -59,8 +59,8 @@ struct ExpiringTodoRule: OptInRule { syntaxKinds.allSatisfy({ $0.isCommentLike }), checkingResult.numberOfRanges > 1, case let range = checkingResult.range(at: 1), - let violationLevel = self.violationLevel(for: expiryDate(file: file, range: range)), - let severity = self.severity(for: violationLevel) else { + let violationLevel = violationLevel(for: expiryDate(file: file, range: range)), + let severity = severity(for: violationLevel) else { return nil } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift index 57f4082adf..62cf3fe0e3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift @@ -69,7 +69,7 @@ struct TypeContentsOrderRule: OptInRule { private func typeContentOffsets(in typeStructure: SourceKittenDictionary) -> [TypeContentOffset] { return typeStructure.substructure.compactMap { typeContentStructure in - guard let typeContent = self.typeContent(for: typeContentStructure) else { return nil } + guard let typeContent = typeContent(for: typeContentStructure) else { return nil } return (typeContent, typeContentStructure.offset!) } } diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift index 8fb43be37d..431fbd0faa 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift @@ -95,8 +95,10 @@ internal extension Configuration.FileGraph { // MARK: - Edge struct Edge: Hashable { + // swiftlint:disable implicitly_unwrapped_optional var parent: Vertex! var child: Vertex! + // swiftlint:enable implicitly_unwrapped_optional } // MARK: - EdgeType diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index f2d202977c..3572200b28 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -233,11 +233,11 @@ public struct CollectedLinter { $0 is SuperfluousDisableCommandRule }) as? SuperfluousDisableCommandRule let validationResults = rules.parallelCompactMap { - $0.lint(file: self.file, regions: regions, benchmark: benchmark, + $0.lint(file: file, regions: regions, benchmark: benchmark, storage: storage, - configuration: self.configuration, + configuration: configuration, superfluousDisableCommandRule: superfluousDisableCommandRule, - compilerArguments: self.compilerArguments) + compilerArguments: compilerArguments) } let undefinedSuperfluousCommandViolations = self.undefinedSuperfluousCommandViolations( regions: regions, configuration: configuration, @@ -265,7 +265,7 @@ public struct CollectedLinter { } private func cachedStyleViolations(benchmark: Bool = false) -> ([StyleViolation], [(id: String, time: Double)])? { - let start: Date! = benchmark ? Date() : nil + let start = Date() guard let cache, let file = file.path, let cachedViolations = cache.violations(forFile: file, configuration: configuration) else { return nil diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index 022800c0fc..ce3f091476 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -531,10 +531,7 @@ extension ConfigurationElement: AnyConfigurationElement { extension Optional: AcceptableByConfigurationElement where Wrapped: AcceptableByConfigurationElement { public func asOption() -> OptionType { - if let value = self { - return value.asOption() - } - return .empty + self?.asOption() ?? .empty } public init(fromAny value: Any, context ruleID: String) throws { diff --git a/Source/SwiftLintCore/Reporters/SummaryReporter.swift b/Source/SwiftLintCore/Reporters/SummaryReporter.swift index ba85a20259..d8a0656114 100644 --- a/Source/SwiftLintCore/Reporters/SummaryReporter.swift +++ b/Source/SwiftLintCore/Reporters/SummaryReporter.swift @@ -37,17 +37,17 @@ private extension TextTable { self.init(columns: columns) let ruleIdentifiersToViolationsMap = violations.group { $0.ruleIdentifier } - let sortedRuleIdentifiers = ruleIdentifiersToViolationsMap.keys.sorted { - let count1 = ruleIdentifiersToViolationsMap[$0]?.count ?? 0 - let count2 = ruleIdentifiersToViolationsMap[$1]?.count ?? 0 + let sortedRuleIdentifiers = ruleIdentifiersToViolationsMap.sorted { lhs, rhs in + let count1 = lhs.value.count + let count2 = rhs.value.count if count1 > count2 { return true } if count1 == count2 { - return $0 < $1 + return lhs.key < rhs.key } return false - } + }.map(\.key) var totalNumberOfWarnings = 0 var totalNumberOfErrors = 0 diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index 8a4f354629..e955060e3e 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -12,7 +12,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, public var message = "Regex matched" /// The regular expression to apply to trigger violations for this custom rule. @ConfigurationElement(key: "regex") - var regex: RegularExpression! + var regex: RegularExpression! // swiftlint:disable:this implicitly_unwrapped_optional /// Regular expressions to include when matching the file path. public var included: [NSRegularExpression] = [] /// Regular expressions to exclude when matching the file path. diff --git a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift index 71a60e7409..d0cf23c514 100644 --- a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift +++ b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift @@ -88,22 +88,22 @@ extension Array where Element == String { (args, shouldContinueToFilterArguments) = partiallyFilter(arguments: args) } - return args.filter { + return args.filter { arg in ![ "-parseable-output", "-incremental", "-serialize-diagnostics", "-emit-dependencies", "-use-frontend-parseable-output" - ].contains($0) - }.map { - if $0 == "-O" { + ].contains(arg) + }.map { arg in + if arg == "-O" { return "-Onone" } - if $0 == "-DNDEBUG=1" { + if arg == "-DNDEBUG=1" { return "-DDEBUG=1" } - return $0 + return arg } } } diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 2da52685e7..25d750903f 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -7,1417 +7,1417 @@ import SwiftLintTestHelpers // swiftlint:disable:next blanket_disable_command // swiftlint:disable file_length single_test_class type_name -class AccessibilityLabelForImageRuleGeneratedTests: SwiftLintTestCase { +final class AccessibilityLabelForImageRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(AccessibilityLabelForImageRule.description) } } -class AccessibilityTraitForButtonRuleGeneratedTests: SwiftLintTestCase { +final class AccessibilityTraitForButtonRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(AccessibilityTraitForButtonRule.description) } } -class AnonymousArgumentInMultilineClosureRuleGeneratedTests: SwiftLintTestCase { +final class AnonymousArgumentInMultilineClosureRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(AnonymousArgumentInMultilineClosureRule.description) } } -class AnyObjectProtocolRuleGeneratedTests: SwiftLintTestCase { +final class AnyObjectProtocolRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(AnyObjectProtocolRule.description) } } -class ArrayInitRuleGeneratedTests: SwiftLintTestCase { +final class ArrayInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ArrayInitRule.description) } } -class AttributesRuleGeneratedTests: SwiftLintTestCase { +final class AttributesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(AttributesRule.description) } } -class BalancedXCTestLifecycleRuleGeneratedTests: SwiftLintTestCase { +final class BalancedXCTestLifecycleRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(BalancedXCTestLifecycleRule.description) } } -class BlanketDisableCommandRuleGeneratedTests: SwiftLintTestCase { +final class BlanketDisableCommandRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(BlanketDisableCommandRule.description) } } -class BlockBasedKVORuleGeneratedTests: SwiftLintTestCase { +final class BlockBasedKVORuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(BlockBasedKVORule.description) } } -class CaptureVariableRuleGeneratedTests: SwiftLintTestCase { +final class CaptureVariableRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(CaptureVariableRule.description) } } -class ClassDelegateProtocolRuleGeneratedTests: SwiftLintTestCase { +final class ClassDelegateProtocolRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ClassDelegateProtocolRule.description) } } -class ClosingBraceRuleGeneratedTests: SwiftLintTestCase { +final class ClosingBraceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ClosingBraceRule.description) } } -class ClosureBodyLengthRuleGeneratedTests: SwiftLintTestCase { +final class ClosureBodyLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ClosureBodyLengthRule.description) } } -class ClosureEndIndentationRuleGeneratedTests: SwiftLintTestCase { +final class ClosureEndIndentationRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ClosureEndIndentationRule.description) } } -class ClosureParameterPositionRuleGeneratedTests: SwiftLintTestCase { +final class ClosureParameterPositionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ClosureParameterPositionRule.description) } } -class ClosureSpacingRuleGeneratedTests: SwiftLintTestCase { +final class ClosureSpacingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ClosureSpacingRule.description) } } -class CollectionAlignmentRuleGeneratedTests: SwiftLintTestCase { +final class CollectionAlignmentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(CollectionAlignmentRule.description) } } -class ColonRuleGeneratedTests: SwiftLintTestCase { +final class ColonRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ColonRule.description) } } -class CommaInheritanceRuleGeneratedTests: SwiftLintTestCase { +final class CommaInheritanceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(CommaInheritanceRule.description) } } -class CommaRuleGeneratedTests: SwiftLintTestCase { +final class CommaRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(CommaRule.description) } } -class CommentSpacingRuleGeneratedTests: SwiftLintTestCase { +final class CommentSpacingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(CommentSpacingRule.description) } } -class CompilerProtocolInitRuleGeneratedTests: SwiftLintTestCase { +final class CompilerProtocolInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(CompilerProtocolInitRule.description) } } -class ComputedAccessorsOrderRuleGeneratedTests: SwiftLintTestCase { +final class ComputedAccessorsOrderRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ComputedAccessorsOrderRule.description) } } -class ConditionalReturnsOnNewlineRuleGeneratedTests: SwiftLintTestCase { +final class ConditionalReturnsOnNewlineRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ConditionalReturnsOnNewlineRule.description) } } -class ContainsOverFilterCountRuleGeneratedTests: SwiftLintTestCase { +final class ContainsOverFilterCountRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ContainsOverFilterCountRule.description) } } -class ContainsOverFilterIsEmptyRuleGeneratedTests: SwiftLintTestCase { +final class ContainsOverFilterIsEmptyRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ContainsOverFilterIsEmptyRule.description) } } -class ContainsOverFirstNotNilRuleGeneratedTests: SwiftLintTestCase { +final class ContainsOverFirstNotNilRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ContainsOverFirstNotNilRule.description) } } -class ContainsOverRangeNilComparisonRuleGeneratedTests: SwiftLintTestCase { +final class ContainsOverRangeNilComparisonRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ContainsOverRangeNilComparisonRule.description) } } -class ControlStatementRuleGeneratedTests: SwiftLintTestCase { +final class ControlStatementRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ControlStatementRule.description) } } -class ConvenienceTypeRuleGeneratedTests: SwiftLintTestCase { +final class ConvenienceTypeRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ConvenienceTypeRule.description) } } -class CyclomaticComplexityRuleGeneratedTests: SwiftLintTestCase { +final class CyclomaticComplexityRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(CyclomaticComplexityRule.description) } } -class DeploymentTargetRuleGeneratedTests: SwiftLintTestCase { +final class DeploymentTargetRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DeploymentTargetRule.description) } } -class DirectReturnRuleGeneratedTests: SwiftLintTestCase { +final class DirectReturnRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DirectReturnRule.description) } } -class DiscardedNotificationCenterObserverRuleGeneratedTests: SwiftLintTestCase { +final class DiscardedNotificationCenterObserverRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DiscardedNotificationCenterObserverRule.description) } } -class DiscouragedAssertRuleGeneratedTests: SwiftLintTestCase { +final class DiscouragedAssertRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DiscouragedAssertRule.description) } } -class DiscouragedDirectInitRuleGeneratedTests: SwiftLintTestCase { +final class DiscouragedDirectInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DiscouragedDirectInitRule.description) } } -class DiscouragedNoneNameRuleGeneratedTests: SwiftLintTestCase { +final class DiscouragedNoneNameRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DiscouragedNoneNameRule.description) } } -class DiscouragedObjectLiteralRuleGeneratedTests: SwiftLintTestCase { +final class DiscouragedObjectLiteralRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DiscouragedObjectLiteralRule.description) } } -class DiscouragedOptionalBooleanRuleGeneratedTests: SwiftLintTestCase { +final class DiscouragedOptionalBooleanRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DiscouragedOptionalBooleanRule.description) } } -class DiscouragedOptionalCollectionRuleGeneratedTests: SwiftLintTestCase { +final class DiscouragedOptionalCollectionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DiscouragedOptionalCollectionRule.description) } } -class DuplicateConditionsRuleGeneratedTests: SwiftLintTestCase { +final class DuplicateConditionsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DuplicateConditionsRule.description) } } -class DuplicateEnumCasesRuleGeneratedTests: SwiftLintTestCase { +final class DuplicateEnumCasesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DuplicateEnumCasesRule.description) } } -class DuplicateImportsRuleGeneratedTests: SwiftLintTestCase { +final class DuplicateImportsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DuplicateImportsRule.description) } } -class DuplicatedKeyInDictionaryLiteralRuleGeneratedTests: SwiftLintTestCase { +final class DuplicatedKeyInDictionaryLiteralRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DuplicatedKeyInDictionaryLiteralRule.description) } } -class DynamicInlineRuleGeneratedTests: SwiftLintTestCase { +final class DynamicInlineRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(DynamicInlineRule.description) } } -class EmptyCollectionLiteralRuleGeneratedTests: SwiftLintTestCase { +final class EmptyCollectionLiteralRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EmptyCollectionLiteralRule.description) } } -class EmptyCountRuleGeneratedTests: SwiftLintTestCase { +final class EmptyCountRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EmptyCountRule.description) } } -class EmptyEnumArgumentsRuleGeneratedTests: SwiftLintTestCase { +final class EmptyEnumArgumentsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EmptyEnumArgumentsRule.description) } } -class EmptyParametersRuleGeneratedTests: SwiftLintTestCase { +final class EmptyParametersRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EmptyParametersRule.description) } } -class EmptyParenthesesWithTrailingClosureRuleGeneratedTests: SwiftLintTestCase { +final class EmptyParenthesesWithTrailingClosureRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EmptyParenthesesWithTrailingClosureRule.description) } } -class EmptyStringRuleGeneratedTests: SwiftLintTestCase { +final class EmptyStringRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EmptyStringRule.description) } } -class EmptyXCTestMethodRuleGeneratedTests: SwiftLintTestCase { +final class EmptyXCTestMethodRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EmptyXCTestMethodRule.description) } } -class EnumCaseAssociatedValuesLengthRuleGeneratedTests: SwiftLintTestCase { +final class EnumCaseAssociatedValuesLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(EnumCaseAssociatedValuesLengthRule.description) } } -class ExpiringTodoRuleGeneratedTests: SwiftLintTestCase { +final class ExpiringTodoRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExpiringTodoRule.description) } } -class ExplicitACLRuleGeneratedTests: SwiftLintTestCase { +final class ExplicitACLRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExplicitACLRule.description) } } -class ExplicitEnumRawValueRuleGeneratedTests: SwiftLintTestCase { +final class ExplicitEnumRawValueRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExplicitEnumRawValueRule.description) } } -class ExplicitInitRuleGeneratedTests: SwiftLintTestCase { +final class ExplicitInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExplicitInitRule.description) } } -class ExplicitSelfRuleGeneratedTests: SwiftLintTestCase { +final class ExplicitSelfRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExplicitSelfRule.description) } } -class ExplicitTopLevelACLRuleGeneratedTests: SwiftLintTestCase { +final class ExplicitTopLevelACLRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExplicitTopLevelACLRule.description) } } -class ExplicitTypeInterfaceRuleGeneratedTests: SwiftLintTestCase { +final class ExplicitTypeInterfaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExplicitTypeInterfaceRule.description) } } -class ExtensionAccessModifierRuleGeneratedTests: SwiftLintTestCase { +final class ExtensionAccessModifierRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExtensionAccessModifierRule.description) } } -class FallthroughRuleGeneratedTests: SwiftLintTestCase { +final class FallthroughRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FallthroughRule.description) } } -class FatalErrorMessageRuleGeneratedTests: SwiftLintTestCase { +final class FatalErrorMessageRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FatalErrorMessageRule.description) } } -class FileHeaderRuleGeneratedTests: SwiftLintTestCase { +final class FileHeaderRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FileHeaderRule.description) } } -class FileLengthRuleGeneratedTests: SwiftLintTestCase { +final class FileLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FileLengthRule.description) } } -class FileNameNoSpaceRuleGeneratedTests: SwiftLintTestCase { +final class FileNameNoSpaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FileNameNoSpaceRule.description) } } -class FileNameRuleGeneratedTests: SwiftLintTestCase { +final class FileNameRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FileNameRule.description) } } -class FileTypesOrderRuleGeneratedTests: SwiftLintTestCase { +final class FileTypesOrderRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FileTypesOrderRule.description) } } -class FinalTestCaseRuleGeneratedTests: SwiftLintTestCase { +final class FinalTestCaseRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FinalTestCaseRule.description) } } -class FirstWhereRuleGeneratedTests: SwiftLintTestCase { +final class FirstWhereRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FirstWhereRule.description) } } -class FlatMapOverMapReduceRuleGeneratedTests: SwiftLintTestCase { +final class FlatMapOverMapReduceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FlatMapOverMapReduceRule.description) } } -class ForWhereRuleGeneratedTests: SwiftLintTestCase { +final class ForWhereRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ForWhereRule.description) } } -class ForceCastRuleGeneratedTests: SwiftLintTestCase { +final class ForceCastRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ForceCastRule.description) } } -class ForceTryRuleGeneratedTests: SwiftLintTestCase { +final class ForceTryRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ForceTryRule.description) } } -class ForceUnwrappingRuleGeneratedTests: SwiftLintTestCase { +final class ForceUnwrappingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ForceUnwrappingRule.description) } } -class FunctionBodyLengthRuleGeneratedTests: SwiftLintTestCase { +final class FunctionBodyLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FunctionBodyLengthRule.description) } } -class FunctionDefaultParameterAtEndRuleGeneratedTests: SwiftLintTestCase { +final class FunctionDefaultParameterAtEndRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FunctionDefaultParameterAtEndRule.description) } } -class FunctionParameterCountRuleGeneratedTests: SwiftLintTestCase { +final class FunctionParameterCountRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(FunctionParameterCountRule.description) } } -class GenericTypeNameRuleGeneratedTests: SwiftLintTestCase { +final class GenericTypeNameRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(GenericTypeNameRule.description) } } -class IBInspectableInExtensionRuleGeneratedTests: SwiftLintTestCase { +final class IBInspectableInExtensionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(IBInspectableInExtensionRule.description) } } -class IdenticalOperandsRuleGeneratedTests: SwiftLintTestCase { +final class IdenticalOperandsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(IdenticalOperandsRule.description) } } -class IdentifierNameRuleGeneratedTests: SwiftLintTestCase { +final class IdentifierNameRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(IdentifierNameRule.description) } } -class ImplicitGetterRuleGeneratedTests: SwiftLintTestCase { +final class ImplicitGetterRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ImplicitGetterRule.description) } } -class ImplicitReturnRuleGeneratedTests: SwiftLintTestCase { +final class ImplicitReturnRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ImplicitReturnRule.description) } } -class ImplicitlyUnwrappedOptionalRuleGeneratedTests: SwiftLintTestCase { +final class ImplicitlyUnwrappedOptionalRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ImplicitlyUnwrappedOptionalRule.description) } } -class InclusiveLanguageRuleGeneratedTests: SwiftLintTestCase { +final class InclusiveLanguageRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(InclusiveLanguageRule.description) } } -class IndentationWidthRuleGeneratedTests: SwiftLintTestCase { +final class IndentationWidthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(IndentationWidthRule.description) } } -class InertDeferRuleGeneratedTests: SwiftLintTestCase { +final class InertDeferRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(InertDeferRule.description) } } -class InvalidSwiftLintCommandRuleGeneratedTests: SwiftLintTestCase { +final class InvalidSwiftLintCommandRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(InvalidSwiftLintCommandRule.description) } } -class IsDisjointRuleGeneratedTests: SwiftLintTestCase { +final class IsDisjointRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(IsDisjointRule.description) } } -class JoinedDefaultParameterRuleGeneratedTests: SwiftLintTestCase { +final class JoinedDefaultParameterRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(JoinedDefaultParameterRule.description) } } -class LargeTupleRuleGeneratedTests: SwiftLintTestCase { +final class LargeTupleRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LargeTupleRule.description) } } -class LastWhereRuleGeneratedTests: SwiftLintTestCase { +final class LastWhereRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LastWhereRule.description) } } -class LeadingWhitespaceRuleGeneratedTests: SwiftLintTestCase { +final class LeadingWhitespaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LeadingWhitespaceRule.description) } } -class LegacyCGGeometryFunctionsRuleGeneratedTests: SwiftLintTestCase { +final class LegacyCGGeometryFunctionsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyCGGeometryFunctionsRule.description) } } -class LegacyConstantRuleGeneratedTests: SwiftLintTestCase { +final class LegacyConstantRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyConstantRule.description) } } -class LegacyConstructorRuleGeneratedTests: SwiftLintTestCase { +final class LegacyConstructorRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyConstructorRule.description) } } -class LegacyHashingRuleGeneratedTests: SwiftLintTestCase { +final class LegacyHashingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyHashingRule.description) } } -class LegacyMultipleRuleGeneratedTests: SwiftLintTestCase { +final class LegacyMultipleRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyMultipleRule.description) } } -class LegacyNSGeometryFunctionsRuleGeneratedTests: SwiftLintTestCase { +final class LegacyNSGeometryFunctionsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyNSGeometryFunctionsRule.description) } } -class LegacyObjcTypeRuleGeneratedTests: SwiftLintTestCase { +final class LegacyObjcTypeRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyObjcTypeRule.description) } } -class LegacyRandomRuleGeneratedTests: SwiftLintTestCase { +final class LegacyRandomRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyRandomRule.description) } } -class LetVarWhitespaceRuleGeneratedTests: SwiftLintTestCase { +final class LetVarWhitespaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LetVarWhitespaceRule.description) } } -class LineLengthRuleGeneratedTests: SwiftLintTestCase { +final class LineLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LineLengthRule.description) } } -class LiteralExpressionEndIndentationRuleGeneratedTests: SwiftLintTestCase { +final class LiteralExpressionEndIndentationRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LiteralExpressionEndIndentationRule.description) } } -class LocalDocCommentRuleGeneratedTests: SwiftLintTestCase { +final class LocalDocCommentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LocalDocCommentRule.description) } } -class LowerACLThanParentRuleGeneratedTests: SwiftLintTestCase { +final class LowerACLThanParentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LowerACLThanParentRule.description) } } -class MarkRuleGeneratedTests: SwiftLintTestCase { +final class MarkRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MarkRule.description) } } -class MissingDocsRuleGeneratedTests: SwiftLintTestCase { +final class MissingDocsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MissingDocsRule.description) } } -class ModifierOrderRuleGeneratedTests: SwiftLintTestCase { +final class ModifierOrderRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ModifierOrderRule.description) } } -class MultilineArgumentsBracketsRuleGeneratedTests: SwiftLintTestCase { +final class MultilineArgumentsBracketsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineArgumentsBracketsRule.description) } } -class MultilineArgumentsRuleGeneratedTests: SwiftLintTestCase { +final class MultilineArgumentsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineArgumentsRule.description) } } -class MultilineFunctionChainsRuleGeneratedTests: SwiftLintTestCase { +final class MultilineFunctionChainsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineFunctionChainsRule.description) } } -class MultilineLiteralBracketsRuleGeneratedTests: SwiftLintTestCase { +final class MultilineLiteralBracketsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineLiteralBracketsRule.description) } } -class MultilineParametersBracketsRuleGeneratedTests: SwiftLintTestCase { +final class MultilineParametersBracketsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineParametersBracketsRule.description) } } -class MultilineParametersRuleGeneratedTests: SwiftLintTestCase { +final class MultilineParametersRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MultilineParametersRule.description) } } -class MultipleClosuresWithTrailingClosureRuleGeneratedTests: SwiftLintTestCase { +final class MultipleClosuresWithTrailingClosureRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(MultipleClosuresWithTrailingClosureRule.description) } } -class NSLocalizedStringKeyRuleGeneratedTests: SwiftLintTestCase { +final class NSLocalizedStringKeyRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NSLocalizedStringKeyRule.description) } } -class NSLocalizedStringRequireBundleRuleGeneratedTests: SwiftLintTestCase { +final class NSLocalizedStringRequireBundleRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NSLocalizedStringRequireBundleRule.description) } } -class NSNumberInitAsFunctionReferenceRuleGeneratedTests: SwiftLintTestCase { +final class NSNumberInitAsFunctionReferenceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NSNumberInitAsFunctionReferenceRule.description) } } -class NSObjectPreferIsEqualRuleGeneratedTests: SwiftLintTestCase { +final class NSObjectPreferIsEqualRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NSObjectPreferIsEqualRule.description) } } -class NestingRuleGeneratedTests: SwiftLintTestCase { +final class NestingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NestingRule.description) } } -class NimbleOperatorRuleGeneratedTests: SwiftLintTestCase { +final class NimbleOperatorRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NimbleOperatorRule.description) } } -class NoExtensionAccessModifierRuleGeneratedTests: SwiftLintTestCase { +final class NoExtensionAccessModifierRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NoExtensionAccessModifierRule.description) } } -class NoFallthroughOnlyRuleGeneratedTests: SwiftLintTestCase { +final class NoFallthroughOnlyRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NoFallthroughOnlyRule.description) } } -class NoGroupingExtensionRuleGeneratedTests: SwiftLintTestCase { +final class NoGroupingExtensionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NoGroupingExtensionRule.description) } } -class NoMagicNumbersRuleGeneratedTests: SwiftLintTestCase { +final class NoMagicNumbersRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NoMagicNumbersRule.description) } } -class NoSpaceInMethodCallRuleGeneratedTests: SwiftLintTestCase { +final class NoSpaceInMethodCallRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NoSpaceInMethodCallRule.description) } } -class NonOptionalStringDataConversionRuleGeneratedTests: SwiftLintTestCase { +final class NonOptionalStringDataConversionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NonOptionalStringDataConversionRule.description) } } -class NonOverridableClassDeclarationRuleGeneratedTests: SwiftLintTestCase { +final class NonOverridableClassDeclarationRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NonOverridableClassDeclarationRule.description) } } -class NotificationCenterDetachmentRuleGeneratedTests: SwiftLintTestCase { +final class NotificationCenterDetachmentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NotificationCenterDetachmentRule.description) } } -class NumberSeparatorRuleGeneratedTests: SwiftLintTestCase { +final class NumberSeparatorRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NumberSeparatorRule.description) } } -class ObjectLiteralRuleGeneratedTests: SwiftLintTestCase { +final class ObjectLiteralRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ObjectLiteralRule.description) } } -class OneDelarationPerFileRuleGeneratedTests: SwiftLintTestCase { +final class OneDelarationPerFileRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OneDelarationPerFileRule.description) } } -class OpeningBraceRuleGeneratedTests: SwiftLintTestCase { +final class OpeningBraceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OpeningBraceRule.description) } } -class OperatorFunctionWhitespaceRuleGeneratedTests: SwiftLintTestCase { +final class OperatorFunctionWhitespaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OperatorFunctionWhitespaceRule.description) } } -class OperatorUsageWhitespaceRuleGeneratedTests: SwiftLintTestCase { +final class OperatorUsageWhitespaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OperatorUsageWhitespaceRule.description) } } -class OptionalEnumCaseMatchingRuleGeneratedTests: SwiftLintTestCase { +final class OptionalEnumCaseMatchingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OptionalEnumCaseMatchingRule.description) } } -class OrphanedDocCommentRuleGeneratedTests: SwiftLintTestCase { +final class OrphanedDocCommentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OrphanedDocCommentRule.description) } } -class OverriddenSuperCallRuleGeneratedTests: SwiftLintTestCase { +final class OverriddenSuperCallRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OverriddenSuperCallRule.description) } } -class OverrideInExtensionRuleGeneratedTests: SwiftLintTestCase { +final class OverrideInExtensionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OverrideInExtensionRule.description) } } -class PatternMatchingKeywordsRuleGeneratedTests: SwiftLintTestCase { +final class PatternMatchingKeywordsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PatternMatchingKeywordsRule.description) } } -class PeriodSpacingRuleGeneratedTests: SwiftLintTestCase { +final class PeriodSpacingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PeriodSpacingRule.description) } } -class PreferNimbleRuleGeneratedTests: SwiftLintTestCase { +final class PreferNimbleRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PreferNimbleRule.description) } } -class PreferSelfInStaticReferencesRuleGeneratedTests: SwiftLintTestCase { +final class PreferSelfInStaticReferencesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PreferSelfInStaticReferencesRule.description) } } -class PreferSelfTypeOverTypeOfSelfRuleGeneratedTests: SwiftLintTestCase { +final class PreferSelfTypeOverTypeOfSelfRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PreferSelfTypeOverTypeOfSelfRule.description) } } -class PreferZeroOverExplicitInitRuleGeneratedTests: SwiftLintTestCase { +final class PreferZeroOverExplicitInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PreferZeroOverExplicitInitRule.description) } } -class PrefixedTopLevelConstantRuleGeneratedTests: SwiftLintTestCase { +final class PrefixedTopLevelConstantRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PrefixedTopLevelConstantRule.description) } } -class PrivateActionRuleGeneratedTests: SwiftLintTestCase { +final class PrivateActionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PrivateActionRule.description) } } -class PrivateOutletRuleGeneratedTests: SwiftLintTestCase { +final class PrivateOutletRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PrivateOutletRule.description) } } -class PrivateOverFilePrivateRuleGeneratedTests: SwiftLintTestCase { +final class PrivateOverFilePrivateRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PrivateOverFilePrivateRule.description) } } -class PrivateSubjectRuleGeneratedTests: SwiftLintTestCase { +final class PrivateSubjectRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PrivateSubjectRule.description) } } -class PrivateSwiftUIStatePropertyRuleGeneratedTests: SwiftLintTestCase { +final class PrivateSwiftUIStatePropertyRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PrivateSwiftUIStatePropertyRule.description) } } -class PrivateUnitTestRuleGeneratedTests: SwiftLintTestCase { +final class PrivateUnitTestRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PrivateUnitTestRule.description) } } -class ProhibitedInterfaceBuilderRuleGeneratedTests: SwiftLintTestCase { +final class ProhibitedInterfaceBuilderRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ProhibitedInterfaceBuilderRule.description) } } -class ProhibitedSuperRuleGeneratedTests: SwiftLintTestCase { +final class ProhibitedSuperRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ProhibitedSuperRule.description) } } -class ProtocolPropertyAccessorsOrderRuleGeneratedTests: SwiftLintTestCase { +final class ProtocolPropertyAccessorsOrderRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ProtocolPropertyAccessorsOrderRule.description) } } -class QuickDiscouragedCallRuleGeneratedTests: SwiftLintTestCase { +final class QuickDiscouragedCallRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(QuickDiscouragedCallRule.description) } } -class QuickDiscouragedFocusedTestRuleGeneratedTests: SwiftLintTestCase { +final class QuickDiscouragedFocusedTestRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(QuickDiscouragedFocusedTestRule.description) } } -class QuickDiscouragedPendingTestRuleGeneratedTests: SwiftLintTestCase { +final class QuickDiscouragedPendingTestRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(QuickDiscouragedPendingTestRule.description) } } -class RawValueForCamelCasedCodableEnumRuleGeneratedTests: SwiftLintTestCase { +final class RawValueForCamelCasedCodableEnumRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RawValueForCamelCasedCodableEnumRule.description) } } -class ReduceBooleanRuleGeneratedTests: SwiftLintTestCase { +final class ReduceBooleanRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ReduceBooleanRule.description) } } -class ReduceIntoRuleGeneratedTests: SwiftLintTestCase { +final class ReduceIntoRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ReduceIntoRule.description) } } -class RedundantDiscardableLetRuleGeneratedTests: SwiftLintTestCase { +final class RedundantDiscardableLetRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantDiscardableLetRule.description) } } -class RedundantNilCoalescingRuleGeneratedTests: SwiftLintTestCase { +final class RedundantNilCoalescingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantNilCoalescingRule.description) } } -class RedundantObjcAttributeRuleGeneratedTests: SwiftLintTestCase { +final class RedundantObjcAttributeRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantObjcAttributeRule.description) } } -class RedundantOptionalInitializationRuleGeneratedTests: SwiftLintTestCase { +final class RedundantOptionalInitializationRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantOptionalInitializationRule.description) } } -class RedundantSelfInClosureRuleGeneratedTests: SwiftLintTestCase { +final class RedundantSelfInClosureRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantSelfInClosureRule.description) } } -class RedundantSetAccessControlRuleGeneratedTests: SwiftLintTestCase { +final class RedundantSetAccessControlRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantSetAccessControlRule.description) } } -class RedundantStringEnumValueRuleGeneratedTests: SwiftLintTestCase { +final class RedundantStringEnumValueRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantStringEnumValueRule.description) } } -class RedundantTypeAnnotationRuleGeneratedTests: SwiftLintTestCase { +final class RedundantTypeAnnotationRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantTypeAnnotationRule.description) } } -class RedundantVoidReturnRuleGeneratedTests: SwiftLintTestCase { +final class RedundantVoidReturnRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantVoidReturnRule.description) } } -class RequiredDeinitRuleGeneratedTests: SwiftLintTestCase { +final class RequiredDeinitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RequiredDeinitRule.description) } } -class RequiredEnumCaseRuleGeneratedTests: SwiftLintTestCase { +final class RequiredEnumCaseRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RequiredEnumCaseRule.description) } } -class ReturnArrowWhitespaceRuleGeneratedTests: SwiftLintTestCase { +final class ReturnArrowWhitespaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ReturnArrowWhitespaceRule.description) } } -class ReturnValueFromVoidFunctionRuleGeneratedTests: SwiftLintTestCase { +final class ReturnValueFromVoidFunctionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ReturnValueFromVoidFunctionRule.description) } } -class SelfBindingRuleGeneratedTests: SwiftLintTestCase { +final class SelfBindingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SelfBindingRule.description) } } -class SelfInPropertyInitializationRuleGeneratedTests: SwiftLintTestCase { +final class SelfInPropertyInitializationRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SelfInPropertyInitializationRule.description) } } -class ShorthandArgumentRuleGeneratedTests: SwiftLintTestCase { +final class ShorthandArgumentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ShorthandArgumentRule.description) } } -class ShorthandOperatorRuleGeneratedTests: SwiftLintTestCase { +final class ShorthandOperatorRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ShorthandOperatorRule.description) } } -class ShorthandOptionalBindingRuleGeneratedTests: SwiftLintTestCase { +final class ShorthandOptionalBindingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ShorthandOptionalBindingRule.description) } } -class SingleTestClassRuleGeneratedTests: SwiftLintTestCase { +final class SingleTestClassRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SingleTestClassRule.description) } } -class SortedEnumCasesRuleGeneratedTests: SwiftLintTestCase { +final class SortedEnumCasesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SortedEnumCasesRule.description) } } -class SortedFirstLastRuleGeneratedTests: SwiftLintTestCase { +final class SortedFirstLastRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SortedFirstLastRule.description) } } -class SortedImportsRuleGeneratedTests: SwiftLintTestCase { +final class SortedImportsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SortedImportsRule.description) } } -class StatementPositionRuleGeneratedTests: SwiftLintTestCase { +final class StatementPositionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(StatementPositionRule.description) } } -class StaticOperatorRuleGeneratedTests: SwiftLintTestCase { +final class StaticOperatorRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(StaticOperatorRule.description) } } -class StaticOverFinalClassRuleGeneratedTests: SwiftLintTestCase { +final class StaticOverFinalClassRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(StaticOverFinalClassRule.description) } } -class StrictFilePrivateRuleGeneratedTests: SwiftLintTestCase { +final class StrictFilePrivateRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(StrictFilePrivateRule.description) } } -class StrongIBOutletRuleGeneratedTests: SwiftLintTestCase { +final class StrongIBOutletRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(StrongIBOutletRule.description) } } -class SuperfluousElseRuleGeneratedTests: SwiftLintTestCase { +final class SuperfluousElseRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SuperfluousElseRule.description) } } -class SwitchCaseAlignmentRuleGeneratedTests: SwiftLintTestCase { +final class SwitchCaseAlignmentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SwitchCaseAlignmentRule.description) } } -class SwitchCaseOnNewlineRuleGeneratedTests: SwiftLintTestCase { +final class SwitchCaseOnNewlineRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SwitchCaseOnNewlineRule.description) } } -class SyntacticSugarRuleGeneratedTests: SwiftLintTestCase { +final class SyntacticSugarRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(SyntacticSugarRule.description) } } -class TestCaseAccessibilityRuleGeneratedTests: SwiftLintTestCase { +final class TestCaseAccessibilityRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TestCaseAccessibilityRule.description) } } -class TodoRuleGeneratedTests: SwiftLintTestCase { +final class TodoRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TodoRule.description) } } -class ToggleBoolRuleGeneratedTests: SwiftLintTestCase { +final class ToggleBoolRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ToggleBoolRule.description) } } -class TrailingClosureRuleGeneratedTests: SwiftLintTestCase { +final class TrailingClosureRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TrailingClosureRule.description) } } -class TrailingCommaRuleGeneratedTests: SwiftLintTestCase { +final class TrailingCommaRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TrailingCommaRule.description) } } -class TrailingNewlineRuleGeneratedTests: SwiftLintTestCase { +final class TrailingNewlineRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TrailingNewlineRule.description) } } -class TrailingSemicolonRuleGeneratedTests: SwiftLintTestCase { +final class TrailingSemicolonRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TrailingSemicolonRule.description) } } -class TrailingWhitespaceRuleGeneratedTests: SwiftLintTestCase { +final class TrailingWhitespaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TrailingWhitespaceRule.description) } } -class TypeBodyLengthRuleGeneratedTests: SwiftLintTestCase { +final class TypeBodyLengthRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TypeBodyLengthRule.description) } } -class TypeContentsOrderRuleGeneratedTests: SwiftLintTestCase { +final class TypeContentsOrderRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TypeContentsOrderRule.description) } } -class TypeNameRuleGeneratedTests: SwiftLintTestCase { +final class TypeNameRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TypeNameRule.description) } } -class TypesafeArrayInitRuleGeneratedTests: SwiftLintTestCase { +final class TypesafeArrayInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(TypesafeArrayInitRule.description) } } -class UnavailableConditionRuleGeneratedTests: SwiftLintTestCase { +final class UnavailableConditionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnavailableConditionRule.description) } } -class UnavailableFunctionRuleGeneratedTests: SwiftLintTestCase { +final class UnavailableFunctionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnavailableFunctionRule.description) } } -class UnhandledThrowingTaskRuleGeneratedTests: SwiftLintTestCase { +final class UnhandledThrowingTaskRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnhandledThrowingTaskRule.description) } } -class UnneededBreakInSwitchRuleGeneratedTests: SwiftLintTestCase { +final class UnneededBreakInSwitchRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnneededBreakInSwitchRule.description) } } -class UnneededOverrideRuleGeneratedTests: SwiftLintTestCase { +final class UnneededOverrideRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnneededOverrideRule.description) } } -class UnneededParenthesesInClosureArgumentRuleGeneratedTests: SwiftLintTestCase { +final class UnneededParenthesesInClosureArgumentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnneededParenthesesInClosureArgumentRule.description) } } -class UnneededSynthesizedInitializerRuleGeneratedTests: SwiftLintTestCase { +final class UnneededSynthesizedInitializerRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnneededSynthesizedInitializerRule.description) } } -class UnownedVariableCaptureRuleGeneratedTests: SwiftLintTestCase { +final class UnownedVariableCaptureRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnownedVariableCaptureRule.description) } } -class UntypedErrorInCatchRuleGeneratedTests: SwiftLintTestCase { +final class UntypedErrorInCatchRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UntypedErrorInCatchRule.description) } } -class UnusedCaptureListRuleGeneratedTests: SwiftLintTestCase { +final class UnusedCaptureListRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedCaptureListRule.description) } } -class UnusedClosureParameterRuleGeneratedTests: SwiftLintTestCase { +final class UnusedClosureParameterRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedClosureParameterRule.description) } } -class UnusedControlFlowLabelRuleGeneratedTests: SwiftLintTestCase { +final class UnusedControlFlowLabelRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedControlFlowLabelRule.description) } } -class UnusedDeclarationRuleGeneratedTests: SwiftLintTestCase { +final class UnusedDeclarationRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedDeclarationRule.description) } } -class UnusedEnumeratedRuleGeneratedTests: SwiftLintTestCase { +final class UnusedEnumeratedRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedEnumeratedRule.description) } } -class UnusedImportRuleGeneratedTests: SwiftLintTestCase { +final class UnusedImportRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedImportRule.description) } } -class UnusedOptionalBindingRuleGeneratedTests: SwiftLintTestCase { +final class UnusedOptionalBindingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedOptionalBindingRule.description) } } -class UnusedSetterValueRuleGeneratedTests: SwiftLintTestCase { +final class UnusedSetterValueRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedSetterValueRule.description) } } -class ValidIBInspectableRuleGeneratedTests: SwiftLintTestCase { +final class ValidIBInspectableRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ValidIBInspectableRule.description) } } -class VerticalParameterAlignmentOnCallRuleGeneratedTests: SwiftLintTestCase { +final class VerticalParameterAlignmentOnCallRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VerticalParameterAlignmentOnCallRule.description) } } -class VerticalParameterAlignmentRuleGeneratedTests: SwiftLintTestCase { +final class VerticalParameterAlignmentRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VerticalParameterAlignmentRule.description) } } -class VerticalWhitespaceBetweenCasesRuleGeneratedTests: SwiftLintTestCase { +final class VerticalWhitespaceBetweenCasesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VerticalWhitespaceBetweenCasesRule.description) } } -class VerticalWhitespaceClosingBracesRuleGeneratedTests: SwiftLintTestCase { +final class VerticalWhitespaceClosingBracesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VerticalWhitespaceClosingBracesRule.description) } } -class VerticalWhitespaceOpeningBracesRuleGeneratedTests: SwiftLintTestCase { +final class VerticalWhitespaceOpeningBracesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VerticalWhitespaceOpeningBracesRule.description) } } -class VerticalWhitespaceRuleGeneratedTests: SwiftLintTestCase { +final class VerticalWhitespaceRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VerticalWhitespaceRule.description) } } -class VoidFunctionInTernaryConditionRuleGeneratedTests: SwiftLintTestCase { +final class VoidFunctionInTernaryConditionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VoidFunctionInTernaryConditionRule.description) } } -class VoidReturnRuleGeneratedTests: SwiftLintTestCase { +final class VoidReturnRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(VoidReturnRule.description) } } -class WeakDelegateRuleGeneratedTests: SwiftLintTestCase { +final class WeakDelegateRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(WeakDelegateRule.description) } } -class XCTFailMessageRuleGeneratedTests: SwiftLintTestCase { +final class XCTFailMessageRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(XCTFailMessageRule.description) } } -class XCTSpecificMatcherRuleGeneratedTests: SwiftLintTestCase { +final class XCTSpecificMatcherRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(XCTSpecificMatcherRule.description) } } -class YodaConditionRuleGeneratedTests: SwiftLintTestCase { +final class YodaConditionRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(YodaConditionRule.description) } diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index 2f99ce541b..7a116f265f 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -13,7 +13,7 @@ private let config: Configuration = { return Configuration(configurationFiles: [Configuration.defaultFileName]) }() -class IntegrationTests: SwiftLintTestCase { +final class IntegrationTests: SwiftLintTestCase { func testSwiftLintLints() { // This is as close as we're ever going to get to a self-hosting linter. let swiftFiles = config.lintableFiles( diff --git a/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift b/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift index 7df7931bee..e9d9589b40 100644 --- a/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift +++ b/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift @@ -1,7 +1,7 @@ import SwiftLintCore import XCTest -class AccessControlLevelTests: SwiftLintTestCase { +final class AccessControlLevelTests: SwiftLintTestCase { func testDescription() { XCTAssertEqual(AccessControlLevel.private.description, "private") XCTAssertEqual(AccessControlLevel.fileprivate.description, "fileprivate") diff --git a/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift b/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift index 29d4306c6f..eabf603fc9 100644 --- a/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class AttributesRuleTests: SwiftLintTestCase { +final class AttributesRuleTests: SwiftLintTestCase { func testAttributesWithAlwaysOnSameLine() { // Test with custom `always_on_same_line` let nonTriggeringExamples = [ diff --git a/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift b/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift index 728855e913..cb0210a1fe 100644 --- a/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class BlanketDisableCommandRuleTests: SwiftLintTestCase { +final class BlanketDisableCommandRuleTests: SwiftLintTestCase { private lazy var emptyDescription = BlanketDisableCommandRule.description .with(triggeringExamples: []) .with(nonTriggeringExamples: []) diff --git a/Tests/SwiftLintFrameworkTests/ChildOptionSeverityConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ChildOptionSeverityConfigurationTests.swift index 042ccc7fab..10d4cd4d0c 100644 --- a/Tests/SwiftLintFrameworkTests/ChildOptionSeverityConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ChildOptionSeverityConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class ChildOptionSeverityConfigurationTests: SwiftLintTestCase { +final class ChildOptionSeverityConfigurationTests: SwiftLintTestCase { typealias TesteeType = ChildOptionSeverityConfiguration func testSeverity() { diff --git a/Tests/SwiftLintFrameworkTests/CodeIndentingRewriterTests.swift b/Tests/SwiftLintFrameworkTests/CodeIndentingRewriterTests.swift index fb3bea1fb8..071b6aff8d 100644 --- a/Tests/SwiftLintFrameworkTests/CodeIndentingRewriterTests.swift +++ b/Tests/SwiftLintFrameworkTests/CodeIndentingRewriterTests.swift @@ -3,7 +3,7 @@ import SwiftParser import SwiftSyntax import XCTest -class CodeIndentingRewriterTests: XCTestCase { +final class CodeIndentingRewriterTests: XCTestCase { func testIndentDefaultStyle() { assertIndent( source: """ diff --git a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift index 862064b4f3..8ca48411f2 100644 --- a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift @@ -2,7 +2,7 @@ import SwiftLintTestHelpers import XCTest -class CollectingRuleTests: SwiftLintTestCase { +final class CollectingRuleTests: SwiftLintTestCase { func testCollectsIntoStorage() { struct Spec: MockCollectingRule { var configuration = SeverityConfiguration(.warning) diff --git a/Tests/SwiftLintFrameworkTests/CollectionAlignmentRuleTests.swift b/Tests/SwiftLintFrameworkTests/CollectionAlignmentRuleTests.swift index 010c24d1f7..364589bc88 100644 --- a/Tests/SwiftLintFrameworkTests/CollectionAlignmentRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CollectionAlignmentRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class CollectionAlignmentRuleTests: SwiftLintTestCase { +final class CollectionAlignmentRuleTests: SwiftLintTestCase { func testCollectionAlignmentWithAlignLeft() { let baseDescription = CollectionAlignmentRule.description let examples = CollectionAlignmentRule.Examples(alignColons: false) diff --git a/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift b/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift index 12079bf451..03d40cd653 100644 --- a/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class ColonRuleTests: SwiftLintTestCase { +final class ColonRuleTests: SwiftLintTestCase { func testColonWithFlexibleRightSpace() { // Verify Colon rule with test values for when flexible_right_spacing // is true. diff --git a/Tests/SwiftLintFrameworkTests/CommandTests.swift b/Tests/SwiftLintFrameworkTests/CommandTests.swift index f53bf9dbe8..e03f2a092e 100644 --- a/Tests/SwiftLintFrameworkTests/CommandTests.swift +++ b/Tests/SwiftLintFrameworkTests/CommandTests.swift @@ -15,7 +15,7 @@ private extension Command { } // swiftlint:disable:next type_body_length -class CommandTests: SwiftLintTestCase { +final class CommandTests: SwiftLintTestCase { // MARK: Command Creation func testNoCommandsInEmptyFile() { diff --git a/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift index eaf29f6a67..bf39d734f5 100644 --- a/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class CompilerProtocolInitRuleTests: SwiftLintTestCase { +final class CompilerProtocolInitRuleTests: SwiftLintTestCase { private let ruleID = CompilerProtocolInitRule.description.identifier func testViolationMessageForExpressibleByIntegerLiteral() throws { diff --git a/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift b/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift index f5502dfaf3..ad19c290df 100644 --- a/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class ComputedAccessorsOrderRuleTests: SwiftLintTestCase { +final class ComputedAccessorsOrderRuleTests: SwiftLintTestCase { func testSetGetConfiguration() { let nonTriggeringExamples = [ Example(""" diff --git a/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift b/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift index c16ae2fe36..446549c9c5 100644 --- a/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class ConditionalReturnsOnNewlineRuleTests: SwiftLintTestCase { +final class ConditionalReturnsOnNewlineRuleTests: SwiftLintTestCase { func testConditionalReturnsOnNewlineWithIfOnly() { // Test with `if_only` set to true let nonTriggeringExamples = [ diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 4718fc728f..2225cbbd58 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -7,9 +7,9 @@ import XCTest private let optInRules = RuleRegistry.shared.list.list.filter({ $0.1.init() is any OptInRule }).map({ $0.0 }) -class ConfigurationTests: SwiftLintTestCase { +final class ConfigurationTests: SwiftLintTestCase { // MARK: Setup & Teardown - private var previousWorkingDir: String! + private var previousWorkingDir: String! // swiftlint:disable:this implicitly_unwrapped_optional override func setUp() { super.setUp() diff --git a/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift b/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift index 920a20bc49..f8691673cd 100644 --- a/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class ContainsOverFirstNotNilRuleTests: SwiftLintTestCase { +final class ContainsOverFirstNotNilRuleTests: SwiftLintTestCase { func testFirstReason() { let example = Example("↓myList.first { $0 % 2 == 0 } != nil") let violations = self.violations(example) diff --git a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift index 169310247b..ea2d4bd885 100644 --- a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift @@ -2,7 +2,7 @@ import SourceKittenFramework @testable import SwiftLintCore import XCTest -class CustomRulesTests: SwiftLintTestCase { +final class CustomRulesTests: SwiftLintTestCase { typealias Configuration = RegexConfiguration func testCustomRuleConfigurationSetsCorrectlyWithMatchKinds() { let configDict = [ diff --git a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift index ec12e35713..d4ff7b94de 100644 --- a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class CyclomaticComplexityConfigurationTests: SwiftLintTestCase { +final class CyclomaticComplexityConfigurationTests: SwiftLintTestCase { func testCyclomaticComplexityConfigurationInitializerSetsLevels() { let warning = 10 let error = 30 diff --git a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift index be4233ccab..8dab89a1b4 100644 --- a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class CyclomaticComplexityRuleTests: SwiftLintTestCase { +final class CyclomaticComplexityRuleTests: SwiftLintTestCase { private lazy var complexSwitchExample: Example = { var example = "func switcheroo() {\n" example += " switch foo {\n" diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift index d3619248b0..df8f2d43fb 100644 --- a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class DeploymentTargetConfigurationTests: SwiftLintTestCase { +final class DeploymentTargetConfigurationTests: SwiftLintTestCase { private typealias Version = DeploymentTargetConfiguration.Version // swiftlint:disable:next function_body_length diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift index 220f1839e7..46c8b21066 100644 --- a/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class DeploymentTargetRuleTests: SwiftLintTestCase { +final class DeploymentTargetRuleTests: SwiftLintTestCase { func testMacOSAttributeReason() { let example = Example("@available(macOS 10.11, *)\nclass A {}") let violations = self.violations(example, config: ["macOS_deployment_target": "10.14.0"]) diff --git a/Tests/SwiftLintFrameworkTests/DisableAllTests.swift b/Tests/SwiftLintFrameworkTests/DisableAllTests.swift index e860186680..507d448028 100644 --- a/Tests/SwiftLintFrameworkTests/DisableAllTests.swift +++ b/Tests/SwiftLintFrameworkTests/DisableAllTests.swift @@ -1,7 +1,7 @@ import SwiftLintFramework import XCTest -class DisableAllTests: SwiftLintTestCase { +final class DisableAllTests: SwiftLintTestCase { /// Example violations. Could be replaced with other single violations. private let violatingPhrases = [ Example("let r = 0"), // Violates identifier_name diff --git a/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift index 4ad5f98016..6a0b84db23 100644 --- a/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class DiscouragedDirectInitRuleTests: SwiftLintTestCase { +final class DiscouragedDirectInitRuleTests: SwiftLintTestCase { private let baseDescription = DiscouragedDirectInitRule.description func testDiscouragedDirectInitWithConfiguredSeverity() { diff --git a/Tests/SwiftLintFrameworkTests/DiscouragedObjectLiteralRuleTests.swift b/Tests/SwiftLintFrameworkTests/DiscouragedObjectLiteralRuleTests.swift index a1679dc833..1a2f17e04e 100644 --- a/Tests/SwiftLintFrameworkTests/DiscouragedObjectLiteralRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/DiscouragedObjectLiteralRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class DiscouragedObjectLiteralRuleTests: SwiftLintTestCase { +final class DiscouragedObjectLiteralRuleTests: SwiftLintTestCase { func testWithImageLiteral() { let baseDescription = DiscouragedObjectLiteralRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ diff --git a/Tests/SwiftLintFrameworkTests/DuplicateImportsRuleTests.swift b/Tests/SwiftLintFrameworkTests/DuplicateImportsRuleTests.swift index d1e9d37d07..5a125b426b 100644 --- a/Tests/SwiftLintFrameworkTests/DuplicateImportsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/DuplicateImportsRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class DuplicateImportsRuleTests: XCTestCase { +final class DuplicateImportsRuleTests: XCTestCase { func testDisableCommand() { let content = """ import InspireAPI diff --git a/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift b/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift index 2b6e0bc83c..da26fe344c 100644 --- a/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class EmptyCountRuleTests: SwiftLintTestCase { +final class EmptyCountRuleTests: SwiftLintTestCase { func testEmptyCountWithOnlyAfterDot() { // Test with `only_after_dot` set to true let nonTriggeringExamples = [ diff --git a/Tests/SwiftLintFrameworkTests/ExampleTests.swift b/Tests/SwiftLintFrameworkTests/ExampleTests.swift index f1ab22a655..fda1b3f6e5 100644 --- a/Tests/SwiftLintFrameworkTests/ExampleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExampleTests.swift @@ -1,7 +1,7 @@ import SwiftLintFramework import XCTest -class ExampleTests: SwiftLintTestCase { +final class ExampleTests: SwiftLintTestCase { func testEquatableDoesNotLookAtFile() { let first = Example("foo", file: "a", line: 1) let second = Example("foo", file: "b", line: 1) diff --git a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift index cbc059c260..c5b1721ac6 100644 --- a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class ExpiringTodoRuleTests: SwiftLintTestCase { +final class ExpiringTodoRuleTests: SwiftLintTestCase { private lazy var config: Configuration = makeConfiguration() func testExpiringTodo() { diff --git a/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift index b46b1b12e7..2c8dadf812 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class ExplicitInitRuleTests: SwiftLintTestCase { +final class ExplicitInitRuleTests: SwiftLintTestCase { func testIncludeBareInit() { let nonTriggeringExamples = [ Example("let foo = Foo()"), diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift index 5affea03a3..474bed9035 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift @@ -2,7 +2,7 @@ @testable import SwiftLintCore import XCTest -class ExplicitTypeInterfaceConfigurationTests: SwiftLintTestCase { +final class ExplicitTypeInterfaceConfigurationTests: SwiftLintTestCase { func testDefaultConfiguration() { let config = ExplicitTypeInterfaceConfiguration() XCTAssertEqual(config.severityConfiguration.severity, .warning) diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift index 7e678e4eb8..739a942265 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { +final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { func testLocalVars() { let nonTriggeringExamples = [ Example("func foo() {\nlet intVal: Int = 1\n}"), diff --git a/Tests/SwiftLintFrameworkTests/ExtendedNSStringTests.swift b/Tests/SwiftLintFrameworkTests/ExtendedNSStringTests.swift index 06c0632084..66ec4b8330 100644 --- a/Tests/SwiftLintFrameworkTests/ExtendedNSStringTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExtendedNSStringTests.swift @@ -1,7 +1,7 @@ import SourceKittenFramework import XCTest -class ExtendedNSStringTests: SwiftLintTestCase { +final class ExtendedNSStringTests: SwiftLintTestCase { func testLineAndCharacterForByteOffset_forContentsContainingMultibyteCharacters() { let contents = "" + "import Foundation\n" + // 18 characters diff --git a/Tests/SwiftLintFrameworkTests/ExtendedStringTests.swift b/Tests/SwiftLintFrameworkTests/ExtendedStringTests.swift index bd1f36b73e..d504d3f4d0 100644 --- a/Tests/SwiftLintFrameworkTests/ExtendedStringTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExtendedStringTests.swift @@ -1,6 +1,6 @@ import XCTest -class ExtendedStringTests: SwiftLintTestCase { +final class ExtendedStringTests: SwiftLintTestCase { func testCountOccurrences() { XCTAssertEqual("aabbabaaba".countOccurrences(of: "a"), 6) XCTAssertEqual("".countOccurrences(of: "a"), 0) diff --git a/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift index 2779b09c9c..35c70859a8 100644 --- a/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift @@ -3,7 +3,7 @@ import XCTest private let fixturesDirectory = "\(TestResources.path)/FileHeaderRuleFixtures" -class FileHeaderRuleTests: SwiftLintTestCase { +final class FileHeaderRuleTests: SwiftLintTestCase { private func validate(fileName: String, using configuration: Any) throws -> [StyleViolation] { let file = SwiftLintFile(path: fixturesDirectory.stringByAppendingPathComponent(fileName))! let rule = try FileHeaderRule(configuration: configuration) diff --git a/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift index f55ebbdcea..3fe2caca40 100644 --- a/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class FileLengthRuleTests: SwiftLintTestCase { +final class FileLengthRuleTests: SwiftLintTestCase { func testFileLengthWithDefaultConfiguration() { verifyRule(FileLengthRule.description, commentDoesntViolate: false, testMultiByteOffsets: false, testShebang: false) diff --git a/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift index ff83c128bd..d3cc871431 100644 --- a/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift @@ -6,7 +6,7 @@ private let fixturesDirectory = #file.bridge() .deletingLastPathComponent.bridge() .appendingPathComponent("Resources/FileNameNoSpaceRuleFixtures") -class FileNameNoSpaceRuleTests: SwiftLintTestCase { +final class FileNameNoSpaceRuleTests: SwiftLintTestCase { private func validate(fileName: String, excludedOverride: [String]? = nil) throws -> [StyleViolation] { let file = SwiftLintFile(path: fixturesDirectory.stringByAppendingPathComponent(fileName))! let rule: FileNameNoSpaceRule diff --git a/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift index 2ac1953856..2a4bc69b93 100644 --- a/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift @@ -3,7 +3,7 @@ import XCTest private let fixturesDirectory = "\(TestResources.path)/FileNameRuleFixtures" -class FileNameRuleTests: SwiftLintTestCase { +final class FileNameRuleTests: SwiftLintTestCase { private func validate(fileName: String, excludedOverride: [String]? = nil, prefixPattern: String? = nil, suffixPattern: String? = nil, nestedTypeSeparator: String? = nil) throws -> [StyleViolation] { diff --git a/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift index e5b7d29290..d5b000a307 100644 --- a/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class FileTypesOrderRuleTests: SwiftLintTestCase { +final class FileTypesOrderRuleTests: SwiftLintTestCase { // swiftlint:disable:next function_body_length func testFileTypesOrderReversedOrder() { // Test with reversed `order` entries diff --git a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift index e53ae1c410..bd5b729168 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift @@ -13,7 +13,7 @@ private func violatingFuncWithBody(_ body: String, file: StaticString = #file, l return funcWithBody(body, violates: true, file: file, line: line) } -class FunctionBodyLengthRuleTests: SwiftLintTestCase { +final class FunctionBodyLengthRuleTests: SwiftLintTestCase { func testFunctionBodyLengths() { let longFunctionBody = funcWithBody(repeatElement("x = 0\n", count: 49).joined()) XCTAssertEqual(self.violations(longFunctionBody), []) diff --git a/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift index 3a3af12910..979d8872c3 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift @@ -9,7 +9,7 @@ private func funcWithParameters(_ parameters: String, return Example("func \(marker)abc(\(parameters)) {}\n", file: file, line: line) } -class FunctionParameterCountRuleTests: SwiftLintTestCase { +final class FunctionParameterCountRuleTests: SwiftLintTestCase { func testFunctionParameterCount() { let baseDescription = FunctionParameterCountRule.description let nonTriggeringExamples = [ diff --git a/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift index 0d35be7e27..51c4a807af 100644 --- a/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class GenericTypeNameRuleTests: SwiftLintTestCase { +final class GenericTypeNameRuleTests: SwiftLintTestCase { func testGenericTypeNameWithExcluded() { let baseDescription = GenericTypeNameRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ diff --git a/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift index 6a8bc753ec..2c4a073fcf 100644 --- a/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class IdentifierNameRuleTests: SwiftLintTestCase { +final class IdentifierNameRuleTests: SwiftLintTestCase { func testIdentifierNameWithExcluded() { let baseDescription = IdentifierNameRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ diff --git a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift index cf72c7363d..b1fd2c08b1 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class ImplicitReturnConfigurationTests: SwiftLintTestCase { +final class ImplicitReturnConfigurationTests: SwiftLintTestCase { func testImplicitReturnConfigurationFromDictionary() throws { var configuration = ImplicitReturnConfiguration(includedKinds: Set()) let config: [String: Any] = [ diff --git a/Tests/SwiftLintFrameworkTests/ImplicitReturnRuleTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitReturnRuleTests.swift index 7e5870a3ab..6aa4036f22 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitReturnRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitReturnRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class ImplicitReturnRuleTests: SwiftLintTestCase { +final class ImplicitReturnRuleTests: SwiftLintTestCase { func testOnlyClosureKindIncluded() { var nonTriggeringExamples = ImplicitReturnRuleExamples.nonTriggeringExamples + ImplicitReturnRuleExamples.triggeringExamples diff --git a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift index 1ce962efcb..53769d4f24 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift @@ -2,7 +2,7 @@ import XCTest // swiftlint:disable:next type_name -class ImplicitlyUnwrappedOptionalConfigurationTests: SwiftLintTestCase { +final class ImplicitlyUnwrappedOptionalConfigurationTests: SwiftLintTestCase { func testImplicitlyUnwrappedOptionalConfigurationProperlyAppliesConfigurationFromDictionary() throws { var configuration = ImplicitlyUnwrappedOptionalConfiguration( severityConfiguration: SeverityConfiguration(.warning), diff --git a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift index b9245c2035..d1fd9f15ae 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class ImplicitlyUnwrappedOptionalRuleTests: SwiftLintTestCase { +final class ImplicitlyUnwrappedOptionalRuleTests: SwiftLintTestCase { func testImplicitlyUnwrappedOptionalRuleDefaultConfiguration() { let rule = ImplicitlyUnwrappedOptionalRule() XCTAssertEqual(rule.configuration.mode, .allExceptIBOutlets) diff --git a/Tests/SwiftLintFrameworkTests/InclusiveLanguageRuleTests.swift b/Tests/SwiftLintFrameworkTests/InclusiveLanguageRuleTests.swift index be3649c97a..a4eecf6901 100644 --- a/Tests/SwiftLintFrameworkTests/InclusiveLanguageRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/InclusiveLanguageRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class InclusiveLanguageRuleTests: SwiftLintTestCase { +final class InclusiveLanguageRuleTests: SwiftLintTestCase { func testNonTriggeringExamplesWithNonDefaultConfig() { InclusiveLanguageRuleExamples.nonTriggeringExamplesWithConfig.forEach { example in let description = InclusiveLanguageRule.description diff --git a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift index 85b5401496..26f836fa4f 100644 --- a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift @@ -3,7 +3,7 @@ import SwiftLintTestHelpers import XCTest -class IndentationWidthRuleTests: SwiftLintTestCase { +final class IndentationWidthRuleTests: SwiftLintTestCase { func testInvalidIndentation() throws { var testee = IndentationWidthConfiguration() let defaultValue = testee.indentationWidth diff --git a/Tests/SwiftLintFrameworkTests/LineEndingTests.swift b/Tests/SwiftLintFrameworkTests/LineEndingTests.swift index 149e626848..8a1caa3a0e 100644 --- a/Tests/SwiftLintFrameworkTests/LineEndingTests.swift +++ b/Tests/SwiftLintFrameworkTests/LineEndingTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class LineEndingTests: SwiftLintTestCase { +final class LineEndingTests: SwiftLintTestCase { func testCarriageReturnDoesNotCauseError() { XCTAssert( violations( diff --git a/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift index a3a164f428..b29037d14a 100644 --- a/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class LineLengthConfigurationTests: SwiftLintTestCase { +final class LineLengthConfigurationTests: SwiftLintTestCase { private let severityLevels = SeverityLevelsConfiguration(warning: 100, error: 150) func testLineLengthConfigurationInitializerSetsLength() { diff --git a/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift index f4a97ec9cd..e3d157293a 100644 --- a/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class LineLengthRuleTests: SwiftLintTestCase { +final class LineLengthRuleTests: SwiftLintTestCase { private let longFunctionDeclarations = [ Example("public func superDuperLongFunctionDeclaration(a: String, b: String, " + "c: String, d: String, e: String, f: String, g: String, h: String, i: String, " + diff --git a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift index 60cada91e7..ad57ad2db7 100644 --- a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift +++ b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift @@ -68,7 +68,7 @@ private class TestFileManager: LintableFileManager { } } -class LinterCacheTests: SwiftLintTestCase { +final class LinterCacheTests: SwiftLintTestCase { // MARK: Test Helpers private var cache = LinterCache(fileManager: TestFileManager()) diff --git a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift index f8480e5214..c7db1cc89f 100644 --- a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class MissingDocsRuleTests: SwiftLintTestCase { +final class MissingDocsRuleTests: SwiftLintTestCase { func testDescriptionEmpty() { let configuration = MissingDocsConfiguration() XCTAssertEqual( diff --git a/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift b/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift index 86bd3f45a6..68ba5658dc 100644 --- a/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift +++ b/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class ModifierOrderTests: SwiftLintTestCase { +final class ModifierOrderTests: SwiftLintTestCase { func testAttributeTypeMethod() { let descriptionOverride = ModifierOrderRule.description .with(nonTriggeringExamples: [ diff --git a/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift b/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift index 5704e7a72a..37653d9409 100644 --- a/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class MultilineArgumentsRuleTests: SwiftLintTestCase { +final class MultilineArgumentsRuleTests: SwiftLintTestCase { func testMultilineArgumentsWithWithNextLine() { let nonTriggeringExamples = [ Example("foo()"), diff --git a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift index 6fdf3f1b37..906ca47a43 100644 --- a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class NameConfigurationTests: SwiftLintTestCase { +final class NameConfigurationTests: SwiftLintTestCase { typealias TesteeType = NameConfiguration func testNameConfigurationSetsCorrectly() { diff --git a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift index 0fee8ca53a..2df7ba3901 100644 --- a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift @@ -5,7 +5,7 @@ private let detectingTypes = ["actor", "class", "struct", "enum"] // swiftlint:disable:next type_body_length -class NestingRuleTests: SwiftLintTestCase { +final class NestingRuleTests: SwiftLintTestCase { // swiftlint:disable:next function_body_length func testNestingWithAlwaysAllowOneTypeInFunctions() { var nonTriggeringExamples = NestingRule.description.nonTriggeringExamples diff --git a/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift b/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift index 522fc516ec..de6c3869d5 100644 --- a/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift @@ -2,7 +2,7 @@ import SwiftParser import XCTest -class NumberSeparatorRuleTests: SwiftLintTestCase { +final class NumberSeparatorRuleTests: SwiftLintTestCase { func testNumberSeparatorWithMinimumLength() { let nonTriggeringExamples = [ Example("let foo = 10_000"), diff --git a/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift b/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift index 64a42fddc6..04d1be52d7 100644 --- a/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class ObjectLiteralRuleTests: SwiftLintTestCase { +final class ObjectLiteralRuleTests: SwiftLintTestCase { // MARK: - Instance Properties private let imageLiteralTriggeringExamples = ["", ".init"].flatMap { (method: String) -> [Example] in ["UI", "NS"].flatMap { (prefix: String) -> [Example] in diff --git a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift index bdc0a0b943..360a15d216 100644 --- a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class OpeningBraceRuleTests: SwiftLintTestCase { +final class OpeningBraceRuleTests: SwiftLintTestCase { func testDefaultExamplesRunInMultilineMode() { let description = OpeningBraceRule.description .with(triggeringExamples: OpeningBraceRule.description.triggeringExamples.removing([ diff --git a/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift b/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift index e3cba45751..c8405b87a6 100644 --- a/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class PrivateOverFilePrivateRuleTests: SwiftLintTestCase { +final class PrivateOverFilePrivateRuleTests: SwiftLintTestCase { func testPrivateOverFilePrivateValidatingExtensions() { let baseDescription = PrivateOverFilePrivateRule.description let triggeringExamples = baseDescription.triggeringExamples + [ diff --git a/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift index 4f0487a43e..666b5ca79b 100644 --- a/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintCore import XCTest -class RegexConfigurationTests: SwiftLintTestCase { +final class RegexConfigurationTests: SwiftLintTestCase { func testShouldValidateIsTrueByDefault() { let config = RegexConfiguration(identifier: "example") XCTAssertTrue(config.shouldValidate(filePath: "App/file.swift")) diff --git a/Tests/SwiftLintFrameworkTests/RegionTests.swift b/Tests/SwiftLintFrameworkTests/RegionTests.swift index 714dc8ee59..7b4732543b 100644 --- a/Tests/SwiftLintFrameworkTests/RegionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RegionTests.swift @@ -1,7 +1,7 @@ import SwiftLintCore import XCTest -class RegionTests: SwiftLintTestCase { +final class RegionTests: SwiftLintTestCase { // MARK: Regions From Files func testNoRegionsInEmptyFile() { diff --git a/Tests/SwiftLintFrameworkTests/ReporterTests.swift b/Tests/SwiftLintFrameworkTests/ReporterTests.swift index c7c2e230f3..20b91c4a04 100644 --- a/Tests/SwiftLintFrameworkTests/ReporterTests.swift +++ b/Tests/SwiftLintFrameworkTests/ReporterTests.swift @@ -4,7 +4,7 @@ import SourceKittenFramework @testable import SwiftLintCore import XCTest -class ReporterTests: SwiftLintTestCase { +final class ReporterTests: SwiftLintTestCase { func testReporterFromString() { for reporter in reportersList { XCTAssertEqual(reporter.identifier, reporterFrom(identifier: reporter.identifier).identifier) diff --git a/Tests/SwiftLintFrameworkTests/RequiredEnumCaseConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RequiredEnumCaseConfigurationTests.swift index 6055b59a50..1ec83cbcde 100644 --- a/Tests/SwiftLintFrameworkTests/RequiredEnumCaseConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RequiredEnumCaseConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class RequiredEnumCaseConfigurationTests: SwiftLintTestCase { +final class RequiredEnumCaseConfigurationTests: SwiftLintTestCase { private typealias RuleConfiguration = RequiredEnumCaseConfiguration private typealias RequiredCase = RuleConfiguration.RequiredCase diff --git a/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/BoolExtensionTests.swift b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/BoolExtensionTests.swift index 1360ccaf23..285895ead2 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/BoolExtensionTests.swift +++ b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/BoolExtensionTests.swift @@ -1,7 +1,7 @@ @testable import SomeModule import XCTest -class BoolExtensionTests: SwiftLintTestCase { +final class BoolExtensionTests: SwiftLintTestCase { func testExample() { // some code } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index eee9cce120..6893a14d7b 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -5,7 +5,7 @@ import XCTest // swiftlint:disable file_length // swiftlint:disable:next type_body_length -class RuleConfigurationDescriptionTests: XCTestCase { +final class RuleConfigurationDescriptionTests: XCTestCase { @AutoApply private struct TestConfiguration: RuleConfiguration { typealias Parent = RuleMock // swiftlint:disable:this nesting diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift index 29996cc2f3..8937c2df9a 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift @@ -3,7 +3,7 @@ import SourceKittenFramework @testable import SwiftLintCore import XCTest -class RuleConfigurationTests: SwiftLintTestCase { +final class RuleConfigurationTests: SwiftLintTestCase { private let defaultNestingConfiguration = NestingConfiguration( typeLevel: SeverityLevelsConfiguration(warning: 0), functionLevel: SeverityLevelsConfiguration(warning: 0) diff --git a/Tests/SwiftLintFrameworkTests/RuleTests.swift b/Tests/SwiftLintFrameworkTests/RuleTests.swift index de92364c16..b1ed928830 100644 --- a/Tests/SwiftLintFrameworkTests/RuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleTests.swift @@ -19,7 +19,7 @@ struct RuleWithLevelsMock: Rule { func validate(file: SwiftLintFile) -> [StyleViolation] { return [] } } -class RuleTests: SwiftLintTestCase { +final class RuleTests: SwiftLintTestCase { fileprivate struct RuleMock1: Rule { var configuration = SeverityConfiguration(.warning) var configurationDescription: some Documentable { RuleConfigurationOption.noOptions } diff --git a/Tests/SwiftLintFrameworkTests/RulesTests.swift b/Tests/SwiftLintFrameworkTests/RulesTests.swift index a0504de814..ef4748f060 100644 --- a/Tests/SwiftLintFrameworkTests/RulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/RulesTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class RulesTests: SwiftLintTestCase { +final class RulesTests: SwiftLintTestCase { func testLeadingWhitespace() { verifyRule(LeadingWhitespaceRule.description, skipDisableCommandTests: true, testMultiByteOffsets: false, testShebang: false) diff --git a/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift b/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift index 4f7484c9fa..dab162bfaf 100644 --- a/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift +++ b/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintCore import XCTest -class SourceKitCrashTests: SwiftLintTestCase { +final class SourceKitCrashTests: SwiftLintTestCase { func testAssertHandlerIsNotCalledOnNormalFile() { let file = SwiftLintFile(contents: "A file didn't crash SourceKitService") file.sourcekitdFailed = false diff --git a/Tests/SwiftLintFrameworkTests/StatementPositionRuleTests.swift b/Tests/SwiftLintFrameworkTests/StatementPositionRuleTests.swift index a0e7d91c29..b776b05302 100644 --- a/Tests/SwiftLintFrameworkTests/StatementPositionRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/StatementPositionRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class StatementPositionRuleTests: SwiftLintTestCase { +final class StatementPositionRuleTests: SwiftLintTestCase { func testStatementPositionUncuddled() { let configuration = ["statement_mode": "uncuddled_else"] verifyRule(StatementPositionRule.uncuddledDescription, ruleConfiguration: configuration) diff --git a/Tests/SwiftLintFrameworkTests/SwiftLintFileTests.swift b/Tests/SwiftLintFrameworkTests/SwiftLintFileTests.swift index b7b035defb..989b126e68 100644 --- a/Tests/SwiftLintFrameworkTests/SwiftLintFileTests.swift +++ b/Tests/SwiftLintFrameworkTests/SwiftLintFileTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintCore import XCTest -class SwiftLintFileTests: SwiftLintTestCase { +final class SwiftLintFileTests: SwiftLintTestCase { private let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) override func setUp() async throws { diff --git a/Tests/SwiftLintFrameworkTests/SwitchCaseAlignmentRuleTests.swift b/Tests/SwiftLintFrameworkTests/SwitchCaseAlignmentRuleTests.swift index 80a6c09299..5ec28069b9 100644 --- a/Tests/SwiftLintFrameworkTests/SwitchCaseAlignmentRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/SwitchCaseAlignmentRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class SwitchCaseAlignmentRuleTests: SwiftLintTestCase { +final class SwitchCaseAlignmentRuleTests: SwiftLintTestCase { func testSwitchCaseAlignmentWithoutIndentedCases() { let baseDescription = SwitchCaseAlignmentRule.description let examples = SwitchCaseAlignmentRule.Examples(indentedCases: false) diff --git a/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift b/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift index 2b0b7f311f..8058742dae 100644 --- a/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class TodoRuleTests: SwiftLintTestCase { +final class TodoRuleTests: SwiftLintTestCase { func testTodo() { verifyRule(TodoRule.description, commentDoesntViolate: false) } diff --git a/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift index 5614353b7b..baedc7ad02 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class TrailingClosureConfigurationTests: SwiftLintTestCase { +final class TrailingClosureConfigurationTests: SwiftLintTestCase { func testDefaultConfiguration() { let config = TrailingClosureConfiguration() XCTAssertEqual(config.severityConfiguration.severity, .warning) diff --git a/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift b/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift index b238c3e5a3..08698e087a 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class TrailingClosureRuleTests: SwiftLintTestCase { +final class TrailingClosureRuleTests: SwiftLintTestCase { func testWithOnlySingleMutedParameterEnabled() { let originalDescription = TrailingClosureRule.description let description = originalDescription diff --git a/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift b/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift index 0ad06f4c72..00de1bec92 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class TrailingCommaRuleTests: SwiftLintTestCase { +final class TrailingCommaRuleTests: SwiftLintTestCase { func testTrailingCommaRuleWithDefaultConfiguration() { // Verify TrailingCommaRule with test values for when mandatory_comma is false (default). let triggeringExamples = TrailingCommaRule.description.triggeringExamples + diff --git a/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift index 171e878480..1f02f6e8f6 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class TrailingWhitespaceRuleTests: SwiftLintTestCase { +final class TrailingWhitespaceRuleTests: SwiftLintTestCase { func testWithIgnoresEmptyLinesEnabled() { // Perform additional tests with the ignores_empty_lines setting enabled. // The set of non-triggering examples is extended by a whitespace-indented empty line diff --git a/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift b/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift index 5722a6f0db..2c7a85a947 100644 --- a/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class TypeContentsOrderRuleTests: SwiftLintTestCase { +final class TypeContentsOrderRuleTests: SwiftLintTestCase { // swiftlint:disable:next function_body_length func testTypeContentsOrderReversedOrder() { // Test with reversed `order` entries diff --git a/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift index 96270b8e40..73e66cd34e 100644 --- a/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class TypeNameRuleTests: SwiftLintTestCase { +final class TypeNameRuleTests: SwiftLintTestCase { func testTypeNameWithExcluded() { let baseDescription = TypeNameRule.description let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ diff --git a/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift b/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift index 0d731cf32b..e17c3e873a 100644 --- a/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class UnneededOverrideRuleTests: SwiftLintTestCase { +final class UnneededOverrideRuleTests: SwiftLintTestCase { func testIncludeAffectInits() { let nonTriggeringExamples = [ Example(""" diff --git a/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift index f677fbe9bf..cca2d1ee8d 100644 --- a/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class UnusedDeclarationConfigurationTests: XCTestCase { +final class UnusedDeclarationConfigurationTests: XCTestCase { func testParseConfiguration() throws { var testee = UnusedDeclarationConfiguration() let config = [ diff --git a/Tests/SwiftLintFrameworkTests/UnusedOptionalBindingRuleTests.swift b/Tests/SwiftLintFrameworkTests/UnusedOptionalBindingRuleTests.swift index 7f3fe8dc65..e210a3c337 100644 --- a/Tests/SwiftLintFrameworkTests/UnusedOptionalBindingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/UnusedOptionalBindingRuleTests.swift @@ -1,6 +1,6 @@ @testable import SwiftLintBuiltInRules -class UnusedOptionalBindingRuleTests: SwiftLintTestCase { +final class UnusedOptionalBindingRuleTests: SwiftLintTestCase { func testDefaultConfiguration() { let baseDescription = UnusedOptionalBindingRule.description let triggeringExamples = baseDescription.triggeringExamples + [ diff --git a/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift index b8df57475d..1f458abae4 100644 --- a/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class VerticalWhitespaceRuleTests: SwiftLintTestCase { +final class VerticalWhitespaceRuleTests: SwiftLintTestCase { private let ruleID = VerticalWhitespaceRule.description.identifier func testAttributesWithMaxEmptyLines() { diff --git a/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift b/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift index 2bf2114589..d32351bbe2 100644 --- a/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules import XCTest -class XCTSpecificMatcherRuleTests: SwiftLintTestCase { +final class XCTSpecificMatcherRuleTests: SwiftLintTestCase { func testEqualTrue() { let example = Example("XCTAssertEqual(a, true)") let violations = self.violations(example) diff --git a/Tests/SwiftLintFrameworkTests/YamlParserTests.swift b/Tests/SwiftLintFrameworkTests/YamlParserTests.swift index 6e4dd56167..4ab1322673 100644 --- a/Tests/SwiftLintFrameworkTests/YamlParserTests.swift +++ b/Tests/SwiftLintFrameworkTests/YamlParserTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintCore import XCTest -class YamlParserTests: SwiftLintTestCase { +final class YamlParserTests: SwiftLintTestCase { func testParseEmptyString() { XCTAssertEqual((try YamlParser.parse("", env: [:])).count, 0, "Parsing empty YAML string should succeed") diff --git a/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift b/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift index 8e5d26f050..4afc8cbd63 100644 --- a/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift +++ b/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift @@ -2,7 +2,7 @@ import Foundation import XCTest import Yams -class YamlSwiftLintTests: SwiftLintTestCase { +final class YamlSwiftLintTests: SwiftLintTestCase { func testFlattenYaml() throws { do { guard let yamlDict = try Yams.load(yaml: try getTestYaml()) as? [String: Any] else { From 108b1fca7a9445c12a92a83fdd9945ae03309f5d Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 29 Apr 2024 06:52:39 +0100 Subject: [PATCH 034/265] Enable rules that currently have no violations (#5547) --- .swiftlint.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index beb81d93dd..66bba1d6ad 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -11,7 +11,6 @@ opt_in_rules: - all disabled_rules: - anonymous_argument_in_multiline_closure - - anyobject_protocol - closure_body_length - conditional_returns_on_newline - convenience_type @@ -25,7 +24,6 @@ disabled_rules: - function_default_parameter_at_end - implicit_return - indentation_width - - inert_defer - missing_docs - multiline_arguments - multiline_arguments_brackets @@ -34,7 +32,6 @@ disabled_rules: - multiline_parameters - multiline_parameters_brackets - no_extension_access_modifier - - no_fallthrough_only - no_grouping_extension - no_magic_numbers - one_declaration_per_file @@ -42,14 +39,12 @@ disabled_rules: - prefer_self_in_static_references - prefixed_toplevel_constant - required_deinit - - static_over_final_class - sorted_enum_cases - strict_fileprivate - switch_case_on_newline - todo - trailing_closure - type_contents_order - - unused_capture_list - vertical_whitespace_between_cases attributes: From 99a990d88f06ec8bdef292299121110ef1f3d264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 29 Apr 2024 13:14:46 +0200 Subject: [PATCH 035/265] Disable deprecated rules (#5549) --- .swiftlint.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.swiftlint.yml b/.swiftlint.yml index 66bba1d6ad..1a9c0662cd 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -11,6 +11,7 @@ opt_in_rules: - all disabled_rules: - anonymous_argument_in_multiline_closure + - anyobject_protocol - closure_body_length - conditional_returns_on_newline - convenience_type @@ -24,6 +25,7 @@ disabled_rules: - function_default_parameter_at_end - implicit_return - indentation_width + - inert_defer - missing_docs - multiline_arguments - multiline_arguments_brackets @@ -45,6 +47,7 @@ disabled_rules: - todo - trailing_closure - type_contents_order + - unused_capture_list - vertical_whitespace_between_cases attributes: From 96db41c37913588fda9ae7cb541c02d9ef79ab40 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 1 May 2024 15:55:33 +0100 Subject: [PATCH 036/265] Add an experimental baseline feature (#5475) --- CHANGELOG.md | 8 +- Source/SwiftLintCore/Models/Baseline.swift | 182 +++++++++++++++ Source/SwiftLintCore/Models/Issue.swift | 9 +- .../SwiftLintCore/Models/StyleViolation.swift | 6 +- Source/swiftlint/Commands/Analyze.swift | 2 + Source/swiftlint/Commands/Baseline.swift | 88 +++++++ Source/swiftlint/Commands/Lint.swift | 2 + Source/swiftlint/Commands/SwiftLint.swift | 1 + .../Helpers/LintOrAnalyzeArguments.swift | 4 + .../Helpers/LintOrAnalyzeCommand.swift | 37 ++- .../BaselineTests.swift | 221 ++++++++++++++++++ 11 files changed, 551 insertions(+), 9 deletions(-) create mode 100644 Source/SwiftLintCore/Models/Baseline.swift create mode 100644 Source/swiftlint/Commands/Baseline.swift create mode 100644 Tests/SwiftLintFrameworkTests/BaselineTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index d9949e3025..ed5a4a1b3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,13 @@ #### Experimental -* None. +* Add two new options to the `lint` and `analyze` commands: `--write-baseline` + to save a baseline to disk, and `--baseline` to read a saved baseline and + use it to filter out detected pre-existing violations. A new `baseline` + command uses the reporters to print the violations in a baseline. + [Martin Redington](https://github.com/mildm8nnered) + [#5475](https://github.com/realm/SwiftLint/pull/5475) + [#3421](https://github.com/realm/SwiftLint/pull/3421) #### Enhancements diff --git a/Source/SwiftLintCore/Models/Baseline.swift b/Source/SwiftLintCore/Models/Baseline.swift new file mode 100644 index 0000000000..8e99891575 --- /dev/null +++ b/Source/SwiftLintCore/Models/Baseline.swift @@ -0,0 +1,182 @@ +import Foundation + +private typealias BaselineViolations = [BaselineViolation] +private typealias ViolationsPerFile = [String: BaselineViolations] +private typealias ViolationsPerRule = [String: BaselineViolations] + +private struct BaselineViolation: Codable, Hashable { + let violation: StyleViolation + let text: String + var key: String { text + violation.reason + violation.severity.rawValue } + + init(violation: StyleViolation, text: String) { + let location = violation.location + self.violation = violation.with(location: Location( + // Within the baseline, we use relative paths, so that + // comparisons are independent of the absolute path + file: location.relativeFile, + line: location.line, + character: location.character) + ) + self.text = text + } +} + +/// A set of violations that can be used to filter newly detected violations. +public struct Baseline: Equatable { + private let baseline: ViolationsPerFile + private var sortedBaselineViolations: BaselineViolations { + baseline.sorted(by: { $0.key < $1.key }).flatMap(\.value) + } + + /// The stored violations. + public var violations: [StyleViolation] { + sortedBaselineViolations.violationsWithAbsolutePaths + } + + /// Creates a `Baseline` from a saved file. + /// + /// - parameter fromPath: The path to read from. + public init(fromPath path: String) throws { + let data = try Data(contentsOf: URL(fileURLWithPath: path)) + baseline = try JSONDecoder().decode(BaselineViolations.self, from: data).groupedByFile() + } + + /// Creates a `Baseline` from a list of violations. + /// + /// - parameter violations: The violations for the baseline. + public init(violations: [StyleViolation]) { + baseline = BaselineViolations(violations).groupedByFile() + } + + /// Writes a `Baseline` to disk in JSON format. + /// + /// - parameter toPath: The path to write to. + public func write(toPath path: String) throws { + let data = try JSONEncoder().encode(sortedBaselineViolations) + try data.write(to: URL(fileURLWithPath: path)) + } + + /// Filters out violations that are present in the `Baseline`. + /// + /// Assumes that all violations are from the same file. + /// + /// - parameter violations: The violations to filter. + /// - Returns: The new violations. + public func filter(_ violations: [StyleViolation]) -> [StyleViolation] { + guard let firstViolation = violations.first, + let baselineViolations = baseline[firstViolation.location.relativeFile ?? ""], + baselineViolations.isNotEmpty else { + return violations + } + + let relativePathViolations = BaselineViolations(violations) + if relativePathViolations == baselineViolations { + return [] + } + + let violationsByRuleIdentifier = relativePathViolations.groupedByRuleIdentifier( + filteredBy: baselineViolations + ) + let baselineViolationsByRuleIdentifier = baselineViolations.groupedByRuleIdentifier( + filteredBy: relativePathViolations + ) + + var filteredViolations: Set = [] + + for (ruleIdentifier, ruleViolations) in violationsByRuleIdentifier { + guard + let baselineViolations = baselineViolationsByRuleIdentifier[ruleIdentifier], + baselineViolations.isNotEmpty else { + filteredViolations.formUnion(ruleViolations) + continue + } + + let groupedRuleViolations = Dictionary(grouping: ruleViolations, by: \.key) + let groupedBaselineViolations = Dictionary(grouping: baselineViolations, by: \.key) + + for (key, ruleViolations) in groupedRuleViolations { + guard let baselineViolations = groupedBaselineViolations[key] else { + filteredViolations.formUnion(ruleViolations) + continue + } + if ruleViolations.count > baselineViolations.count { + filteredViolations.formUnion(ruleViolations) + } + } + } + + let violationsWithAbsolutePaths = Set(filteredViolations.violationsWithAbsolutePaths) + return violations.filter { violationsWithAbsolutePaths.contains($0) } + } + + /// Returns the violations that are present in another `Baseline`, but not in this one. + /// + /// The violations are filtered using the same algorithm as the `filter` method above. + /// + /// - parameter otherBaseline: The other `Baseline`. + public func compare(_ otherBaseline: Baseline) -> [StyleViolation] { + otherBaseline.baseline.flatMap { + filter($1.violationsWithAbsolutePaths) + } + } +} + +private struct LineCache { + private var lines: [String: [String]] = [:] + + mutating func text(at location: Location) -> String { + let line = (location.line ?? 0) - 1 + if line > 0, let file = location.file, let content = cached(file: file), line < content.count { + return content[line] + } + return "" + } + + private mutating func cached(file: String) -> [String]? { + if let fileLines = lines[file] { + return fileLines + } + if let fileLines = SwiftLintFile(path: file)?.lines.map(\.content) { + lines[file] = fileLines + return fileLines + } + return nil + } +} + +private extension Sequence where Element == BaselineViolation { + init(_ violations: [StyleViolation]) where Self == BaselineViolations { + var lineCache = LineCache() + self = violations.map { $0.baselineViolation(text: lineCache.text(at: $0.location)) } + } + + var violationsWithAbsolutePaths: [StyleViolation] { + map { $0.violation.withAbsolutePath } + } + + func groupedByFile() -> ViolationsPerFile { + Dictionary(grouping: self) { $0.violation.location.relativeFile ?? "" } + } + + func groupedByRuleIdentifier(filteredBy existingViolations: [BaselineViolation] = []) -> ViolationsPerRule { + Dictionary(grouping: Set(self).subtracting(existingViolations), by: \.violation.ruleIdentifier) + } +} + +private extension StyleViolation { + var withAbsolutePath: StyleViolation { + let absolutePath: String? = + if let relativePath = location.file { + FileManager.default.currentDirectoryPath + "/" + relativePath + } else { + nil + } + let newLocation = Location(file: absolutePath, line: location.line, character: location.character) + return with(location: newLocation) + } + + func baselineViolation(text: String = "") -> BaselineViolation { + BaselineViolation(violation: self, text: text) + } +} diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index b7ee200f28..1e9cc6ef59 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -71,6 +71,9 @@ public enum Issue: LocalizedError, Equatable { /// An error that occurred when parsing YAML. case yamlParsing(String) + /// The baseline file at `path` is not readable or cannot be opened. + case baselineNotReadable(path: String) + /// Flag to enable warnings for deprecations being printed to the console. Printing is enabled by default. public static var printDeprecationWarnings = true @@ -172,6 +175,8 @@ public enum Issue: LocalizedError, Equatable { """ case let .initialFileNotFound(path): return "Could not read file at path '\(path)'." + case let .fileNotFound(path): + return "File at path '\(path)' not found." case let .fileNotReadable(path, id): return "Cannot open or read file at path '\(path ?? "...")' within '\(id)' rule." case let .fileNotWritable(path): @@ -187,8 +192,8 @@ public enum Issue: LocalizedError, Equatable { return "Cannot get cursor info from file at path '\(path ?? "...")' within '\(id)' rule." case let .yamlParsing(message): return "Cannot parse YAML file: \(message)" - case let .fileNotFound(path): - return "File at path '\(path)' not found." + case let .baselineNotReadable(path): + return "Cannot open or read the baseline file at path '\(path)'." } } } diff --git a/Source/SwiftLintCore/Models/StyleViolation.swift b/Source/SwiftLintCore/Models/StyleViolation.swift index c243e08d14..627f7460e9 100644 --- a/Source/SwiftLintCore/Models/StyleViolation.swift +++ b/Source/SwiftLintCore/Models/StyleViolation.swift @@ -1,5 +1,5 @@ /// A value describing an instance of Swift source code that is considered invalid by a SwiftLint rule. -public struct StyleViolation: CustomStringConvertible, Equatable, Codable { +public struct StyleViolation: CustomStringConvertible, Codable, Hashable { /// The identifier of the rule that generated this violation. public let ruleIdentifier: String @@ -66,4 +66,8 @@ public struct StyleViolation: CustomStringConvertible, Equatable, Codable { new.location = location return new } + + public func hash(into hasher: inout Hasher) { + hasher.combine(description) + } } diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index 9e41eea340..ac74e32f3f 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -43,6 +43,8 @@ extension SwiftLint { useScriptInputFiles: common.useScriptInputFiles, benchmark: common.benchmark, reporter: common.reporter, + baseline: common.baseline, + writeBaseline: common.writeBaseline, quiet: quiet, output: common.output, progress: common.progress, diff --git a/Source/swiftlint/Commands/Baseline.swift b/Source/swiftlint/Commands/Baseline.swift new file mode 100644 index 0000000000..a58b889c87 --- /dev/null +++ b/Source/swiftlint/Commands/Baseline.swift @@ -0,0 +1,88 @@ +import ArgumentParser +import Foundation +import SwiftLintFramework + +extension SwiftLint { + struct Baseline: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Operations on existing baselines", + subcommands: [Report.self, Compare.self], + defaultSubcommand: Report.self + ) + } + + private struct BaselineOptions: ParsableArguments { + @Argument(help: "The path to the baseline file.") + var baseline: String + } + + private struct ReportingOptions: ParsableArguments { + @Option( + help: """ + The reporter used to report violations. The 'summary' reporter can be useful to \ + provide an overview. + """ + ) + var reporter: String? + @Option(help: "The file where violations should be saved. Prints to stdout by default.") + var output: String? + } + + private struct Report: ParsableCommand { + static let configuration = CommandConfiguration(abstract: "Reports the violations in a baseline.") + + @OptionGroup + var options: BaselineOptions + @OptionGroup + var reportingOptions: ReportingOptions + + func run() throws { + let savedBaseline = try SwiftLintCore.Baseline(fromPath: options.baseline) + try report(savedBaseline.violations, using: reportingOptions.reporter, to: reportingOptions.output) + ExitHelper.successfullyExit() + } + } + + private struct Compare: ParsableCommand { + static let configuration = CommandConfiguration( + abstract: "Reports the violations that are present in another baseline " + + "but not in the original baseline." + ) + + @OptionGroup + var options: BaselineOptions + @Option( + help: """ + The path to a second baseline to compare against the baseline. Violations in \ + the second baseline that are not present in the original baseline will be reported. + """ + ) + var otherBaseline: String + @OptionGroup + var reportingOptions: ReportingOptions + + func run() throws { + let baseline = try SwiftLintCore.Baseline(fromPath: options.baseline) + let otherBaseline = try SwiftLintCore.Baseline(fromPath: otherBaseline) + try report(baseline.compare(otherBaseline), using: reportingOptions.reporter, to: reportingOptions.output) + ExitHelper.successfullyExit() + } + } +} + +private func report(_ violations: [StyleViolation], using reporterIdentifier: String?, to output: String?) throws { + let reporter = reporterFrom(identifier: reporterIdentifier) + let report = reporter.generateReport(violations) + if report.isNotEmpty { + if let output { + let data = Data((report + "\n").utf8) + do { + try data.write(to: URL(fileURLWithPath: output)) + } catch { + Issue.fileNotWritable(path: output).print() + } + } else { + queuedPrint(report) + } + } +} diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index 7a26830b91..e3ec05f07a 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -59,6 +59,8 @@ extension SwiftLint { useScriptInputFiles: common.useScriptInputFiles, benchmark: common.benchmark, reporter: common.reporter, + baseline: common.baseline, + writeBaseline: common.writeBaseline, quiet: quiet, output: common.output, progress: common.progress, diff --git a/Source/swiftlint/Commands/SwiftLint.swift b/Source/swiftlint/Commands/SwiftLint.swift index dd86138e7e..8229530b18 100644 --- a/Source/swiftlint/Commands/SwiftLint.swift +++ b/Source/swiftlint/Commands/SwiftLint.swift @@ -24,6 +24,7 @@ struct SwiftLint: AsyncParsableCommand { Docs.self, GenerateDocs.self, Lint.self, + Baseline.self, Reporters.self, Rules.self, Version.self diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift index e8e039d983..e7ea89cf05 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -38,6 +38,10 @@ struct LintOrAnalyzeArguments: ParsableArguments { var benchmark = false @Option(help: "The reporter used to log errors and warnings.") var reporter: String? + @Option(help: "The path to a baseline file, which will be used to filter out detected violations.") + var baseline: String? + @Option(help: "The path to save detected violations to as a new baseline.") + var writeBaseline: String? @Flag(help: "Use the in-process version of SourceKit.") var inProcessSourcekit = false @Option(help: "The file where violations should be saved. Prints to stdout by default.") diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift index da717523c7..3c5e946b84 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -44,6 +44,9 @@ struct LintOrAnalyzeCommand { private static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws { let builder = LintOrAnalyzeResultBuilder(options) let files = try await collectViolations(builder: builder) + if let baselineOutputPath = options.writeBaseline { + try Baseline(violations: builder.unfilteredViolations).write(toPath: baselineOutputPath) + } try Signposts.record(name: "LintOrAnalyzeCommand.PostProcessViolations") { try postProcessViolations(files: files, builder: builder) } @@ -52,6 +55,7 @@ struct LintOrAnalyzeCommand { private static func collectViolations(builder: LintOrAnalyzeResultBuilder) async throws -> [SwiftLintFile] { let options = builder.options let visitorMutationQueue = DispatchQueue(label: "io.realm.swiftlint.lintVisitorMutation") + let baseline = try baseline(options) return try await builder.configuration.visitLintableFiles(options: options, cache: builder.cache, storage: builder.storage) { linter in let currentViolations: [StyleViolation] @@ -68,7 +72,6 @@ struct LintOrAnalyzeCommand { visitorMutationQueue.sync { builder.fileBenchmark.record(file: linter.file, from: start) currentRuleTimes.forEach { builder.ruleBenchmark.record(id: $0, time: $1) } - builder.violations += currentViolations } } else { currentViolations = applyLeniency( @@ -76,12 +79,15 @@ struct LintOrAnalyzeCommand { strict: builder.configuration.strict, violations: linter.styleViolations(using: builder.storage) ) - visitorMutationQueue.sync { - builder.violations += currentViolations - } } + let filteredViolations = baseline?.filter(currentViolations) ?? currentViolations + visitorMutationQueue.sync { + builder.unfilteredViolations += currentViolations + builder.violations += filteredViolations + } + linter.file.invalidateCache() - builder.report(violations: currentViolations, realtimeCondition: true) + builder.report(violations: filteredViolations, realtimeCondition: true) } } @@ -115,6 +121,22 @@ struct LintOrAnalyzeCommand { guard numberOfSeriousViolations == 0 else { exit(2) } } + private static func baseline(_ options: LintOrAnalyzeOptions) throws -> Baseline? { + if let baselinePath = options.baseline { + do { + return try Baseline(fromPath: baselinePath) + } catch { + Issue.baselineNotReadable(path: baselinePath).print() + if + (error as? CocoaError)?.code != CocoaError.fileReadNoSuchFile || + options.writeBaseline != options.baseline { + throw error + } + } + } + return nil + } + private static func printStatus(violations: [StyleViolation], files: [SwiftLintFile], serious: Int, verb: String) { let pluralSuffix = { (collection: [Any]) -> String in return collection.count != 1 ? "s" : "" @@ -237,6 +259,8 @@ struct LintOrAnalyzeOptions { let useScriptInputFiles: Bool let benchmark: Bool let reporter: String? + let baseline: String? + let writeBaseline: String? let quiet: Bool let output: String? let progress: Bool @@ -260,6 +284,9 @@ struct LintOrAnalyzeOptions { private class LintOrAnalyzeResultBuilder { var fileBenchmark = Benchmark(name: "files") var ruleBenchmark = Benchmark(name: "rules") + /// All detected violations, unfiltered by the baseline, if any. + var unfilteredViolations = [StyleViolation]() + /// The violations to be reported, possibly filtered by a baseline, plus any threshold violations. var violations = [StyleViolation]() let storage = RuleStorage() let configuration: Configuration diff --git a/Tests/SwiftLintFrameworkTests/BaselineTests.swift b/Tests/SwiftLintFrameworkTests/BaselineTests.swift new file mode 100644 index 0000000000..8d38050308 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/BaselineTests.swift @@ -0,0 +1,221 @@ +@testable import SwiftLintBuiltInRules +@testable import SwiftLintCore +import XCTest + +private var temporaryDirectoryPath: String { + let result = URL( + fileURLWithPath: NSTemporaryDirectory(), + isDirectory: true + ).path + +#if os(macOS) + return "/private" + result +#else + return result +#endif +} + +final class BaselineTests: XCTestCase { + private static let example = """ + import Foundation + import SwiftLintFramework + + class Example: NSObject { + private var foo: Int + private var bar: String + + init(foo: Int, bar: String) { + self.foo = foo + self.bar = bar + } // init + func someFunction() -> Int { + foo * 10 + } // someFunction + func someOtherFunction() -> String { + bar + } // someOtherFunction + func yetAnotherFunction() -> (Int, String) { + (foo, bar) + } // yetAnotherFunction + } + """ + + private static let ruleDescriptions = [ + ArrayInitRule.description, + BlockBasedKVORule.description, + ClosingBraceRule.description, + DirectReturnRule.description + ] + + private static var currentDirectoryPath: String? + + private static func violations(for filePath: String?) -> [StyleViolation] { + ruleDescriptions.violations(for: filePath) + } + + private static func baseline(for filePath: String) -> Baseline { + Baseline(violations: ruleDescriptions.violations(for: filePath)) + } + + override static func setUp() { + super.setUp() + currentDirectoryPath = FileManager.default.currentDirectoryPath + XCTAssertTrue(FileManager.default.changeCurrentDirectoryPath(temporaryDirectoryPath)) + } + + override static func tearDown() { + if let currentDirectoryPath { + XCTAssertTrue(FileManager.default.changeCurrentDirectoryPath(currentDirectoryPath)) + self.currentDirectoryPath = nil + } + super.tearDown() + } + + func testWritingAndReading() throws { + try withExampleFileCreated { sourceFilePath in + let baselinePath = temporaryDirectoryPath.stringByAppendingPathComponent(UUID().uuidString) + try Baseline(violations: Self.violations(for: sourceFilePath)).write(toPath: baselinePath) + defer { + try? FileManager.default.removeItem(atPath: baselinePath) + } + let newBaseline = try Baseline(fromPath: baselinePath) + XCTAssertEqual(newBaseline, Self.baseline(for: sourceFilePath)) + } + } + + func testUnchangedViolations() throws { + try withExampleFileCreated { sourceFilePath in + XCTAssertEqual(Self.baseline(for: sourceFilePath).filter(Self.violations(for: sourceFilePath)), []) + } + } + + func testShiftedViolations() throws { + try withExampleFileCreated { sourceFilePath in + let baseline = Self.baseline(for: sourceFilePath) + let violations = try Self.violations(for: sourceFilePath).lineShifted(by: 2, path: sourceFilePath) + XCTAssertEqual(baseline.filter(violations), []) + } + } + + func testNewViolation() throws { + try testViolationDetection( + violationRuleDescriptions: Self.ruleDescriptions, + newViolationRuleDescription: EmptyCollectionLiteralRule.description, + insertionIndex: 2 + ) + } + + func testViolationDetection() throws { + let violationRuleDescriptions = [ + ArrayInitRule.description, + BlockBasedKVORule.description, + ArrayInitRule.description, + ClosingBraceRule.description, + ClosingBraceRule.description, + ClosingBraceRule.description, + BlockBasedKVORule.description, + DirectReturnRule.description, + ArrayInitRule.description, + ClosingBraceRule.description + ] + + let ruleDescriptions = [ + ArrayInitRule.description, + BlockBasedKVORule.description, + ClosingBraceRule.description, + DirectReturnRule.description + ] + + for ruleDescription in ruleDescriptions { + for insertionIndex in 0.. Void) throws { + let sourceFilePath = temporaryDirectoryPath.stringByAppendingPathComponent("\(UUID().uuidString).swift") + guard let data = Self.example.data(using: .utf8) else { + XCTFail("Could not convert example code to data using UTF-8 encoding") + return + } + try data.write(to: URL(fileURLWithPath: sourceFilePath)) + defer { + try? FileManager.default.removeItem(atPath: sourceFilePath) + } + try block(sourceFilePath) + } +} + +private extension [StyleViolation] { + func lineShifted(by shift: Int, path: String) throws -> [StyleViolation] { + guard shift > 0 else { + XCTFail("Shift must be positive") + return self + } + var lines = SwiftLintFile(path: path)?.lines.map({ $0.content }) ?? [] + lines = [String](repeating: "", count: shift) + lines + if let data = lines.joined(separator: "\n").data(using: .utf8) { + try data.write(to: URL(fileURLWithPath: path)) + } + return map { + let shiftedLocation = Location( + file: path, + line: $0.location.line != nil ? $0.location.line! + shift : nil, + character: $0.location.character + ) + return $0.with(location: shiftedLocation) + } + } +} + +private extension Sequence where Element == RuleDescription { + func violations(for filePath: String?) -> [StyleViolation] { + enumerated().map { index, ruleDescription in + StyleViolation( + ruleDescription: ruleDescription, + location: Location(file: filePath, line: (index + 1) * 2, character: 1) + ) + } + } +} From 16cb4a02b1751ebe14a8dcc5dd9d30bbd49ab7b1 Mon Sep 17 00:00:00 2001 From: Chandler Wall <3250827+chandlerwall@users.noreply.github.com> Date: Wed, 1 May 2024 13:51:01 -0500 Subject: [PATCH 037/265] Fix numeric version comparisons (#5526) --- CHANGELOG.md | 5 ++ .../SwiftLintCore/Models/SwiftVersion.swift | 20 ++++++++ .../SwiftVersionTests.swift | 48 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed5a4a1b3c..05f8adcb16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -190,6 +190,11 @@ #### Bug Fixes +* Fix version comparison algorithm which caused some version-dependent rules to + misbehave with Swift 5.10. + [chandlerwall](https://github.com/chandlerwall) + [#5517](https://github.com/realm/SwiftLint/issues/5517) + * Silence `discarded_notification_center_observer` rule in closures. Furthermore, handle `get` and `set` accessors correctly and consider implicit returns. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintCore/Models/SwiftVersion.swift b/Source/SwiftLintCore/Models/SwiftVersion.swift index 62ccdee305..64d59af6bb 100644 --- a/Source/SwiftLintCore/Models/SwiftVersion.swift +++ b/Source/SwiftLintCore/Models/SwiftVersion.swift @@ -11,9 +11,29 @@ public struct SwiftVersion: RawRepresentable, Codable, Comparable, Sendable { self.rawValue = rawValue } + public static func == (lhs: SwiftVersion, rhs: SwiftVersion) -> Bool { + if let lhsComparators = lhs.comparators, let rhsComparators = rhs.comparators { + return lhsComparators == rhsComparators + } + return lhs.rawValue == rhs.rawValue + } + public static func < (lhs: SwiftVersion, rhs: SwiftVersion) -> Bool { + if let lhsComparators = lhs.comparators, let rhsComparators = rhs.comparators { + return lhsComparators.lexicographicallyPrecedes(rhsComparators) + } return lhs.rawValue < rhs.rawValue } + + private var comparators: [Int]? { + let components = rawValue.split(separator: ".").compactMap { Int($0) } + guard let major = components.first else { + return nil + } + let minor = components.dropFirst(1).first ?? 0 + let patch = components.dropFirst(2).first ?? 0 + return [major, minor, patch] + } } public extension SwiftVersion { diff --git a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift index 8a1b566a96..33f3a71c0d 100644 --- a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift +++ b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift @@ -48,4 +48,52 @@ final class SwiftVersionTests: SwiftLintTestCase { #endif XCTAssertEqual(SwiftVersion.current.rawValue, version) } + + func testCompareBalancedSwiftVersion() { + XCTAssertNotEqual(SwiftVersion(rawValue: "5"), SwiftVersion(rawValue: "6")) + XCTAssertTrue(SwiftVersion(rawValue: "5") < SwiftVersion(rawValue: "6")) + XCTAssertFalse(SwiftVersion(rawValue: "5") > SwiftVersion(rawValue: "6")) + XCTAssertFalse(SwiftVersion(rawValue: "6") < SwiftVersion(rawValue: "5")) + + XCTAssertNotEqual(SwiftVersion(rawValue: "5.1"), SwiftVersion(rawValue: "5.2")) + XCTAssertTrue(SwiftVersion(rawValue: "5.1") < SwiftVersion(rawValue: "5.2")) + XCTAssertFalse(SwiftVersion(rawValue: "5.1") > SwiftVersion(rawValue: "5.2")) + XCTAssertFalse(SwiftVersion(rawValue: "5.2") < SwiftVersion(rawValue: "5.1")) + + XCTAssertNotEqual(SwiftVersion(rawValue: "5.1.1"), SwiftVersion(rawValue: "5.1.2")) + XCTAssertTrue(SwiftVersion(rawValue: "5.1.1") < SwiftVersion(rawValue: "5.1.2")) + XCTAssertFalse(SwiftVersion(rawValue: "5.1.1") > SwiftVersion(rawValue: "5.1.2")) + XCTAssertFalse(SwiftVersion(rawValue: "5.1.2") < SwiftVersion(rawValue: "5.1.1")) + } + + func testCompareUnbalancedSwiftVersion() { + XCTAssertEqual(SwiftVersion(rawValue: "5"), SwiftVersion(rawValue: "5.0")) + XCTAssertFalse(SwiftVersion(rawValue: "5") < SwiftVersion(rawValue: "5.0")) + XCTAssertFalse(SwiftVersion(rawValue: "5") > SwiftVersion(rawValue: "5.0")) + + XCTAssertNotEqual(SwiftVersion(rawValue: "5.9"), SwiftVersion(rawValue: "6")) + XCTAssertTrue(SwiftVersion(rawValue: "5.9") < SwiftVersion(rawValue: "6")) + XCTAssertFalse(SwiftVersion(rawValue: "5.9") > SwiftVersion(rawValue: "6")) + XCTAssertFalse(SwiftVersion(rawValue: "6") < SwiftVersion(rawValue: "5.9")) + + XCTAssertNotEqual(SwiftVersion(rawValue: "5.2"), SwiftVersion(rawValue: "5.10.3")) + XCTAssertTrue(SwiftVersion(rawValue: "5.2") < SwiftVersion(rawValue: "5.10.3")) + XCTAssertFalse(SwiftVersion(rawValue: "5.2") > SwiftVersion(rawValue: "5.10.3")) + XCTAssertFalse(SwiftVersion(rawValue: "5.10.3") < SwiftVersion(rawValue: "5.2")) + } + + func testCompareProblematicSwiftVersion() { + XCTAssertEqual(SwiftVersion(rawValue: "5.010"), SwiftVersion(rawValue: "5.10")) + XCTAssertFalse(SwiftVersion(rawValue: "5.010") < SwiftVersion(rawValue: "5.10")) + XCTAssertFalse(SwiftVersion(rawValue: "5.010") > SwiftVersion(rawValue: "5.10")) + + XCTAssertNotEqual(SwiftVersion(rawValue: "-10"), SwiftVersion(rawValue: "-1")) + XCTAssertTrue(SwiftVersion(rawValue: "-10") < SwiftVersion(rawValue: "-1")) + + XCTAssertNotEqual(SwiftVersion(rawValue: "0"), SwiftVersion(rawValue: "10")) + XCTAssertTrue(SwiftVersion(rawValue: "0") < SwiftVersion(rawValue: "10")) + + XCTAssertNotEqual(SwiftVersion(rawValue: "alpha"), SwiftVersion(rawValue: "beta")) + XCTAssertTrue(SwiftVersion(rawValue: "alpha") < SwiftVersion(rawValue: "beta")) + } } From 16c0213027d4047bd4c265faffad7ce3d104c67d Mon Sep 17 00:00:00 2001 From: "Garric G. Nahapetian" Date: Wed, 1 May 2024 12:15:35 -0700 Subject: [PATCH 038/265] Add option to `redundant_type_annotation` rule to consider default literal types redundant (#4756) --- CHANGELOG.md | 14 +++ .../RedundantTypeAnnotationRule.swift | 114 ++++++++++++------ ...RedundantTypeAnnotationConfiguration.swift | 2 + .../default_rule_configurations.yml | 1 + 4 files changed, 92 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05f8adcb16..717fc5ff21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,12 @@ [Martin Redington](https://github.com/mildm8nnered) [#4792](https://github.com/realm/SwiftLint/issues/4792) +* With the introduction of the `consider_default_literal_types_redundant` + option to the `redundant_type_annotation` rule, `Bool` literals will no + longer be considered redundant by default. Set this option to true to + preserve the previous behavior. + [Garric Nahapetian](https://github.com/garricn) + #### Experimental * Add two new options to the `lint` and `analyze` commands: `--write-baseline` @@ -188,6 +194,14 @@ [Martin Redington](https://github.com/mildm8nnered) [#5470](https://github.com/realm/SwiftLint/issues/5470) +* Include `Double`, `Int` and `String` to the exiting redundant type validation + check of `Bool` in the `redundant_type_annotation` rule. Add + `consider_default_literal_types_redundant` option supporting `Bool`, + `Double`, `Int` and `String`. Setting this option to `true` lets the rule + consider said types in declarations like `let i: Int = 1` or + `let s: String = ""` as redundant. + [Garric Nahapetian](https://github.com/garricn) + #### Bug Fixes * Fix version comparison algorithm which caused some version-dependent rules to diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index a75b3be334..5810619632 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -52,7 +52,11 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { @IgnoreMe let i: Int = Int(1) return i } - """, configuration: ["ignore_attributes": ["IgnoreMe"]]) + """, configuration: ["ignore_attributes": ["IgnoreMe"]]), + Example("var bol: Bool = true"), + Example("var dbl: Double = 0.0"), + Example("var int: Int = 0"), + Example("var str: String = \"str\"") ], triggeringExamples: [ Example("var url↓:URL=URL()"), @@ -84,7 +88,6 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { } } """), - Example("var isEnabled↓: Bool = true"), Example("let a↓: [Int] = [Int]()"), Example("let a↓: A.B = A.B()"), Example(""" @@ -102,7 +105,11 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { let i↓: Int = Int(1) return i } - """, configuration: ["ignore_attributes": ["IgnoreMe"]]) + """, configuration: ["ignore_attributes": ["IgnoreMe"]]), + Example("var bol↓: Bool = true", configuration: ["consider_default_literal_types_redundant": true]), + Example("var dbl↓: Double = 0.0", configuration: ["consider_default_literal_types_redundant": true]), + Example("var int↓: Int = 0", configuration: ["consider_default_literal_types_redundant": true]), + Example("var str↓: String = \"str\"", configuration: ["consider_default_literal_types_redundant": true]) ], corrections: [ Example("var url↓: URL = URL()"): Example("var url = URL()"), @@ -159,7 +166,15 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { let i = Int(1) return i } - """) + """), + Example("var bol: Bool = true", configuration: ["consider_default_literal_types_redundant": true]): + Example("var bol = true"), + Example("var dbl: Double = 0.0", configuration: ["consider_default_literal_types_redundant": true]): + Example("var dbl = 0.0"), + Example("var int: Int = 0", configuration: ["consider_default_literal_types_redundant": true]): + Example("var int = 0"), + Example("var str: String = \"str\"", configuration: ["consider_default_literal_types_redundant": true]): + Example("var str = \"str\"") ] ) } @@ -168,52 +183,44 @@ private extension RedundantTypeAnnotationRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: PatternBindingSyntax) { guard let varDecl = node.parent?.parent?.as(VariableDeclSyntax.self), - configuration.ignoreAttributes.allSatisfy({ !varDecl.attributes.contains(attributeNamed: $0) }) else { + configuration.ignoreAttributes.allSatisfy({ !varDecl.attributes.contains(attributeNamed: $0) }), + let typeAnnotation = node.typeAnnotation, + let initializer = node.initializer?.value else { return } - if let typeAnnotation = node.typeAnnotation, - let initializer = node.initializer?.value, - typeAnnotation.isRedundant(with: initializer) { - violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) - violationCorrections.append(ViolationCorrection( - start: typeAnnotation.position, - end: typeAnnotation.endPositionBeforeTrailingTrivia, - replacement: "" - )) + let validateLiterals = configuration.considerDefaultLiteralTypesRedundant + let isLiteralRedundant = validateLiterals && initializer.hasRedundantLiteralType(typeAnnotation.type) + guard isLiteralRedundant || initializer.hasRedundantType(typeAnnotation.type) else { + return } + violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) + violationCorrections.append(ViolationCorrection( + start: typeAnnotation.position, + end: typeAnnotation.endPositionBeforeTrailingTrivia, + replacement: "" + )) } override func visitPost(_ node: OptionalBindingConditionSyntax) { - if let typeAnnotation = node.typeAnnotation, - let initializer = node.initializer?.value, - typeAnnotation.isRedundant(with: initializer) { - violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) - violationCorrections.append(ViolationCorrection( - start: typeAnnotation.position, - end: typeAnnotation.endPositionBeforeTrailingTrivia, - replacement: "" - )) + guard let typeAnnotation = node.typeAnnotation, + let initializer = node.initializer?.value else { + return } + let validateLiterals = configuration.considerDefaultLiteralTypesRedundant + let isLiteralRedundant = validateLiterals && initializer.hasRedundantLiteralType(typeAnnotation.type) + guard isLiteralRedundant || initializer.hasRedundantType(typeAnnotation.type) else { + return + } + violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) + violationCorrections.append(ViolationCorrection( + start: typeAnnotation.position, + end: typeAnnotation.endPositionBeforeTrailingTrivia, + replacement: "" + )) } } } -private extension TypeAnnotationSyntax { - func isRedundant(with initializerExpr: ExprSyntax) -> Bool { - var initializer = initializerExpr - if let forceUnwrap = initializer.as(ForceUnwrapExprSyntax.self) { - initializer = forceUnwrap.expression - } - - // If the initializer is a boolean expression, we consider using the `Bool` type - // annotation as redundant. - if initializer.is(BooleanLiteralExprSyntax.self) { - return type.trimmedDescription == "Bool" - } - return initializer.accessedNames.contains(type.trimmedDescription) - } -} - private extension ExprSyntax { /// An expression can represent an access to an identifier in one or another way depending on the exact underlying /// expression type. E.g. the expression `A` accesses `A` while `f()` accesses `f` and `a.b.c` accesses `a` in the @@ -233,4 +240,33 @@ private extension ExprSyntax { [] } } + + func hasRedundantLiteralType(_ type: TypeSyntax) -> Bool { + type.trimmedDescription == kind.compilerInferredLiteralType + } + + func hasRedundantType(_ type: TypeSyntax) -> Bool { + var expr = self + if let forceUnwrap = expr.as(ForceUnwrapExprSyntax.self) { + expr = forceUnwrap.expression + } + return expr.accessedNames.contains(type.trimmedDescription) + } +} + +private extension SyntaxKind { + var compilerInferredLiteralType: String? { + switch self { + case .booleanLiteralExpr: + "Bool" + case .floatLiteralExpr: + "Double" + case .integerLiteralExpr: + "Int" + case .stringLiteralExpr: + "String" + default: + nil + } + } } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift index 01c22d6005..fa837304f5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift @@ -8,4 +8,6 @@ struct RedundantTypeAnnotationConfiguration: SeverityBasedRuleConfiguration { var severityConfiguration = SeverityConfiguration(.warning) @ConfigurationElement(key: "ignore_attributes") var ignoreAttributes = Set(["IBInspectable"]) + @ConfigurationElement(key: "consider_default_literal_types_redundant") + private(set) var considerDefaultLiteralTypesRedundant = false } diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index a8796526ee..404b9ef45d 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -457,6 +457,7 @@ redundant_string_enum_value: redundant_type_annotation: severity: warning ignore_attributes: ["IBInspectable"] + consider_default_literal_types_redundant: false redundant_void_return: severity: warning include_closures: true From 1658f1de70c9b4ea5ed5498e50ce148c14c0dd7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 1 May 2024 21:48:13 +0200 Subject: [PATCH 039/265] Extract method for common code and make signatures swiftier (#5554) --- .../RedundantTypeAnnotationRule.swift | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index 5810619632..5be4a8b2dd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -182,39 +182,31 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { private extension RedundantTypeAnnotationRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: PatternBindingSyntax) { - guard let varDecl = node.parent?.parent?.as(VariableDeclSyntax.self), - configuration.ignoreAttributes.allSatisfy({ !varDecl.attributes.contains(attributeNamed: $0) }), - let typeAnnotation = node.typeAnnotation, - let initializer = node.initializer?.value else { - return - } - let validateLiterals = configuration.considerDefaultLiteralTypesRedundant - let isLiteralRedundant = validateLiterals && initializer.hasRedundantLiteralType(typeAnnotation.type) - guard isLiteralRedundant || initializer.hasRedundantType(typeAnnotation.type) else { - return + if let varDecl = node.parent?.parent?.as(VariableDeclSyntax.self), + configuration.ignoreAttributes.allSatisfy({ !varDecl.attributes.contains(attributeNamed: $0) }), + let typeAnnotation = node.typeAnnotation, + let initializer = node.initializer?.value { + collectViolation(forType: typeAnnotation, withInitializer: initializer) } - violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) - violationCorrections.append(ViolationCorrection( - start: typeAnnotation.position, - end: typeAnnotation.endPositionBeforeTrailingTrivia, - replacement: "" - )) } override func visitPost(_ node: OptionalBindingConditionSyntax) { - guard let typeAnnotation = node.typeAnnotation, - let initializer = node.initializer?.value else { - return + if let typeAnnotation = node.typeAnnotation, + let initializer = node.initializer?.value { + collectViolation(forType: typeAnnotation, withInitializer: initializer) } + } + + private func collectViolation(forType type: TypeAnnotationSyntax, withInitializer initializer: ExprSyntax) { let validateLiterals = configuration.considerDefaultLiteralTypesRedundant - let isLiteralRedundant = validateLiterals && initializer.hasRedundantLiteralType(typeAnnotation.type) - guard isLiteralRedundant || initializer.hasRedundantType(typeAnnotation.type) else { + let isLiteralRedundant = validateLiterals && initializer.hasRedundant(literalType: type.type) + guard isLiteralRedundant || initializer.hasRedundant(type: type.type) else { return } - violations.append(typeAnnotation.positionAfterSkippingLeadingTrivia) + violations.append(type.positionAfterSkippingLeadingTrivia) violationCorrections.append(ViolationCorrection( - start: typeAnnotation.position, - end: typeAnnotation.endPositionBeforeTrailingTrivia, + start: type.position, + end: type.endPositionBeforeTrailingTrivia, replacement: "" )) } @@ -241,16 +233,13 @@ private extension ExprSyntax { } } - func hasRedundantLiteralType(_ type: TypeSyntax) -> Bool { + func hasRedundant(literalType type: TypeSyntax) -> Bool { type.trimmedDescription == kind.compilerInferredLiteralType } - func hasRedundantType(_ type: TypeSyntax) -> Bool { - var expr = self - if let forceUnwrap = expr.as(ForceUnwrapExprSyntax.self) { - expr = forceUnwrap.expression - } - return expr.accessedNames.contains(type.trimmedDescription) + func hasRedundant(type: TypeSyntax) -> Bool { + `as`(ForceUnwrapExprSyntax.self)?.expression.hasRedundant(type: type) + ?? accessedNames.contains(type.trimmedDescription) } } From 11cbac63d1a1cb64819a290c14b9b485caeb5c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 1 May 2024 21:58:42 +0200 Subject: [PATCH 040/265] Enable `consider_default_literal_types_redundant` option (#5555) --- .swiftlint.yml | 2 ++ .../Rules/Idiomatic/StrictFilePrivateRule.swift | 2 +- .../Extensions/Configuration+Remote.swift | 10 +++++----- Source/SwiftLintCore/Models/Location.swift | 6 +++--- Source/SwiftLintCore/Reporters/JSONReporter.swift | 2 +- .../RuleConfigurations/RegexConfiguration.swift | 2 +- .../SeverityLevelsConfiguration.swift | 2 +- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 1a9c0662cd..ca4daf6e3f 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -80,6 +80,8 @@ single_test_class: *unit_test_configuration final_test_case: *unit_test_configuration function_body_length: 60 type_body_length: 400 +redundant_type_annotation: + consider_default_literal_types_redundant: true custom_rules: rule_id: diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift index d36aa2bd7c..ca57cd6822 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift @@ -205,7 +205,7 @@ private extension StrictFilePrivateRule { private final class ProtocolCollector: ViolationsSyntaxVisitor { private(set) var protocols = [String: [ProtocolRequirementType]]() - private var currentProtocolName: String = "" + private var currentProtocolName = "" override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .allExcept(ProtocolDeclSyntax.self) } diff --git a/Source/SwiftLintCore/Extensions/Configuration+Remote.swift b/Source/SwiftLintCore/Extensions/Configuration+Remote.swift index 186dc88e47..3337ad1da0 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Remote.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Remote.swift @@ -7,19 +7,19 @@ import FoundationNetworking internal extension Configuration.FileGraph.FilePath { // MARK: - Properties: Remote Cache /// This should never be touched. - private static let swiftlintPath: String = ".swiftlint" + private static let swiftlintPath = ".swiftlint" /// This should never be touched. Change the version number for changes to the cache format - private static let remoteCachePath: String = "\(swiftlintPath)/RemoteConfigCache" + private static let remoteCachePath = "\(swiftlintPath)/RemoteConfigCache" /// If the format of the caching is changed in the future, change this version number - private static let remoteCacheVersionNumber: String = "v1" + private static let remoteCacheVersionNumber = "v1" /// Use this to get the path to the cache directory for the current cache format - private static let versionedRemoteCachePath: String = "\(remoteCachePath)/\(remoteCacheVersionNumber)" + private static let versionedRemoteCachePath = "\(remoteCachePath)/\(remoteCacheVersionNumber)" /// The path to the gitignore file. - private static let gitignorePath: String = ".gitignore" + private static let gitignorePath = ".gitignore" /// This dictionary has URLs as its keys and contents of those URLs as its values /// In production mode, this should be empty. For tests, it may be filled. diff --git a/Source/SwiftLintCore/Models/Location.swift b/Source/SwiftLintCore/Models/Location.swift index 5e4202467a..0b12874209 100644 --- a/Source/SwiftLintCore/Models/Location.swift +++ b/Source/SwiftLintCore/Models/Location.swift @@ -15,9 +15,9 @@ public struct Location: CustomStringConvertible, Comparable, Codable, Sendable { public var description: String { // Xcode likes warnings and errors in the following format: // {full_path_to_file}{:line}{:character}: {error,warning}: {content} - let fileString: String = file ?? "" - let lineString: String = ":\(line ?? 1)" - let charString: String = ":\(character ?? 1)" + let fileString = file ?? "" + let lineString = ":\(line ?? 1)" + let charString = ":\(character ?? 1)" return [fileString, lineString, charString].joined() } diff --git a/Source/SwiftLintCore/Reporters/JSONReporter.swift b/Source/SwiftLintCore/Reporters/JSONReporter.swift index 78834307e2..f5a866f151 100644 --- a/Source/SwiftLintCore/Reporters/JSONReporter.swift +++ b/Source/SwiftLintCore/Reporters/JSONReporter.swift @@ -7,7 +7,7 @@ struct JSONReporter: Reporter { static let identifier = "json" static let isRealtime = false - static let description: String = "Reports violations as a JSON array." + static let description = "Reports violations as a JSON array." static func generateReport(_ violations: [StyleViolation]) -> String { return toJSON(violations.map(dictionary(for:))) diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index e955060e3e..c25c4dfb1b 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -23,7 +23,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, @ConfigurationElement(key: "severity") public var severityConfiguration = SeverityConfiguration(.warning) /// The index of the regex capture group to match. - public var captureGroup: Int = 0 + public var captureGroup = 0 public var cacheDescription: String { let jsonObject: [String] = [ diff --git a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift index 1e6e2c7937..8403bcb327 100644 --- a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift @@ -2,7 +2,7 @@ public struct SeverityLevelsConfiguration: RuleConfiguration, InlinableOptionType { /// The threshold for a violation to be a warning. @ConfigurationElement(key: "warning") - public var warning: Int = 12 + public var warning = 12 /// The threshold for a violation to be an error. @ConfigurationElement(key: "error") public var error: Int? From 3258fc8089df0d8de378fb8bb48bcbf4cde5f317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 1 May 2024 22:20:21 +0200 Subject: [PATCH 041/265] Sort and categorize configuration (#5556) --- .swiftlint.yml | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index ca4daf6e3f..456678cd5e 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,9 +1,12 @@ +# Directory and file filters included: - Plugins - Source - Tests excluded: - Tests/SwiftLintFrameworkTests/Resources + +# Enabled/disabled rules analyzer_rules: - unused_declaration - unused_import @@ -50,17 +53,17 @@ disabled_rules: - unused_capture_list - vertical_whitespace_between_cases +# Configurations attributes: always_on_line_above: - "@ConfigurationElement" - "@OptionGroup" - "@RuleConfigurationDescriptionBuilder" -identifier_name: - excluded: - - id -large_tuple: 3 -number_separator: - minimum_length: 5 +balanced_xctest_lifecycle: &unit_test_configuration + test_parent_classes: + - SwiftLintTestCase + - XCTestCase +empty_xctest_method: *unit_test_configuration file_name: excluded: - Exports.swift @@ -68,21 +71,26 @@ file_name: - RuleConfigurationMacros.swift - SwiftSyntax+SwiftLint.swift - TestHelpers.swift -unneeded_override: - affect_initializers: true - -balanced_xctest_lifecycle: &unit_test_configuration - test_parent_classes: - - SwiftLintTestCase - - XCTestCase -empty_xctest_method: *unit_test_configuration -single_test_class: *unit_test_configuration final_test_case: *unit_test_configuration function_body_length: 60 -type_body_length: 400 +identifier_name: + excluded: + - id +large_tuple: 3 +number_separator: + minimum_length: 5 redundant_type_annotation: consider_default_literal_types_redundant: true +single_test_class: *unit_test_configuration +type_body_length: 400 +unneeded_override: + affect_initializers: true +unused_import: + always_keep_imports: + - SwiftSyntaxBuilder # we can't detect uses of string interpolation of swift syntax nodes + - SwiftLintFramework # now that this is a wrapper around other modules, don't treat as unused +# Custom rules custom_rules: rule_id: included: Source/SwiftLintBuiltInRules/Rules/.+/\w+\.swift @@ -104,8 +112,3 @@ custom_rules: message: Rule Test Function mustn't end with `rule` regex: func\s*test\w+(r|R)ule\(\) severity: error - -unused_import: - always_keep_imports: - - SwiftSyntaxBuilder # we can't detect uses of string interpolation of swift syntax nodes - - SwiftLintFramework # now that this is a wrapper around other modules, don't treat as unused From 5f8fe00bf9b0200d6066be42c1f85a20c9770f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 1 May 2024 18:59:48 +0200 Subject: [PATCH 042/265] Pass an entity's parent to the traversal block as well --- .../Rules/Lint/CaptureVariableRule.swift | 20 +++++++++---------- .../Rules/Lint/UnusedDeclarationRule.swift | 8 ++++---- .../Extensions/Dictionary+SwiftLint.swift | 12 ++++++----- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift index 388c0e96a1..f86ad77a04 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift @@ -206,13 +206,13 @@ private extension SwiftLintFile { let offsets = self.captureListVariableOffsets() guard !offsets.isEmpty, let indexEntities = index(compilerArguments: compilerArguments) else { return Set() } - return Set(indexEntities.traverseEntitiesDepthFirst { + return Set(indexEntities.traverseEntitiesDepthFirst { _, entity in guard - let kind = $0.kind, + let kind = entity.kind, kind.hasPrefix("source.lang.swift.ref.var."), - let usr = $0.usr, - let line = $0.line, - let column = $0.column, + let usr = entity.usr, + let line = entity.line, + let column = entity.column, let offset = stringView.byteOffset(forLine: line, bytePosition: column) else { return nil } return offsets.contains(offset) ? CaptureVariableRule.Variable(usr: usr, offset: offset) : nil @@ -245,16 +245,16 @@ private extension SwiftLintFile { let offsets = self.declaredVariableOffsets() guard !offsets.isEmpty, let indexEntities = index(compilerArguments: compilerArguments) else { return Set() } - return Set(indexEntities.traverseEntitiesDepthFirst { + return Set(indexEntities.traverseEntitiesDepthFirst { _, entity in guard - let declarationKind = $0.declarationKind, + let declarationKind = entity.declarationKind, Self.checkedDeclarationKinds.contains(declarationKind), - let line = $0.line, - let column = $0.column, + let line = entity.line, + let column = entity.column, let offset = stringView.byteOffset(forLine: line, bytePosition: column), offsets.contains(offset) else { return nil } - return $0.usr + return entity.usr }) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index 4820a6b35e..00e56b480c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -90,7 +90,7 @@ private extension SwiftLintFile { } func referencedUSRs(index: SourceKittenDictionary) -> Set { - return Set(index.traverseEntitiesDepthFirst { entity -> String? in + return Set(index.traverseEntitiesDepthFirst { _, entity -> String? in if let usr = entity.usr, let kind = entity.kind, kind.starts(with: "source.lang.swift.ref") { @@ -104,7 +104,7 @@ private extension SwiftLintFile { func declaredUSRs(index: SourceKittenDictionary, editorOpen: SourceKittenDictionary, compilerArguments: [String], configuration: UnusedDeclarationConfiguration) -> Set { - return Set(index.traverseEntitiesDepthFirst { indexEntity in + return Set(index.traverseEntitiesDepthFirst { _, indexEntity in self.declaredUSR(indexEntity: indexEntity, editorOpen: editorOpen, compilerArguments: compilerArguments, configuration: configuration) }) @@ -140,14 +140,14 @@ private extension SwiftLintFile { // Skip CodingKeys as they are used for Codable generation if kind == .enum, indexEntity.name == "CodingKeys", - case let allRelatedUSRs = indexEntity.traverseEntitiesDepthFirst(traverseBlock: { $0.usr }), + case let allRelatedUSRs = indexEntity.traverseEntitiesDepthFirst(traverseBlock: { $1.usr }), allRelatedUSRs.contains("s:s9CodingKeyP") { return nil } // Skip `static var allTests` members since those are used for Linux test discovery. if kind == .varStatic, indexEntity.name == "allTests" { - let allTestCandidates = indexEntity.traverseEntitiesDepthFirst { subEntity -> Bool in + let allTestCandidates = indexEntity.traverseEntitiesDepthFirst { _, subEntity -> Bool in subEntity.value["key.is_test_candidate"] as? Bool == true } diff --git a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift index af8c31c1e5..5d96d507a9 100644 --- a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift @@ -190,6 +190,9 @@ public struct SourceKittenDictionary { } extension SourceKittenDictionary { + /// Block executed for every encountered entity during traversal of a dictionary. + public typealias TraverseBlock = (_ parent: SourceKittenDictionary, _ entity: SourceKittenDictionary) -> T? + /// Traversing all substuctures of the dictionary hierarchically, calling `traverseBlock` on each node. /// Traversing using depth first strategy, so deepest substructures will be passed to `traverseBlock` first. /// @@ -216,21 +219,20 @@ extension SourceKittenDictionary { /// Traversing all entities of the dictionary hierarchically, calling `traverseBlock` on each node. /// Traversing using depth first strategy, so deepest substructures will be passed to `traverseBlock` first. /// - /// - parameter traverseBlock: block that will be called for each entity in the dictionary. + /// - parameter traverseBlock: Block that will be called for each entity and its parent in the dictionary. /// /// - returns: The list of entity dictionaries with updated values from the traverse block. - public func traverseEntitiesDepthFirst(traverseBlock: (SourceKittenDictionary) -> T?) -> [T] { + public func traverseEntitiesDepthFirst(traverseBlock: TraverseBlock) -> [T] { var result: [T] = [] traverseEntitiesDepthFirst(collectingValuesInto: &result, traverseBlock: traverseBlock) return result } - private func traverseEntitiesDepthFirst(collectingValuesInto array: inout [T], - traverseBlock: (SourceKittenDictionary) -> T?) { + private func traverseEntitiesDepthFirst(collectingValuesInto array: inout [T], traverseBlock: TraverseBlock) { entities.forEach { subDict in subDict.traverseEntitiesDepthFirst(collectingValuesInto: &array, traverseBlock: traverseBlock) - if let collectedValue = traverseBlock(subDict) { + if let collectedValue = traverseBlock(self, subDict) { array.append(collectedValue) } } From 4a72167b95900cc8631f97462274eff514144bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 1 May 2024 21:16:42 +0200 Subject: [PATCH 043/265] Check that a reference is not just extended --- CHANGELOG.md | 5 +++ .../Rules/Lint/UnusedDeclarationRule.swift | 41 ++++++++++++++----- .../Lint/UnusedDeclarationRuleExamples.swift | 17 +++++++- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 717fc5ff21..54918a70ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -223,6 +223,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5489](https://github.com/realm/SwiftLint/pull/5489) +* Ensure that declarations referenced only as extended types do not count as + used by means of the `unused_declaration` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5550](https://github.com/realm/SwiftLint/issues/5550) + * Fix some false positives in `multiline_literal_brackets` rule that would happen when comments are present. [Marcelo Fabri](https://github.com/marcelofabri) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index 00e56b480c..02ce724740 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -46,7 +46,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { } return FileUSRs( - referenced: file.referencedUSRs(index: index), + referenced: file.referencedUSRs(index: index, editorOpen: editorOpen), declared: file.declaredUSRs(index: index, editorOpen: editorOpen, compilerArguments: compilerArguments, @@ -89,11 +89,16 @@ private extension SwiftLintFile { .map(SourceKittenDictionary.init) } - func referencedUSRs(index: SourceKittenDictionary) -> Set { - return Set(index.traverseEntitiesDepthFirst { _, entity -> String? in + func referencedUSRs(index: SourceKittenDictionary, editorOpen: SourceKittenDictionary) -> Set { + return Set(index.traverseEntitiesDepthFirst { parent, entity -> String? in if let usr = entity.usr, - let kind = entity.kind, - kind.starts(with: "source.lang.swift.ref") { + let kind = entity.kind, + kind.starts(with: "source.lang.swift.ref"), + !parent.extends(reference: entity), + let line = entity.line, + let column = entity.column, + let nameOffset = stringView.byteOffset(forLine: line, bytePosition: column), + editorOpen.propertyAtOffset(nameOffset, property: \.kind) != "source.lang.swift.decl.extension" { return usr } @@ -133,7 +138,8 @@ private extension SwiftLintFile { return nil } - if !configuration.includePublicAndOpen, [.public, .open].contains(editorOpen.aclAtOffset(nameOffset)) { + if !configuration.includePublicAndOpen, + [.public, .open].contains(editorOpen.propertyAtOffset(nameOffset, property: \.accessibility)) { return nil } @@ -230,14 +236,14 @@ private extension SourceKittenDictionary { return value["key.is_implicit"] as? Bool == true } - func aclAtOffset(_ offset: ByteCount) -> AccessControlLevel? { + func propertyAtOffset(_ offset: ByteCount, property: KeyPath) -> T? { if let nameOffset, nameOffset == offset, - let acl = accessibility { - return acl + let field = self[keyPath: property] { + return field } for child in substructure { - if let acl = child.aclAtOffset(offset) { + if let acl = child.propertyAtOffset(offset, property: property) { return acl } } @@ -296,6 +302,21 @@ private extension SourceKittenDictionary { return resultBuilderStaticMethods.contains(name) } + + func extends(reference other: Self) -> Bool { + if let kind, kind.starts(with: "source.lang.swift.decl.extension") { + let extendedKind = kind.components(separatedBy: ".").last + return extendedKind != nil && extendedKind == other.referencedKind + } + return false + } + + private var referencedKind: String? { + if let kind, kind.starts(with: "source.lang.swift.ref") { + return kind.components(separatedBy: ".").last + } + return nil + } } // Skip initializers, deinit, enum cases and subscripts since we can't reliably detect if they're used. diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift index 937838f2e9..3118ed3ba3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift @@ -207,8 +207,23 @@ struct UnusedDeclarationRuleExamples { } _ = ComponentBuilder() + """), + Example(""" + protocol ↓Foo {} + extension Foo {} + """), + Example(""" + class ↓C {} + extension C {} """) - ] + platformSpecificTriggeringExamples + ] + ["actor", "enum", "class", "struct"].map { + Example(""" + protocol Foo {} + \($0) ↓FooImpl {} + extension FooImpl {} + extension FooImpl: Foo {} + """, excludeFromDocumentation: true) + } + platformSpecificTriggeringExamples #if os(macOS) private static let platformSpecificNonTriggeringExamples = [ From d734022778af1b9b0a922b4bc2984253a7779fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 4 May 2024 15:52:21 +0200 Subject: [PATCH 044/265] Add `package` ACL (#5559) --- Source/SwiftLintCore/Models/AccessControlLevel.swift | 9 +++++++-- .../AccessControlLevelTests.swift | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/SwiftLintCore/Models/AccessControlLevel.swift b/Source/SwiftLintCore/Models/AccessControlLevel.swift index 5e23aca586..cade95837b 100644 --- a/Source/SwiftLintCore/Models/AccessControlLevel.swift +++ b/Source/SwiftLintCore/Models/AccessControlLevel.swift @@ -8,6 +8,8 @@ public enum AccessControlLevel: String, CustomStringConvertible { case `fileprivate` = "source.lang.swift.accessibility.fileprivate" /// Accessible by the declaration's same module, or modules importing it with the `@testable` attribute. case `internal` = "source.lang.swift.accessibility.internal" + /// Accessible by all the modules defined in the same Swift package. + case `package` = "source.lang.swift.accessibility.package" /// Accessible by the declaration's same program. case `public` = "source.lang.swift.accessibility.public" /// Accessible and customizable (via subclassing or overrides) by the declaration's same program. @@ -21,6 +23,7 @@ public enum AccessControlLevel: String, CustomStringConvertible { case "private": self = .private case "fileprivate": self = .fileprivate case "internal": self = .internal + case "package": self = .package case "public": self = .public case "open": self = .open default: return nil @@ -39,6 +42,7 @@ public enum AccessControlLevel: String, CustomStringConvertible { case .private: return "private" case .fileprivate: return "fileprivate" case .internal: return "internal" + case .package: return "package" case .public: return "public" case .open: return "open" } @@ -56,8 +60,9 @@ extension AccessControlLevel: Comparable { case .private: return 1 case .fileprivate: return 2 case .internal: return 3 - case .public: return 4 - case .open: return 5 + case .package: return 4 + case .public: return 5 + case .open: return 6 } } diff --git a/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift b/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift index e9d9589b40..ac1efded9d 100644 --- a/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift +++ b/Tests/SwiftLintFrameworkTests/AccessControlLevelTests.swift @@ -6,6 +6,7 @@ final class AccessControlLevelTests: SwiftLintTestCase { XCTAssertEqual(AccessControlLevel.private.description, "private") XCTAssertEqual(AccessControlLevel.fileprivate.description, "fileprivate") XCTAssertEqual(AccessControlLevel.internal.description, "internal") + XCTAssertEqual(AccessControlLevel.package.description, "package") XCTAssertEqual(AccessControlLevel.public.description, "public") XCTAssertEqual(AccessControlLevel.open.description, "open") } @@ -13,7 +14,8 @@ final class AccessControlLevelTests: SwiftLintTestCase { func testPriority() { XCTAssertLessThan(AccessControlLevel.private, .fileprivate) XCTAssertLessThan(AccessControlLevel.fileprivate, .internal) - XCTAssertLessThan(AccessControlLevel.internal, .public) + XCTAssertLessThan(AccessControlLevel.internal, .package) + XCTAssertLessThan(AccessControlLevel.package, .public) XCTAssertLessThan(AccessControlLevel.public, .open) } } From 6834393712c2ee69ad0f9103acc2cc62136384cc Mon Sep 17 00:00:00 2001 From: "iulianOnofrei (U-lee-aan)" <5748627+revolter@users.noreply.github.com> Date: Wed, 8 May 2024 23:34:17 +0300 Subject: [PATCH 045/265] Use Swift Argument Parser from version 1.2.1 (#5562) --- Package.resolved | 8 ++++---- Package.swift | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Package.resolved b/Package.resolved index 84a5b28ce4..620c440cbc 100644 --- a/Package.resolved +++ b/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/jpsim/SourceKitten.git", "state" : { - "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", - "version" : "0.34.1" + "revision" : "fd4df99170f5e9d7cf9aa8312aa8506e0e7a44e7", + "version" : "0.35.0" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { - "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", - "version" : "1.2.3" + "revision" : "46989693916f56d1186bd59ac15124caef896560", + "version" : "1.3.1" } }, { diff --git a/Package.swift b/Package.swift index 73a30a47ca..27af292450 100644 --- a/Package.swift +++ b/Package.swift @@ -23,9 +23,9 @@ let package = Package( .plugin(name: "SwiftLintCommandPlugin", targets: ["SwiftLintCommandPlugin"]) ], dependencies: [ - .package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.1")), + .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.0"), - .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.34.1")), + .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), .package(url: "https://github.com/JohnSundell/CollectionConcurrencyKit.git", from: "0.2.0"), From 0a2878d559264ddd27f28d61eac75737f6e5ccc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 9 May 2024 10:21:53 +0200 Subject: [PATCH 046/265] Update Bazel and SPM dependencies (#5563) SourceKitten 0.35.0 Swift Argument Parser 1.3.1 SwiftSyntax 510.0.2 --- MODULE.bazel | 6 +++--- Package.resolved | 4 ++-- Package.swift | 2 +- bazel/deps.bzl | 3 --- bazel/repos.bzl | 12 ++++++------ 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index d9b455aaff..67e649636e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -10,9 +10,9 @@ bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "rules_apple", version = "3.1.1", repo_name = "build_bazel_rules_apple") bazel_dep(name = "rules_swift", version = "1.16.0", repo_name = "build_bazel_rules_swift") -bazel_dep(name = "sourcekitten", version = "0.34.1", repo_name = "com_github_jpsim_sourcekitten") -bazel_dep(name = "swift-syntax", version = "510.0.0", repo_name = "SwiftSyntax") -bazel_dep(name = "swift_argument_parser", version = "1.2.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") +bazel_dep(name = "sourcekitten", version = "0.35.0", repo_name = "com_github_jpsim_sourcekitten") +bazel_dep(name = "swift-syntax", version = "510.0.2", repo_name = "SwiftSyntax") +bazel_dep(name = "swift_argument_parser", version = "1.3.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") bazel_dep(name = "yams", version = "5.0.6", repo_name = "sourcekitten_com_github_jpsim_yams") swiftlint_repos = use_extension("//bazel:repos.bzl", "swiftlint_repos_bzlmod") diff --git a/Package.resolved b/Package.resolved index 620c440cbc..0c9c7c9860 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "08a2f0a9a30e0f705f79c9cfaca1f68b71bdc775", - "version" : "510.0.0" + "revision" : "303e5c5c36d6a558407d364878df131c3546fad8", + "version" : "510.0.2" } }, { diff --git a/Package.swift b/Package.swift index 27af292450..05cc2bfc51 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), - .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.0"), + .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.2"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), diff --git a/bazel/deps.bzl b/bazel/deps.bzl index 13f9e3f6d7..de21f081f1 100644 --- a/bazel/deps.bzl +++ b/bazel/deps.bzl @@ -1,5 +1,4 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load("@com_github_jpsim_sourcekitten//bazel:repos.bzl", "sourcekitten_repos") def _extra_swift_sources_impl(ctx): ctx.file("WORKSPACE", "") @@ -36,5 +35,3 @@ def swiftlint_deps(): if not native.existing_rule("swiftlint_extra_rules"): extra_swift_sources(name = "swiftlint_extra_rules") - - sourcekitten_repos() diff --git a/bazel/repos.bzl b/bazel/repos.bzl index cbdf471875..93a8cce26a 100644 --- a/bazel/repos.bzl +++ b/bazel/repos.bzl @@ -5,16 +5,16 @@ def swiftlint_repos(bzlmod = False): if not bzlmod: http_archive( name = "com_github_jpsim_sourcekitten", - sha256 = "fcc5ea783e6a0b58b3873c3d551c0ff7a146fdd536e66e1d37af13b1f52df3d4", - strip_prefix = "SourceKitten-0.34.1", - url = "https://github.com/jpsim/SourceKitten/releases/download/0.34.1/SourceKitten-0.34.1.tar.gz", + sha256 = "d9c559166f01627826505b0e655b56a59f86938389e1739259e6ce49c9fd95f0", + strip_prefix = "SourceKitten-0.35.0", + url = "https://github.com/jpsim/SourceKitten/releases/download/0.35.0/SourceKitten-0.35.0.tar.gz", ) http_archive( name = "SwiftSyntax", - sha256 = "1cddda9f7d249612e3d75d4caa8fd9534c0621b8a890a7d7524a4689bce644f1", - strip_prefix = "swift-syntax-509.0.0", - url = "https://github.com/apple/swift-syntax/archive/refs/tags/509.0.0.tar.gz", + sha256 = "6572f60ca3c75c2a40f8ccec98c5cd0d3994599a39402d69b433381aaf2c1712", + strip_prefix = "swift-syntax-510.0.2", + url = "https://github.com/apple/swift-syntax/archive/refs/tags/510.0.2.tar.gz", ) http_archive( From b17bbaaebc520785eb9de38a713bbe59e904a5e6 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 11 May 2024 08:43:39 +0100 Subject: [PATCH 047/265] Remove severity as a baseline key (#5566) It interacts poorly with `--strict`. --- Source/SwiftLintCore/Models/Baseline.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintCore/Models/Baseline.swift b/Source/SwiftLintCore/Models/Baseline.swift index 8e99891575..630537caaa 100644 --- a/Source/SwiftLintCore/Models/Baseline.swift +++ b/Source/SwiftLintCore/Models/Baseline.swift @@ -7,7 +7,7 @@ private typealias ViolationsPerRule = [String: BaselineViolations] private struct BaselineViolation: Codable, Hashable { let violation: StyleViolation let text: String - var key: String { text + violation.reason + violation.severity.rawValue } + var key: String { text + violation.reason } init(violation: StyleViolation, text: String) { let location = violation.location From c29391a5aeee1b483b205cab56c253111673428d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 11 May 2024 12:28:10 +0200 Subject: [PATCH 048/265] Ignore but report invalid keys (#5567) Don't fall back to the default configuration due to invalid keys. --- CHANGELOG.md | 5 +++++ Source/SwiftLintCore/Models/Issue.swift | 2 +- .../RuleConfigurationMacros.swift | 2 +- Tests/MacroTests/AutoApplyTests.swift | 10 ++++----- ...licitTypeInterfaceConfigurationTests.swift | 7 +++--- .../RuleConfigurationDescriptionTests.swift | 22 ++++++++++++------- 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54918a70ac..50d18c3e25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -204,6 +204,11 @@ #### Bug Fixes +* Invalid keys in a configuration don't lead to the default configuration being + used anymore. The invalid key will just be reported but otherwise ignored. + [SimplyDanny](https://github.com/SimplyDanny) + [#5565](https://github.com/realm/SwiftLint/issues/5565) + * Fix version comparison algorithm which caused some version-dependent rules to misbehave with Swift 5.10. [chandlerwall](https://github.com/chandlerwall) diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 1e9cc6ef59..0fb24acf0c 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -86,7 +86,7 @@ public enum Issue: LocalizedError, Equatable { /// - returns: The collected messages produced while running the code in the runner. static func captureConsole(runner: () throws -> Void) rethrows -> String { var console = "" - messageConsumer = { console += $0 } + messageConsumer = { console += (console.isEmpty ? "" : "\n") + $0 } defer { messageConsumer = nil } try runner() return console diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index f303ab22b8..036d4177bb 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -80,7 +80,7 @@ enum AutoApply: MemberMacro { """ if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) - throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) + Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } """ }) diff --git a/Tests/MacroTests/AutoApplyTests.swift b/Tests/MacroTests/AutoApplyTests.swift index 93b39f60fa..6e8a677f69 100644 --- a/Tests/MacroTests/AutoApplyTests.swift +++ b/Tests/MacroTests/AutoApplyTests.swift @@ -42,7 +42,7 @@ final class AutoApplyTests: XCTestCase { } if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) - throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) + Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } } } @@ -84,7 +84,7 @@ final class AutoApplyTests: XCTestCase { try eB.apply(configuration[$eB.key], ruleID: Parent.identifier) if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) - throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) + Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } } } @@ -135,7 +135,7 @@ final class AutoApplyTests: XCTestCase { try eC.apply(configuration[$eC.key], ruleID: Parent.identifier) if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) - throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) + Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } } } @@ -161,7 +161,7 @@ final class AutoApplyTests: XCTestCase { } if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) - throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) + Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } } } @@ -215,7 +215,7 @@ final class AutoApplyTests: XCTestCase { try foo.apply(configuration[$foo.key], ruleID: Parent.identifier) if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) - throw Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys) + Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } } } diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift index 474bed9035..022ce95e7e 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift @@ -21,9 +21,10 @@ final class ExplicitTypeInterfaceConfigurationTests: SwiftLintTestCase { func testInvalidKeyInCustomConfiguration() { var config = ExplicitTypeInterfaceConfiguration() - checkError(Issue.invalidConfigurationKeys(ruleID: ExplicitTypeInterfaceRule.identifier, keys: ["invalidKey"])) { - try config.apply(configuration: ["invalidKey": "error"]) - } + XCTAssertEqual( + try Issue.captureConsole { try config.apply(configuration: ["invalidKey": "error"]) }, + "warning: Configuration for 'explicit_type_interface' rule contains the invalid key(s) 'invalidKey'." + ) } func testInvalidTypeOfCustomConfiguration() { diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index 6893a14d7b..886537167b 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -502,14 +502,20 @@ final class RuleConfigurationDescriptionTests: XCTestCase { func testInvalidKeys() throws { var configuration = TestConfiguration() - checkError(Issue.invalidConfigurationKeys(ruleID: "RuleMock", keys: ["unknown", "unsupported"])) { - try configuration.apply(configuration: [ - "severity": "error", - "warning": 3, - "unknown": 1, - "unsupported": true - ]) - } + XCTAssertEqual( + try Issue.captureConsole { + try configuration.apply(configuration: [ + "severity": "error", + "warning": 3, + "unknown": 1, + "unsupported": true + ]) + }, + """ + warning: Configuration option 'set' in 'my_rule' rule is deprecated. Use the option 'other_opt' instead. + warning: Configuration for 'RuleMock' rule contains the invalid key(s) 'unknown', 'unsupported'. + """ + ) } private func description(@RuleConfigurationDescriptionBuilder _ content: () -> RuleConfigurationDescription) From 5c5390e47b91a4276fae0d77cf0dcd12bb2cd7b8 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 11 May 2024 19:49:58 +0800 Subject: [PATCH 049/265] Allow a SwiftSyntax version range (#5534) --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 05cc2bfc51..adcddccd02 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), - .package(url: "https://github.com/apple/swift-syntax.git", exact: "510.0.2"), + .package(url: "https://github.com/apple/swift-syntax.git", from: "510.0.2"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), From 84710bd6ffe9b3bfe51515c53a6135a1d18be5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 11 May 2024 22:55:54 +0200 Subject: [PATCH 050/265] Create draft release and skip publishing steps temporarily --- Makefile | 2 +- tools/create-github-release.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 822b53df1a..42225f1629 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ endif git push origin HEAD git push origin $(NEW_VERSION) ./tools/create-github-release.sh "$(NEW_VERSION)" - make publish + # make publish ./tools/add-new-changelog-section.sh git commit -a -m "Add new changelog section" git push origin HEAD diff --git a/tools/create-github-release.sh b/tools/create-github-release.sh index 0736a3dd7d..1fe37c3a2f 100755 --- a/tools/create-github-release.sh +++ b/tools/create-github-release.sh @@ -12,7 +12,7 @@ release_notes=$(mktemp) # Create GitHub Release release_title="$(sed -n '1s/^## //p' CHANGELOG.md)" -gh release create "$version" --title "$release_title" -F "$release_notes" +gh release create "$version" --draft --title "$release_title" -F "$release_notes" rm "$release_notes" From 460d88c036163ee2f7cb5e32c180d9143ac332ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 11 May 2024 23:09:19 +0200 Subject: [PATCH 051/265] release 0.55.0 --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d18c3e25..928017b799 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Main +## 0.55.0: Universal Washing Powder #### Breaking diff --git a/MODULE.bazel b/MODULE.bazel index 67e649636e..42c7d4fd66 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "swiftlint", - version = "0.54.0", + version = "0.55.0", compatibility_level = 1, repo_name = "SwiftLint", ) diff --git a/Package.swift b/Package.swift index adcddccd02..4bd04de7ff 100644 --- a/Package.swift +++ b/Package.swift @@ -145,8 +145,8 @@ let package = Package( ), .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.54.0/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "963121d6babf2bf5fd66a21ac9297e86d855cbc9d28322790646b88dceca00f1" + url: "https://github.com/realm/SwiftLint/releases/download/0.55.0/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "0a689bf8f851e4ab06bfce1bf5a01840984473ef720a63916611664e442499d6" ), .macro( name: "SwiftLintCoreMacros", diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index 318c136b20..b92a8e6ae9 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -4,5 +4,5 @@ public struct Version { public let value: String /// The current SwiftLint version. - public static let current = Version(value: "0.54.0") + public static let current = Version(value: "0.55.0") } From a04ecbd4d3813f9f0d8aad4d808e173609e6e8b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 11 May 2024 23:09:36 +0200 Subject: [PATCH 052/265] Add new changelog section --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 928017b799..58bd985f63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Main + +#### Breaking + +* None. + +#### Experimental + +* None. + +#### Enhancements + +* None. + +#### Bug Fixes + +* None. + ## 0.55.0: Universal Washing Powder #### Breaking From 0e9db3a065cbb127dcbeecd4ed1185df3403dd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 12 May 2024 00:27:18 +0200 Subject: [PATCH 053/265] Revert "Create draft release and skip publishing steps temporarily" This reverts commit 84710bd6ffe9b3bfe51515c53a6135a1d18be5ed. --- Makefile | 2 +- tools/create-github-release.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 42225f1629..822b53df1a 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ endif git push origin HEAD git push origin $(NEW_VERSION) ./tools/create-github-release.sh "$(NEW_VERSION)" - # make publish + make publish ./tools/add-new-changelog-section.sh git commit -a -m "Add new changelog section" git push origin HEAD diff --git a/tools/create-github-release.sh b/tools/create-github-release.sh index 1fe37c3a2f..0736a3dd7d 100755 --- a/tools/create-github-release.sh +++ b/tools/create-github-release.sh @@ -12,7 +12,7 @@ release_notes=$(mktemp) # Create GitHub Release release_title="$(sed -n '1s/^## //p' CHANGELOG.md)" -gh release create "$version" --draft --title "$release_title" -F "$release_notes" +gh release create "$version" --title "$release_title" -F "$release_notes" rm "$release_notes" From 6620d8a5daf8bb120ce21583835bffa6012e0daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 12 May 2024 00:29:49 +0200 Subject: [PATCH 054/265] Capitalize release commit message --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 822b53df1a..2dcae7143c 100644 --- a/Makefile +++ b/Makefile @@ -181,7 +181,7 @@ endif make portable_zip make spm_artifactbundle_macos ./tools/update-artifact-bundle.sh "$(NEW_VERSION)" - git commit -a -m "release $(NEW_VERSION)" + git commit -a -m "Release $(NEW_VERSION)" git tag -a $(NEW_VERSION) -m "$(NEW_VERSION_AND_NAME)" git push origin HEAD git push origin $(NEW_VERSION) From b1d3e5c29b9008ae0d1e8de5cef58de881e8c167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 12 May 2024 00:46:50 +0200 Subject: [PATCH 055/265] Create release and upload artifacts at once --- tools/create-github-release.sh | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tools/create-github-release.sh b/tools/create-github-release.sh index 0736a3dd7d..1c9ff0cefe 100755 --- a/tools/create-github-release.sh +++ b/tools/create-github-release.sh @@ -12,20 +12,11 @@ release_notes=$(mktemp) # Create GitHub Release release_title="$(sed -n '1s/^## //p' CHANGELOG.md)" -gh release create "$version" --title "$release_title" -F "$release_notes" +gh release create "$version" --title "$release_title" -F "$release_notes" \ + "bazel.tar.gz" \ + "bazel.tar.gz.sha256" \ + "portable_swiftlint.zip" \ + "SwiftLint.pkg" \ + "SwiftLintBinary-macos.artifactbundle.zip" rm "$release_notes" - -# Upload release assets - -files_to_upload=( - "bazel.tar.gz" - "bazel.tar.gz.sha256" - "portable_swiftlint.zip" - "SwiftLint.pkg" - "SwiftLintBinary-macos.artifactbundle.zip" -) - -for file in "${files_to_upload[@]}"; do - gh release upload "$version" "$file" -done From 919c10f211c82ccddfb26869030b5dcd16cb300e Mon Sep 17 00:00:00 2001 From: "Garric G. Nahapetian" Date: Mon, 13 May 2024 12:50:00 -0700 Subject: [PATCH 056/265] Fix testSARIFReporter (#5572) --- .../Resources/CannedSARIFReporterOutput.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json index e353071a66..590e84732c 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json @@ -82,9 +82,9 @@ ], "tool" : { "driver" : { - "informationUri" : "https:\/\/github.com\/realm\/SwiftLint\/blob\/0.54.0\/README.md", + "informationUri" : "https:\/\/github.com\/realm\/SwiftLint\/blob\/0.55.0\/README.md", "name" : "SwiftLint", - "semanticVersion" : "0.54.0" + "semanticVersion" : "0.55.0" } } } From e84a6fc6b2c4f1634d2b74e6a58368d761d0229f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 15 May 2024 19:41:55 +0200 Subject: [PATCH 057/265] Silence `unused_enumerated` rule when `$0` in a closure is explicitly unpacked (#5577) --- CHANGELOG.md | 4 ++- .../Idiomatic/UnusedEnumeratedRule.swift | 30 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58bd985f63..3b3fd5fdcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,9 @@ #### Bug Fixes -* None. +* Silence `unused_enumerated` rule when `$0` in a closure is explicitly unpacked. + [SimplyDanny](https://github.com/SimplyDanny) + [#5573](https://github.com/realm/SwiftLint/issues/5573) ## 0.55.0: Universal Washing Powder diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift index 55d94c785e..8e8c614296 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift @@ -29,7 +29,14 @@ struct UnusedEnumeratedRule: Rule { $1.enumerated().forEach { print($0, $1) } return $0 } - """) + """), + Example(""" + list.enumerated().forEach { + f($0) + let (i, e) = $0 + print(i) + } + """, excludeFromDocumentation: true) ], triggeringExamples: [ Example("for (↓_, foo) in bar.enumerated() { }"), @@ -72,7 +79,12 @@ struct UnusedEnumeratedRule: Rule { $1.forEach { print($0) } return $1 } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), + Example(""" + list.↓enumerated().forEach { + let (i, _) = $0 + } + """) ] ) } @@ -188,6 +200,9 @@ private extension UnusedEnumeratedRule { $0.onePosition = node.positionAfterSkippingLeadingTrivia } else { $0.zeroPosition = node.positionAfterSkippingLeadingTrivia + if node.isUnpacked { + $0.onePosition = node.positionAfterSkippingLeadingTrivia + } } } else { $0.onePosition = node.positionAfterSkippingLeadingTrivia @@ -255,3 +270,14 @@ private extension ClosureShorthandParameterSyntax { name.tokenKind == .wildcard } } + +private extension DeclReferenceExprSyntax { + var isUnpacked: Bool { + if let initializer = parent?.as(InitializerClauseSyntax.self), + let binding = initializer.parent?.as(PatternBindingSyntax.self), + let elements = binding.pattern.as(TuplePatternSyntax.self)?.elements { + return elements.count == 2 && elements.allSatisfy { !$0.pattern.is(WildcardPatternSyntax.self) } + } + return false + } +} From 40bee881320e859c87b676cfd22bd3e5c0995e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 15 May 2024 20:16:01 +0200 Subject: [PATCH 058/265] Respect configuration in `unneeded_override` rule's rewriter (#5579) --- CHANGELOG.md | 5 +++++ .../Rules/Lint/UnneededOverrideRule.swift | 2 +- .../Rules/Lint/UnneededOverrideRuleExamples.swift | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b3fd5fdcc..e5e4371af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5573](https://github.com/realm/SwiftLint/issues/5573) +* Remove redundant initializers in `unneeded_override` rule only when checking + initializers is actually enabled in the configuration. + [SimplyDanny](https://github.com/SimplyDanny) + [#5571](https://github.com/realm/SwiftLint/issues/5571) + ## 0.55.0: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift index 09534bc962..58ef48cf16 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift @@ -41,7 +41,7 @@ private extension UnneededOverrideRule { } override func visit(_ node: InitializerDeclSyntax) -> DeclSyntax { - guard node.isUnneededOverride else { + guard configuration.affectInits, node.isUnneededOverride else { return super.visit(node) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift index 25b62636de..2014039e0d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift @@ -206,6 +206,21 @@ struct UnneededOverrideRuleExamples { // This is another function func baz() {} } + """), + // Nothing happens to initializers by default. + Example(""" + class Foo { + ↓override func foo() { super.foo() } + override init(i: Int) { + super.init(i: i) + } + } + """): Example(""" + class Foo { + override init(i: Int) { + super.init(i: i) + } + } """) ] } From 3a3ec0795262f3ed9c83624d2d828d3d140be049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 15 May 2024 21:26:11 +0200 Subject: [PATCH 059/265] Fix Bazel build when `bzlmod` is not in use (#5580) --- CHANGELOG.md | 5 +++++ bazel/repos.bzl | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5e4371af4..4e40d27817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ #### Bug Fixes +* Fix Bazel build when `bzlmod` is not in use by adding transitive dependencies + explicitly. + [SimplyDanny](https://github.com/SimplyDanny) + [#5568](https://github.com/realm/SwiftLint/issues/5568) + * Silence `unused_enumerated` rule when `$0` in a closure is explicitly unpacked. [SimplyDanny](https://github.com/SimplyDanny) [#5573](https://github.com/realm/SwiftLint/issues/5573) diff --git a/bazel/repos.bzl b/bazel/repos.bzl index 93a8cce26a..ba4f937e22 100644 --- a/bazel/repos.bzl +++ b/bazel/repos.bzl @@ -17,6 +17,29 @@ def swiftlint_repos(bzlmod = False): url = "https://github.com/apple/swift-syntax/archive/refs/tags/510.0.2.tar.gz", ) + http_archive( + name = "sourcekitten_com_github_apple_swift_argument_parser", + url = "https://github.com/apple/swift-argument-parser/archive/refs/tags/1.3.1.tar.gz", + sha256 = "4d964f874b251abc280ee28f0f187de3c13a6122a9561524f66a10768ca2d837", + build_file = "@com_github_jpsim_sourcekitten//bazel:SwiftArgumentParser.BUILD", + strip_prefix = "swift-argument-parser-1.3.1", + ) + + http_archive( + name = "sourcekitten_com_github_jpsim_yams", + url = "https://github.com/jpsim/Yams/releases/download/5.0.6/Yams-5.0.6.tar.gz", + sha256 = "a81c6b93f5d26bae1b619b7f8babbfe7c8abacf95b85916961d488888df886fb", + strip_prefix = "Yams-5.0.6", + ) + + http_archive( + name = "sourcekitten_com_github_drmohundro_SWXMLHash", + url = "https://github.com/drmohundro/SWXMLHash/archive/refs/tags/7.0.1.tar.gz", + build_file = "@com_github_jpsim_sourcekitten//bazel:SWXMLHash.BUILD", + sha256 = "bafa037a09aa296f180e5613206748db5053b79aa09258c78d093ae9f8102a18", + strip_prefix = "SWXMLHash-7.0.1", + ) + http_archive( name = "swiftlint_com_github_scottrhoyt_swifty_text_table", sha256 = "b77d403db9f33686caeb2a12986997fb02a0819e029e669c6b9554617c4fd6ae", From dfe19ac7fca4d977c31b0035448e30fed2ce65ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 15 May 2024 23:06:59 +0200 Subject: [PATCH 060/265] Respect comments before opening braces in `opening_brace` rule (#5582) --- CHANGELOG.md | 6 +++++ .../Rules/Style/OpeningBraceRule.swift | 22 ++++++++++++++++--- .../Style/OpeningBraceRuleExamples.swift | 20 ++++++++++++++--- .../Extensions/SwiftSyntax+SwiftLint.swift | 6 +++++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e40d27817..ef970ac1c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,12 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5571](https://github.com/realm/SwiftLint/issues/5571) +* Respect comments before opening brace in `opening_brace` rule when there is + one space before the brace after the comment. Everything else is still a + violation, yet the rewriter will not remove the comment anymore. + [SimplyDanny](https://github.com/SimplyDanny) + [#5578](https://github.com/realm/SwiftLint/issues/5578) + ## 0.55.0: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index 92e90eeedc..ba36909ea8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -225,16 +225,32 @@ private extension BracedSyntax { func violationCorrection(_ locationConverter: SourceLocationConverter) -> ViolationCorrection? { if let previousToken = leftBrace.previousToken(viewMode: .sourceAccurate) { + let triviaBetween = previousToken.trailingTrivia + leftBrace.leadingTrivia let previousLocation = previousToken.endLocation(converter: locationConverter) let leftBraceLocation = leftBrace.startLocation(converter: locationConverter) - if previousLocation.line != leftBraceLocation.line - || previousLocation.column + 1 != leftBraceLocation.column { + let violation = ViolationCorrection( + start: previousToken.endPositionBeforeTrailingTrivia, + end: leftBrace.positionAfterSkippingLeadingTrivia, + replacement: " " + ) + if previousLocation.line != leftBraceLocation.line { + return violation + } + if previousLocation.column + 1 == leftBraceLocation.column { + return nil + } + if triviaBetween.containsComments { + if triviaBetween.pieces.last == .spaces(1) { + return nil + } + let comment = triviaBetween.description.trimmingTrailingCharacters(in: .whitespaces) return ViolationCorrection( - start: previousToken.endPositionBeforeTrailingTrivia, + start: previousToken.endPositionBeforeTrailingTrivia + SourceLength(of: comment), end: leftBrace.positionAfterSkippingLeadingTrivia, replacement: " " ) } + return violation } return nil } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index 73b50146bc..a855aac2cb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -52,7 +52,12 @@ struct OpeningBraceRuleExamples { Example(""" if c {} else {} - """) + """), + Example(""" + if c /* comment */ { + return + } + """) ] static let triggeringExamples = [ @@ -210,7 +215,7 @@ struct OpeningBraceRuleExamples { """), Example(""" if c ↓{} - else ↓{} + else /* comment */ ↓{} """) ] @@ -531,6 +536,15 @@ struct OpeningBraceRuleExamples { precedencegroup Group { assignment: true } - """) + """), + Example(""" + if c /* comment */ { + return + } + """): Example(""" + if c /* comment */ { + return + } + """) ] } diff --git a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift index c00399fc60..326c5fa439 100644 --- a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift @@ -254,6 +254,12 @@ public extension Trivia { } } + var containsComments: Bool { + isNotEmpty && contains { piece in + !piece.isWhitespace && !piece.isNewline + } + } + var isSingleSpace: Bool { self == .spaces(1) } From 7ec22383647a53caf91c50ca8567cf4619ec91dc Mon Sep 17 00:00:00 2001 From: "Garric G. Nahapetian" Date: Wed, 15 May 2024 14:09:55 -0700 Subject: [PATCH 061/265] Improve README.md (#5543) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch Co-authored-by: Christopher Fuller --- README.md | 506 ++++++++++++++++++----------- assets/runscript.png | Bin 59733 -> 0 bytes assets/select-swiftlint-plugin.png | Bin 19530 -> 0 bytes 3 files changed, 312 insertions(+), 194 deletions(-) delete mode 100644 assets/runscript.png delete mode 100644 assets/select-swiftlint-plugin.png diff --git a/README.md b/README.md index 3abca7de11..5c1f5a68d5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # SwiftLint -A tool to enforce Swift style and conventions, loosely based on the now archived [GitHub Swift Style Guide](https://github.com/github/swift-style-guide). SwiftLint enforces the style guide rules that are generally accepted by the Swift community. These rules are well described in popular style guides like [Kodeco's Swift Style Guide](https://github.com/kodecocodes/swift-style-guide). +A tool to enforce Swift style and conventions, loosely based on the now +archived [GitHub Swift Style Guide](https://github.com/github/swift-style-guide). +SwiftLint enforces the style guide rules that are generally accepted by the +Swift community. These rules are well described in popular style guides like +[Kodeco's Swift Style Guide](https://github.com/kodecocodes/swift-style-guide). SwiftLint hooks into [Clang](http://clang.llvm.org) and [SourceKit](http://www.jpsim.com/uncovering-sourcekit) to use the @@ -12,67 +16,92 @@ of your source files for more accurate results. ![](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/screenshot.png) -This project adheres to the [Contributor Covenant Code of Conduct](https://realm.io/conduct). +This project adheres to the +[Contributor Covenant Code of Conduct](https://realm.io/conduct). By participating, you are expected to uphold this code. Please report unacceptable behavior to [info@realm.io](mailto:info@realm.io). -> Language Switch: [中文](https://github.com/realm/SwiftLint/blob/main/README_CN.md), [한국어](https://github.com/realm/SwiftLint/blob/main/README_KR.md). +> Switch Language: +> [中文](https://github.com/realm/SwiftLint/blob/main/README_CN.md) +> [한국어](https://github.com/realm/SwiftLint/blob/main/README_KR.md) + +## Video Introduction + +To get a high-level overview of SwiftLint, we encourage you to watch this +presentation recorded January 9th, 2017 by JP Simard (transcript provided): + +[![Presentation](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/presentation.svg)](https://youtu.be/9Z1nTMTejqU) ## Installation -### Using [Swift Package Manager](https://github.com/apple/swift-package-manager): +### [Swift Package Manager](https://github.com/apple/swift-package-manager) -> Replace `` with the desired minimum version. +SwiftLint can be used as a [command plugin](#swift-package-command-plugin) +or a [build tool plugin](#swift-package-build-tool-plugins). + +Add ```swift .package(url: "https://github.com/realm/SwiftLint.git", from: "") ``` -SwiftLint can be used as a [command plugin](#swift-package-command-plugin) or a [build tool plugin](#swift-package-build-tool-plugins). +to your `Package.swift` file to consume the latest release of SwiftLint +automatically or pin the dependency to a specific version: + +```swift +.package(url: "https://github.com/realm/SwiftLint.git", exact: "") +``` + +> [!NOTE] +> Replace `` with the desired minimum or exact version. -### Using [Homebrew](http://brew.sh/): +### [Xcode Package Dependency](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) + +Use the following link to add SwiftLint as a Package Dependency to an Xcode +project: + +``` +https://github.com/realm/SwiftLint +``` + +> [!IMPORTANT] +> Do not add the `SwiftLintFramework` library or the +> `swiftlint` executable to any targets. Ensure `None` +> is selected when asked to choose package products. + +### [Homebrew](http://brew.sh) ``` brew install swiftlint ``` -### Using [CocoaPods](https://cocoapods.org): +### [CocoaPods](https://cocoapods.org) -Simply add the following line to your Podfile: +Add the following to your `Podfile`: ```ruby pod 'SwiftLint' ``` -This will download the SwiftLint binaries and dependencies in `Pods/` during your next -`pod install` execution and will allow you to invoke it via `${PODS_ROOT}/SwiftLint/swiftlint` -in your Script Build Phases. +This will download the SwiftLint binaries and dependencies in `Pods/` during +your next `pod install` execution and will allow you to invoke it via +`${PODS_ROOT}/SwiftLint/swiftlint` in your Script Build Phases. -This is the recommended way to install a specific version of SwiftLint since it supports -installing a pinned version rather than simply the latest (which is the case with Homebrew). +Installing via Cocoapods also enables pinning to a specific version of +SwiftLint rather than simply the latest (which is the case with +[Homebrew](#homebrew)). -Note that this will add the SwiftLint binaries, its dependencies' binaries, and the Swift binary -library distribution to the `Pods/` directory, so checking in this directory to SCM such as -git is discouraged. +Note that this will add the SwiftLint binaries, its dependencies' binaries, and +the Swift binary library distribution to the `Pods/` directory, so checking in +this directory to SCM such as Git is discouraged. -### Using [Mint](https://github.com/yonaskolb/mint): +### [Mint](https://github.com/yonaskolb/mint) ``` $ mint install realm/SwiftLint ``` -### Using a pre-built package: - -You can also install SwiftLint by downloading `SwiftLint.pkg` from the -[latest GitHub release](https://github.com/realm/SwiftLint/releases/latest) and -running it. - -### Installing from source: - -You can also build and install from source by cloning this project and running -`make install` (Xcode 15.0 or later). - -### Using Bazel +### [Bazel](https://bazel.build) Put this in your `MODULE.bazel`: @@ -139,162 +168,231 @@ Then you can run SwiftLint in the current directory with this command: bazel run -c opt @SwiftLint//:swiftlint ``` -## Usage +### Pre-Built Package -### Presentation +Download `SwiftLint.pkg` from the +[latest GitHub release](https://github.com/realm/SwiftLint/releases/latest) and +run it. -To get a high-level overview of recommended ways to integrate SwiftLint into your project, -we encourage you to watch this presentation or read the transcript: +### From Source -[![Presentation](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/presentation.svg)](https://youtu.be/9Z1nTMTejqU) +Make sure the build tool [Bazel](https://bazel.build) and a +recent [Swift toolchain](https://www.swift.org/download/) are +installed and all tools are discoverable in your `PATH`. -### Xcode Run Script Build Phase +To build SwiftLint, clone this repository and run `make install`. -Integrate SwiftLint into your Xcode project to get warnings and errors displayed -in the issue navigator. +## Setup -To do this select the project in the file navigator, then select the primary app -target, and go to Build Phases. Click the + and select "New Run Script Phase". -Insert the following as the script: +> [!IMPORTANT] +> While it may seem intuitive to run SwiftLint before compiling Swift source +> files to exit a build early when there are lint violations, it is important +> to understand that SwiftLint is designed to analyze valid source code that +> is compilable. Non-compiling code can very easily lead to unexpected and +> confusing results, especially when executing with `--fix`/`--autocorrect` +> command line arguments. -![](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/runscript.png) +### Swift Package Command Plugin -Xcode 15 made a significant change by setting the default value of the `ENABLE_USER_SCRIPT_SANDBOXING` Build Setting from `NO` to `YES`. -As a result, SwiftLint encounters an error related to missing file permissions, -which typically manifests as follows: `error: Sandbox: swiftlint(19427) deny(1) file-read-data.` +> [!NOTE] +> Requires installing via [Swift Package Manager](#swift-package-manager). -To resolve this issue, it is necessary to manually set the `ENABLE_USER_SCRIPT_SANDBOXING` setting to `NO` for the specific target that SwiftLint is being configured for. +The command plugin enables running SwiftLint from the command line as follows: -If you installed SwiftLint via Homebrew on Apple Silicon, you might experience this warning: +```shell +swift package plugin swiftlint +``` -> warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint +### Swift Package Build Tool Plugins -That is because Homebrew on Apple Silicon installs the binaries into the `/opt/homebrew/bin` -folder by default. To instruct Xcode where to find SwiftLint, you can either add -`/opt/homebrew/bin` to the `PATH` environment variable in your build phase +SwiftLint can be used as a build tool plugin for both +[Swift Package projects](#swift-package-projects) +and [Xcode projects](#xcode-projects). -```bash -if [[ "$(uname -m)" == arm64 ]]; then - export PATH="/opt/homebrew/bin:$PATH" -fi +The build tool plugin determines the SwiftLint working directory by locating +the topmost config file within the package/project directory. If a config file +is not found therein, the package/project directory is used as the working +directory. -if which swiftlint > /dev/null; then - swiftlint -else - echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" -fi -``` +The plugin throws an error when it is unable to resolve the SwiftLint working +directory. For example, this will occur in Xcode projects where the target's +Swift files are not located within the project directory. -or you can create a symbolic link in `/usr/local/bin` pointing to the actual binary: +To maximize compatibility with the plugin, avoid project structures that require +the use of the `--config` option. -```bash -ln -s /opt/homebrew/bin/swiftlint /usr/local/bin/swiftlint -``` +### Swift Package Projects -You might want to move your SwiftLint phase directly before the 'Compile Sources' -step to detect errors quickly before compiling. However, SwiftLint is designed -to run on valid Swift code that cleanly completes the compiler's parsing stage. -So running SwiftLint before 'Compile Sources' might yield some incorrect -results. +> [!NOTE] +> Requires installing via [Swift Package Manager](#swift-package-manager). -If you wish to fix violations as well, your script could run -`swiftlint --fix && swiftlint` instead of just `swiftlint`. This will mean -that all correctable violations are fixed while ensuring warnings show up in -your project for remaining violations. +Build tool plugins run when building each target. When a project has multiple +targets, the plugin must be added to the desired targets individually. -If you've installed SwiftLint via CocoaPods the script should look like this: +To do this, add the plugin to the target(s) to be linted as follows: -```bash -"${PODS_ROOT}/SwiftLint/swiftlint" +```swift +.target( + ... + plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLint")] +), ``` -### Swift Package Command Plugin +### Xcode Projects -The command plugin enables running SwiftLint from the command line as follows: +> [!NOTE] +> Requires installing via [Xcode Package Dependency](#xcode-package-dependency). -```shell -swift package plugin swiftlint -``` +Build tool plugins run as a build phase of each target. When a project has +multiple targets, the plugin must be added to the desired targets individually. -### Swift Package Build Tool Plugins +To do this, add the `SwiftLintBuildToolPlugin` to the `Run Build Tool Plug-ins` +phase of the `Build Phases` for the target(s) to be linted. -SwiftLint can be used as a build tool plugin for both [Xcode projects](#xcode-projects) and -[Swift Package projects](#swift-package-projects). +> [!TIP] +> When using the plugin for the first time, be sure to trust and enable +> it when prompted. If a macros build warning exists, select it to trust +> and enable the macros as well. -The build tool plugin determines the SwiftLint working directory by locating -the topmost config file within the package/project directory. If a config file -is not found therein, the package/project directory is used as the working -directory. +For unattended use (e.g. on CI), package plugin and macro +validations can be disabled with either of the following: -The plugin throws an error when it is unable to resolve the SwiftLint working -directory. For example, this will occur in Xcode projects where the target's -Swift files are not located within the project directory. +* Using `xcodebuild` options: + ``` + -skipPackagePluginValidation + -skipMacroValidation + ``` +* Setting Xcode defaults: + ``` + defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidation -bool YES + defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES + ``` -To maximize compatibility with the plugin, avoid project structures that require -the use of the `--config` option. +> [!IMPORTANT] +> The unattended use options bypass Xcode's validation dialogs +> and implicitly trust all plugins and macros, which has security implications. -#### Unexpected Project Structures +#### Unexpected Xcode Project Structures -Project structures where SwiftLint's configuration file is located -outside of the package/project directory are not directly supported -by the build tool plugin. This is because it isn't possible to pass -arguments to build tool plugins (e.g., passing the config file path). +Project structures where SwiftLint's configuration file is located +outside of the package/project directory are not directly supported +by the build tool plugin. This is because it isn't possible to pass +arguments to build tool plugins (e.g., passing the config file path). -If your project structure doesn't work directly with the build tool +If your project structure doesn't work directly with the build tool plugin, please consider one of the following options: -- To use a config file located outside the package/project directory, a config - file may be added to that directory specifying a parent config path to the +- To use a config file located outside the package/project directory, a config + file may be added to that directory specifying a parent config path to the other config file, e.g., `parent_config: path/to/.swiftlint.yml`. -- You can also consider the use of a Run Script Build Phase in place of the - build tool plugin. +- You can also consider the use of a + [Run Script Build Phase](#xcode-run-script-build-phase) in place of the build + tool plugin. -#### Xcode Projects +### Xcode Run Script Build Phase -You can integrate SwiftLint as an Xcode Build Tool Plugin if you're working -with a project in Xcode. +If the build tool plugin does not work for your project setup or when +additional custom setup is required, SwiftLint can be added as a Run Script +Build Phase. This is useful when a project setup relies on the `--config` +SwiftLint option; or to lint all targets together in a single `swiftlint` +invocation. File inclusions and exclusions can be configured in the +[`.swiftlint.yml` configuration](#configuration). -Add SwiftLint as a package dependency to your project without linking any of the -products. +To do this, add a custom script to a `Run Script` phase of the `Build Phases` +of the primary app target, after the `Compile Sources` phase. Use the +following script implementation: -Select the target you want to add linting to and open the `Build Phases` inspector. -Open `Run Build Tool Plugins` and select the `+` button. -Select `SwiftLintBuildToolPlugin` from the list and add it to the project. +``` +if command -v swiftlint >/dev/null 2>&1 +then + swiftlint +else + echo "warning: `swiftlint` command not found - See https://github.com/realm/SwiftLint#installation for installation instructions." +fi +``` -![](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/select-swiftlint-plugin.png) +
-For unattended use (e.g. on CI), you can disable the package and macro validation dialog by +> [!TIP] +> Uncheck `Based on dependency analysis` to run `swiftlint` on all incremental +> builds, suppressing the unspecified outputs warning. -* individually passing `-skipPackagePluginValidation` and `-skipMacroValidation` to `xcodebuild` or -* globally setting `defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES` and `defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES` - for that user. +> [!NOTE] +> Based upon the installation method used, the shell command syntax in the +> Run Script Build Phase may be different or additional configuration could +> be required. Refer to the [installation](#installation) instructions for +> more information. -_Note: This implicitly trusts all Xcode package plugins and macros in packages and bypasses Xcode's package validation - dialogs, which has security implications._ +**Consideration for Xcode 15.0+** -#### Swift Package Projects +Xcode 15 made a significant change by setting the default value of the +`ENABLE_USER_SCRIPT_SANDBOXING` build setting from `NO` to `YES`. +As a result, SwiftLint encounters an error related to missing file permissions, +which typically manifests as +`error: Sandbox: swiftlint(19427) deny(1) file-read-data.` -You can integrate SwiftLint as a Swift Package Manager Plugin if you're working with -a Swift Package with a `Package.swift` manifest. +To resolve this issue, it is necessary to manually set the +`ENABLE_USER_SCRIPT_SANDBOXING` setting to `NO` for the specific target that +SwiftLint is being configured for. -Add SwiftLint as a package dependency to your `Package.swift` file. -Add SwiftLint to a target using the `plugins` parameter. +**Consideration for Apple Silicon** -```swift -.target( - ... - plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLint")] -), +If you installed SwiftLint via Homebrew on Apple Silicon, you might experience +this warning: + +> warning: SwiftLint not installed, download from +> https://github.com/realm/SwiftLint + +That is because Homebrew on Apple Silicon installs the binaries into the +`/opt/homebrew/bin` folder by default. To instruct Xcode where to find +SwiftLint, you can either add `/opt/homebrew/bin` to the `PATH` environment +variable in your build phase: + +```bash +if [[ "$(uname -m)" == arm64 ]] +then + export PATH="/opt/homebrew/bin:$PATH" +fi + +if command -v swiftlint >/dev/null 2>&1 +then + swiftlint +else + echo "warning: `swiftlint` command not found - See https://github.com/realm/SwiftLint#installation for installation instructions." +fi +``` + +or you can create a symbolic link in `/usr/local/bin` pointing to the actual +binary: + +```bash +ln -s /opt/homebrew/bin/swiftlint /usr/local/bin/swiftlint +``` + +**Additional Considerations** + +If you wish to fix violations as well, your script could run +`swiftlint --fix && swiftlint` instead of just `swiftlint`. This will mean +that all correctable violations are fixed while ensuring warnings show up in +your project for remaining violations. + +If you've installed SwiftLint via CocoaPods the script should look like this: + +```bash +"${PODS_ROOT}/SwiftLint/swiftlint" ``` ### Visual Studio Code -To integrate SwiftLint with [vscode](https://code.visualstudio.com), install the -[`vscode-swiftlint`](https://marketplace.visualstudio.com/items?itemName=vknabel.vscode-swiftlint) extension from the marketplace. +To integrate SwiftLint with [Visual Studio Code](https://code.visualstudio.com), install the +[`vscode-swiftlint`](https://marketplace.visualstudio.com/items?itemName=vknabel.vscode-swiftlint) +extension from the marketplace. -### fastlane +### Fastlane -You can use the [official swiftlint fastlane action](https://docs.fastlane.tools/actions/swiftlint) to run SwiftLint as part of your fastlane process. +You can use the official +[`swiftlint` fastlane action](https://docs.fastlane.tools/actions/swiftlint) +to run SwiftLint as part of your fastlane process. ```ruby swiftlint( @@ -316,8 +414,9 @@ swiftlint( ### Docker -`swiftlint` is also available as a [Docker](https://www.docker.com/) image using `Ubuntu`. -So just the first time you need to pull the docker image using the next command: +SwiftLint is also available as a [Docker](https://www.docker.com/) image using +`Ubuntu`. So just the first time you need to pull the docker image using the +next command: ```bash docker pull ghcr.io/realm/swiftlint:latest ``` @@ -327,7 +426,8 @@ Then following times, you just run `swiftlint` inside of the docker like: docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest ``` -This will execute `swiftlint` in the folder where you are right now (`pwd`), showing an output like: +This will execute `swiftlint` in the folder where you are right now (`pwd`), +showing an output like: ```bash $ docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest Linting Swift files in current working directory @@ -337,9 +437,10 @@ Linting 'YamlSwiftLintTests.swift' (490/490) Done linting! Found 0 violations, 0 serious in 490 files. ``` -Here you have more documentation about the usage of [Docker Images](https://docs.docker.com/). +Here you have more documentation about the usage of +[Docker Images](https://docs.docker.com/). -### Command Line +## Command Line Usage ``` $ swiftlint help @@ -371,13 +472,14 @@ To specify a list of files when using `lint` or `analyze` [`ExtraBuildPhase`](https://github.com/norio-nomura/ExtraBuildPhase) Xcode plugin, or modified files in the working tree based on `git ls-files -m`), you can do so by passing the option `--use-script-input-files` and setting the -following instance variables: `SCRIPT_INPUT_FILE_COUNT` and -`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`...`SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT - 1}`. +following instance variables: `SCRIPT_INPUT_FILE_COUNT` +and `SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`, ..., +`SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT - 1}`. These are same environment variables set for input files to [custom Xcode script phases](http://indiestack.com/2014/12/speeding-up-custom-script-phases/). -### Working With Multiple Swift Versions +## Working With Multiple Swift Versions SwiftLint hooks into SourceKit so it continues working even as Swift evolves! @@ -415,7 +517,7 @@ On Linux, SourceKit is expected to be located in `/usr/lib/libsourcekitdInProc.so` or specified by the `LINUX_SOURCEKIT_LIB_PATH` environment variable. -### pre-commit +## Git `pre-commit` Hook SwiftLint can be run as a [pre-commit](https://pre-commit.com/) hook. Once [installed](https://pre-commit.com/#install), add this to the @@ -429,7 +531,8 @@ repos: - id: swiftlint ``` -Adjust `rev` to the SwiftLint version of your choice. `pre-commit autoupdate` can be used to update to the current version. +Adjust `rev` to the SwiftLint version of your choice. `pre-commit autoupdate` +can be used to update to the current version. SwiftLint can be configured using `entry` to apply fixes and fail on errors: ```yaml @@ -444,12 +547,14 @@ SwiftLint can be configured using `entry` to apply fixes and fail on errors: Over 200 rules are included in SwiftLint and the Swift community (that's you!) continues to contribute more over time. -[Pull requests](https://github.com/realm/SwiftLint/blob/main/CONTRIBUTING.md) are encouraged. +[Pull requests](https://github.com/realm/SwiftLint/blob/main/CONTRIBUTING.md) +are encouraged. You can find an updated list of rules and more information about them [here](https://realm.github.io/SwiftLint/rule-directory.html). -You can also check [Source/SwiftLintBuiltInRules/Rules](https://github.com/realm/SwiftLint/tree/main/Source/SwiftLintBuiltInRules/Rules) +You can also check the +[Source/SwiftLintBuiltInRules/Rules](https://github.com/realm/SwiftLint/tree/main/Source/SwiftLintBuiltInRules/Rules) directory to see their implementation. ### Opt-In Rules @@ -485,7 +590,8 @@ let noWarning :String = "" // No warning about colons immediately after variable let hasWarning :String = "" // Warning generated about colons immediately after variable names ``` -Including the `all` keyword will disable all rules until the linter sees a matching enable comment: +Including the `all` keyword will disable all rules until the linter sees a +matching enable comment: `// swiftlint:disable all` `// swiftlint:enable all` @@ -632,9 +738,9 @@ following syntax: ```yaml custom_rules: pirates_beat_ninjas: # rule identifier - included: + included: - ".*\\.swift" # regex that defines paths to include during linting. optional. - excluded: + excluded: - ".*Test\\.swift" # regex that defines paths to exclude during linting. optional name: "Pirates Beat Ninjas" # rule name. optional. regex: "([nN]inja)" # matching pattern @@ -653,12 +759,13 @@ This is what the output would look like: ![](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/custom-rule.png) -It is important to note that the regular expression pattern is used with the flags `s` -and `m` enabled, that is `.` +It is important to note that the regular expression pattern is used with the +flags `s` and `m` enabled, that is `.` [matches newlines](https://developer.apple.com/documentation/foundation/nsregularexpression/options/1412529-dotmatcheslineseparators) -and `^`/`$` +and `^`/`$` [match the start and end of lines](https://developer.apple.com/documentation/foundation/nsregularexpression/options/1408263-anchorsmatchlines), -respectively. If you do not want to have `.` match newlines, for example, the regex can be prepended by `(?-s)`. +respectively. If you do not want to have `.` match newlines, for example, the +regex can be prepended by `(?-s)`. You can filter the matches by providing one or more `match_kinds`, which will reject matches that include syntax kinds that are not present in this list. Here @@ -719,7 +826,7 @@ command invocation (incremental builds will fail) must be passed to `analyze` via the `--compiler-log-path` flag. e.g. `--compiler-log-path /path/to/xcodebuild.log` -This can be obtained by +This can be obtained by 1. Cleaning DerivedData (incremental builds won't work with analyze) 2. Running `xcodebuild -workspace {WORKSPACE}.xcworkspace -scheme {SCHEME} > xcodebuild.log` @@ -730,13 +837,14 @@ Analyzer rules tend to be considerably slower than lint rules. ## Using Multiple Configuration Files SwiftLint offers a variety of ways to include multiple configuration files. -Multiple configuration files get merged into one single configuration that is then applied -just as a single configuration file would get applied. +Multiple configuration files get merged into one single configuration that is +then applied just as a single configuration file would get applied. -There are quite a lot of use cases where using multiple configuration files could be helpful: +There are quite a lot of use cases where using multiple configuration files +could be helpful: -For instance, one could use a team-wide shared SwiftLint configuration while allowing overrides -in each project via a child configuration file. +For instance, one could use a team-wide shared SwiftLint configuration while +allowing overrides in each project via a child configuration file. Team-Wide Configuration: @@ -754,12 +862,14 @@ opt_in_rules: ### Child / Parent Configs (Locally) -You can specify a `child_config` and / or a `parent_config` reference within a configuration file. -These references should be local paths relative to the folder of the configuration file they are specified in. -This even works recursively, as long as there are no cycles and no ambiguities. +You can specify a `child_config` and / or a `parent_config` reference within a +configuration file. These references should be local paths relative to the +folder of the configuration file they are specified in. This even works +recursively, as long as there are no cycles and no ambiguities. -**A child config is treated as a refinement and therefore has a higher priority**, -while a parent config is considered a base with lower priority in case of conflicts. +**A child config is treated as a refinement and thus has a higher priority**, +while a parent config is considered a base with lower priority in case of +conflicts. Here's an example, assuming you have the following file structure: @@ -771,7 +881,8 @@ ProjectRoot |_ .swiftlint_base.yml ``` -To include both the refinement and the base file, your `.swiftlint.yml` should look like this: +To include both the refinement and the base file, your `.swiftlint.yml` should +look like this: ```yaml child_config: .swiftlint_refinement.yml @@ -784,9 +895,10 @@ of the containing configuration files. ### Child / Parent Configs (Remote) -Just as you can provide local `child_config` / `parent_config` references, instead of -referencing local paths, you can just put urls that lead to configuration files. -In order for SwiftLint to detect these remote references, they must start with `http://` or `https://`. +Just as you can provide local `child_config` / `parent_config` references, +instead of referencing local paths, you can just put urls that lead to +configuration files. In order for SwiftLint to detect these remote references, +they must start with `http://` or `https://`. The referenced remote configuration files may even recursively reference other remote configuration files, but aren't allowed to include local references. @@ -797,20 +909,23 @@ Using a remote reference, your `.swiftlint.yml` could look like this: parent_config: https://myteamserver.com/our-base-swiftlint-config.yml ``` -Every time you run SwiftLint and have an Internet connection, SwiftLint tries to get a new version of -every remote configuration that is referenced. If this request times out, a cached version is -used if available. If there is no cached version available, SwiftLint fails – but no worries, a cached version -should be there once SwiftLint has run successfully at least once. +Every time you run SwiftLint and have an Internet connection, SwiftLint tries +to get a new version of every remote configuration that is referenced. If this +request times out, a cached version is used if available. If there is no cached +version available, SwiftLint fails – but no worries, a cached version should be +there once SwiftLint has run successfully at least once. -If needed, the timeouts for the remote configuration fetching can be specified manually via the -configuration file(s) using the `remote_timeout` / `remote_timeout_if_cached` specifiers. -These values default to 2 / 1 second(s). +If needed, the timeouts for the remote configuration fetching can be specified +manually via the configuration file(s) using the +`remote_timeout` / `remote_timeout_if_cached` specifiers. These values default +to 2 / 1 second(s). ### Command Line -Instead of just providing one configuration file when running SwiftLint via the command line, -you can also pass a hierarchy, where the first configuration is treated as a parent, -while the last one is treated as the highest-priority child. +Instead of just providing one configuration file when running SwiftLint via the +command line, you can also pass a hierarchy, where the first configuration is +treated as a parent, while the last one is treated as the highest-priority +child. A simple example including just two configuration files looks like this: @@ -818,23 +933,26 @@ A simple example including just two configuration files looks like this: ### Nested Configurations -In addition to a main configuration (the `.swiftlint.yml` file in the root folder), -you can put other configuration files named `.swiftlint.yml` into the directory structure -that then get merged as a child config, but only with an effect for those files -that are within the same directory as the config or in a deeper directory where -there isn't another configuration file. In other words: Nested configurations don't work -recursively – there's a maximum number of one nested configuration per file -that may be applied in addition to the main configuration. - -`.swiftlint.yml` files are only considered as a nested configuration if they have not been -used to build the main configuration already (e. g. by having been referenced via something -like `child_config: Folder/.swiftlint.yml`). Also, `parent_config` / `child_config` -specifications of nested configurations are getting ignored because there's no sense to that. - -If one (or more) SwiftLint file(s) are explicitly specified via the `--config` parameter, -that configuration will be treated as an override, no matter whether there exist -other `.swiftlint.yml` files somewhere within the directory. **So if you want to use - nested configurations, you can't use the `--config` parameter.** +In addition to a main configuration (the `.swiftlint.yml` file in the root +folder), you can put other configuration files named `.swiftlint.yml` into the +directory structure that then get merged as a child config, but only with an +effect for those files that are within the same directory as the config or in a +deeper directory where there isn't another configuration file. In other words: +Nested configurations don't work recursively – there's a maximum number of one +nested configuration per file that may be applied in addition to the main +configuration. + +`.swiftlint.yml` files are only considered as a nested configuration if they +have not been used to build the main configuration already (e. g. by having +been referenced via something like `child_config: Folder/.swiftlint.yml`). +Also, `parent_config` / `child_config` specifications of nested configurations +are getting ignored because there's no sense to that. + +If one (or more) SwiftLint file(s) are explicitly specified via the `--config` +parameter, that configuration will be treated as an override, no matter whether +there exist other `.swiftlint.yml` files somewhere within the directory. +**So if you want to use nested configurations, you can't use the `--config` +parameter.** ## License diff --git a/assets/runscript.png b/assets/runscript.png deleted file mode 100644 index 12c35c867d520751e04aeb721e9406fa1b80fea4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59733 zcmd?Qgg-MfA{7PEJ!vPL5I2)7{R|#TEb z_~T`VG|y$lXYiC5bH0<|J@I+1)dh*U!`1x6+JunNS^hp@j3tUzUN;d?^Y%`Xh!U0= zIti7DN|y*8&hT23K@86iVr8#&lgD^z0WDp3V#D(G57cK8q3F$tVe%o{ z3uk`U_+o2-@{J$a03&@;x&)=Q(39`_8;dTb#E83B^n?wvu1Dq`hI|!mJL<$^%cuxR~+0TqbDvN$AI->XhXcY)8NDY>y@f444@s+doC)%;&5LvUwy<8&P9^88YO0+N~0Yx5Tq1=2jn2wrn{k-}W*?pncED62+ zV(HH>c;xQUl+|~6dmcpXcW*U4>M<23JEz9`{Vl28kY7ed%=6vtc!o#0D{uEsa>Jjy zJuo#3sR?T@_?_|PInYHwhW)9&k^Poskk$N0)D-sD&O|^by}d_oFUP43=y&KBKUR@P zxCxASIJc=jb|;e*hCXF<*{(!Jb|kXoyuJOHkzzMwA=~Z;ixMAm=!mE$&Qz zo%0fDMQ{2;99I~h?26V5XY2Htgc$XhCduM&@~nGv`0@B6c>LXTAMvs{a*2%9$f;C< zEQhg|-x4Vh(hc&^^={GBc5yR08%UC&LoS$nGoq2VBxJLP;9jVz?Wej;ZAOjZqEta7A?^IS%HFjG>KI9T{Q@5ym2+I15 zt0_DsTkmCY=y#90)DXDMK8t(vqc^8FXJF|-#tuQm|B(YO!tqOk_oMr}?2_LP?^zXQ zzoo?L_z_5D@*Tp^&QH1M8t%W5&Vv%f%Cgl=Jyq-DyYp*C2kQZ7 z(Yw(7*Re54XS8sou6FU{(mw93E9c^_%p5|Z5YFmQF|k`BzlblM<2@kEeJ=Ux)@Q4! zJB-w|S$FM1PP6YPhOJr>&tNsY-L@2&!6gY1fAc8g7NW~`^sd`m;2T%((3EW4!;m1H z=dbXHtr(l%kz2>jFsr}A{T&m|nDFZ9r_g++)OUCZ%yl2{yb`OuH~ZE_t~9|S!RE)q z73T4{`RDXZWJkdca*vJ`=lMEzj$60)f>UG{@yP&zkLv?lBbHD+Ga(BgavOT8Y$DhC}2q)-P@7C%T z`|2x>4|>U*pj7|3`CD7+i$Uh$$2?4K%=C;|Yz-6=@7f;UQ%ZTQvd<*{Su`J8o6}Ls zk$2<%#*>oIhau(4!pss0az9I6lQ(@aeGZqCR%%xcQrI!jGT<}V(~j0(DjC!?Dy)?& zc)t2xxkyTlH;5c!GY#<*VEHe)0NWeDRR0OM3#FGf!HvP5bi88TXMnab#qkLcKy|@4Z+l z8fu{|=TCy%f^vfXX{>25p%EvaXU`%zS>AQoKDFGk%&_rxB8NPM%orOPuNt4%8$$x> zg&=126p$ik11IokG9O>zozFvqRy;QJ*6`OsG*-`;EpdXs|0X|IG^N`!x6hC3Ah9S? zMZ6s*&eUjrx;BSqV`7cg-sjLe)s(w7L010Vaop8X-mg4)bG6F#ds z6F6!_Hm;*-9?*n8d`AqW%@A4_eob>mYxl5HSkiIE_WQGap?fqH!s51vp#?((maEm! znlwYH-m~7NUhQSq-iqE!wq!PZwjMTIRr)X5s#2-~ss`!8X~$n4rp5}S+v?l+Oq=%1 ze>1gghqlgMv_%xif9iP=BOZfD7Eg8=U>=|uIM)~Ck|~ocds2pkzH}xXe|2tsE`Dy1H>6M$ zXU^B`e`tVf5cMdEjs*Qkh^|kZN zS`r@yGL3Hd+qh!6LwPdoN>F#5{y8**Tk~^nk14Ct<$dA(& za3AzIuWTQ<<-R#`u()ykv{Rgs z%hJ8GOg2hZ>DO2%`nmb@x-fNIn=Y#^+pY?xG$wo|+86YZY2kK}(D38%rpO^82|9JW zcsvX8pcvQAwc4^-DVv49VS3p8=dtf%X2|wL$Jw;+%|0Wc6Y-fZ^+4wh=DpMcj4`Is zwLLj|{=rt&e9(P4dfBGeATF2&`9OlJK`f43gw;*M)FROGqV@!cua7?--un{rJvw?S z8udB!vp(C;Pm1g#>g^f1Da@)R8mt9ug*&R-nPmJ{L*c{Gl@u!M@Ql}Dj%WEXpO4rO zs?vP&t_1e|OM)+qwdb~Hw=Q=y*TU|%K$8Hi{lk$o8RXd3+gaEeqt`e>a9AkQgul_te5Q5bfb*aZac#b( z*;;$D5So97nDs8}fwFiI!FfqxqWKffHpnP&DOvu6c_|m#GaNI`du80q)uOwjX|8qU zkMH}l08AHbjy~ud|4>jdFrVydu5QX>9OM{$ZBiV*5M$Z_^%$@W4-kDBLHehOW}l?tC-a?W+^| zOHdfByJ1S-NLSB=-Hmtt%3JYw+?s`CPzk)Gu`UpiVwP)GyHL}TUb;|LhF(V*>4!mI zIX54x&%+vc{VXnnS}tKE&qxy)aBvH7EiTfIkwbFiQ8c8$NATe97e9LQKIGX#UTuGv z%MyQ{SuS1BemOH^6H5#yRt&DYcAfTEUQS}K*LW(SBxdC4`Ac`K1U~V5V!@t L6^ zvDH`jbnB>aPptyMJZvV)5OC$)tRunCid(aiPLgIhO!j|L&XoDo%ZRTk~!fV@k)?jcws8~oG4+CoqeJ7O5w65)G} z8fww_YH=)k`MgK&GDY<3wv<`D-6q{3{(Vctz%P-e^DZxc+zQSluQ< zeI(vD!Uxj!WjFVr;KVlAcLPil>=tNywE4s0Dj0J3813Dj+)D3Pw^FeKGeeoeg^qg< zrMCvQk--+n&(Ys@;^`UEWmrK0P?>Fkje}-hs0B^CLSUQBM~P>QYp+D#=V9HYO-s1d znQn$Ps{L#B7JQk*d-YO<>D~TtvFtAyt5rHRrrnj=0fx8X{#Y-&1^Vq~2AK-G&4VuD z(745Q2XAN-FNo~fZJ$1A?IDvUB5D=FdOL~LN&T}^_PQ`6gja%bRst(ySO>+ zqC(tr(lf>oJLqHZEp1tsF*Z4_NQ|$5|K^pE7Zw&3>!0^6CGE$%7&juzQPb1MIEsvk;8w@oTmZYCJ=BKNzw-uwGtBaeLxStgBUlih)-+zjEnHm2g@phJC zHdNDOlympAWfbBOY#AQAI2)SuCZO&vpH7Z7q;y4C(#8 z-b4Su8w=NS6mi{SEr@)PBa=8qrN)|Eu)mN~Flte+)Z#*WT4zK%keqr+&NQh!&K&&d z{yuv@SUz>(aG~(S;A^{~g|?1^reJBbmkb)7D&c$A_pmu$aqR$=F(NiH(l%iO_gc%i zU*#W7jg80n7VCzOPEP7qOx04WBX95COn`+geGA(Jj`t7sWk2DO&9MCp%YOI|1Xv;5 zs9QK>vRF5KFe>5TxqM!EK1%ct1aCW&(Kn6yPua)E*fPEmYEkBON3UU1;iI*1g4`U;n*{8p8!kCsny?om# ztVEA9^iKqMF8-wd#0n*5S^Vlpl}EduKcsjbAp^*sx@7ldMh&&3~wn__!K? z)F+=wetak;PEF)8F+Sd|*j89}Bl3@*xUgX>epE_h1lX{AKO#Zw8)Wtu@QJMD zxfE!(rdiFBRwZ)z#^y5oFk(;PZd$S;vGDfytdnt{&UwG^q{QsOw^VU;zBbvO;G=GF2TcksjKm5 z_gzXsp_I_+^uto}igp4~s!QpJ0N^}c+r^&m<|%BED^F|NbFpMFq@qYOqNjw-8R9|! zxj=V}U1-E_RFd0F2@M}_We6EA^pz)W9!-uz@}@XGi7f?DrZI{NP2qImPa1uxGySG8 zl0vgsfUn^rWi=waG^|B-0|dY7DHyAXf%&J#=#(0oFJk)ONIEp?kY37!Lg8@iPTVf< zb>4<}%hYY{C`a+ufb7keoCf4kxr^);6B1b!xX@RhMHrxR1}WD&wgfIx=R&Ri)NMJv zX$?zifb!2(56w)Re@i?5m?x&0-7au%Xl1 zwxyd~ny;$2i(NL1`gvx3B-hNS$#ZQ(F;jSc8mXK# zVkW@TT<2hzMU_^d-W%a3z%Oi37XX2Naka&FDUdpdM8;_qQXHM7kvC}QkK&oc!yg6a zMOI!YJhVx63T#wpux+J1l~A*UEilZu@rP_j2Q=(8L?Lfl#?*r`0^TXWGk-}v<&wOy zh(Ag3Y&fNU`#8OG1>nc2y3~Gv+#dIv#e- z^?b0@D~g^ID=1417Ov@Rz)pRkH=7q+z&GGqY9iNHy*{eP>W0zZAK#R2*tS9_FdGl8 z?1B^`#mQ$x#jYw0F4by0t#~1H{ah+--{!KbxgCv7IkK^1!Z`3SpI(5)#rb~Psr&U6 zDII6>usFM#OzS$ceCiprvNoXzNuZ|TC zoqC9YM2C4&f9ERmY%ATS&|OHc4o*5%Z-rC-daY|{fcI0WzCq?(&M@^FqNI~$szj&H zka~0U>d_@~o$t1u4&t&pfv1>4B0TodB`p?dAgADtn8k%kA5oywP(X9B*0*@j zvvq;Nae!LU8%kO=2}yyXlj_4J;S=>s@MR|;@>?bQ=ySq`j=~*-=CFRrI?EY~<|6~% zrplBolU5at*QPW+^X>7eTq2yF4gE~FVmr<`x;W3Uv=7yeNyzAQSZq6&kr87?ZxIX*QN4VSN6_Nk5gwv zf$@hdXlX8KzjlAlGa4b9{&KpsT|0dINXQ@$2&pfty$w5-6DmV=02bv6W38%sY3g=u z0nR%?4OY}OVK*59vh#mnC=GM}FdC0~fP@V^Xp;>NtZ(6YZ!@kf@e1(K0-6&xY*we> zyk+xn?u}nfCB&;u^0Gj~%(mUyf~>~lddn=JMuVdsg8KY8#PyK8Jf~AQS8n*WUFF;= z60G~JlTYG-E1z!q+8s=kWxh0sJGk;_*wfCVjw<$`-qnJmXNvRXLuWNnFDR;9?R^3vPdSgZExu925N98g=fr~ov`Lv)QU z-VJPL!MlJmYvT2Dt?@nBV&C>^tMi=&1VTK$*H2b#;oo|$bb6v1fr`F(aG7r{r^RO9 zofnI~3A(TEYPtJFUZ4F;4?`0tDZO?++MI&3D8?lkAO6a4kG+Zq$J&?7D4FeZIYujt#lA_HG7&|Hjj-Lt!kwuIJ!git$Pk$Eu20epO!$| zyZ#1ZS=-4?9S!H7#Jn2KC~0rpBoh@o``5}pRPwi}t6Dna#BH0b4ZXo>7~a)S0qn*N zn{NR6a(zBJ^$)=TgR6cs5@KYXcB=44qP~L?ExwG2ZNVYPfI8rbSqpLe)2n%D_eFM$ z>|3KgS#1Y~tUgoRrJ>Tdkf~meilDQ^OZpe4`=`d|Fg3C47BX>WGgE5Q*Gf zc6*dJY-d;@p7^@Gox(kv9uF1o^#wPvYcN!R6uA}y&FZdp-%A5hTDQnuuPr}S5~-$G zYUpJv)|dHx;sFeS&d0n3M0Rew|G;T5z8Iad3#qsa5QNkO@6{?&IV`ep>zO)mi>(D0 z6s|d$F4Mjqa)EUv8o4I%@t#Zne8&1>^3)krA*e%Af2<}pdU9nHaIh!b-XL);Rv%FA z7GPN@Hfio9V*9gPg$=kF(rc%TQ};C`9?HksJsOcd+2M~RscEz{{LpC@l)LhjLNw)I z?G1q5X^mw^P)nl7n|R10y+g~)WRd#IaCTMziNC3to9guSmx!g!mqrhV-BS4L{Sbaa z04Z37K)?oqqOqjsV^f;QkHLyg!ka-N(Cy_US9h_by}PNklLIF6To@dkL+kNTjq#`|xij5PO&Vnm$khb0 zBZGvq!8^#A$)KmlQW;*zIs1Z4fwPkH??*TdBosHQaz8s}@2av`3W{y1s0o7fKG}VD zoH|w?JNQmTqMDfYl%}-)d#CVnkd*&VqbEdW^mAuB5@z$;_)>=x3hg#ysLxd$^BxWS zYF7?x)l+f?QBi3*{l6EDZKzb7XKM?_$H%Ry-iw7!kBcC-&cWu~o{vujj2qfe))LjRcoCNX@|iQb6Y3j~ z&;E@uT|vpG0SMmUv9&6KqdZ!HDa725?6KypJQ*L|vZ(1V6-2J0&4$y)d2%vYm30#g z&km@+kT;YqKd?f6xwn+iW8t9Pdq;n&pgngHp^MYN8f!@$TU{|NqJjh;;(~{VS6l50 zxgJ=>zS++2F)1o`j2$m}$uWQjo5>5#tiW>x5**YA_c_G|dxt}VZRmIl%yM!+R09mF zqi@(FH2JWT_^PFD#l(SDK|8gbFDz4}5SLFj>pS~e33oaM(-L_4)8$P<5vR6xueqXablgLd@ z>7SR(7c2es^_SqTn&&F5aYwy@3t|Dga;W(xuQsogK!-(%nGqY4LL90m$c@Wqo%Bfh zE`AB~ecr&{T$|_Q?aVir?uiE3{5;}5*w`jjz6UELSI?k0wJAqI!{yi(#^!nlpmLNZ(KN{ZJAoZ${ZFHP?4)55$>bD0R#&E;=;=FA1Bdqs|yVh&C;e)bY zX@f0Iw#@j;Gpj(~sJ02E!aJc|@?qGn?wfSN2Xd$}+4J}y$TtaAftel6j@*U;Ev}G? z+hJ-q*?R=!#UC&>sgd`fm*#TN{&MFd2rIEgy9F%1y_jpr8xP8LrhDhg3)(^MHFKs; zxw*XvFEk0R>usby0xMFbM-1@?5~dp=^8T3oLysCrGro(t*o;^poeS&^ohqVXxyKyd z)e{`9Y2yRt*+XImTahB?10odeSNcazmtIDCJuOcO z1Ww-Y%cLz}T%^5(?1K6@y?Z_tt-!Z&zio%r`Hm2vEM%q}8) zyS&g*3LVB145C*p*G+feBVoaP3>?1Rz=rFz4=w`jg8L9Dm<;O+lw-OXdrVt8^@n5g zwcErY}JFP!87=P*%Mulkl2w}*XhKXsTBB}1n~SYKG?Z<-3!9)C*> z*}xB-VEj@QR#^Ui3l^7h!D1m`A3011+orqEA>yU@dNFSM%Lebn0c(ruUKeW!d3}yn zExDO=Gwgi)*|qN7E3M9u1c=#Pe`=85v#tHSW2r~mo~AW6g&kRgDGj1=wKr+sTiM^( zAF5-MBZ2#X^iL} zpoz1h`pg88k!k3Z^HGm4zmd-b4nAv3ojntb;F;{a_Geq3j6h{gsRM&K(-qGFF zd3=a`DD~n-hs6`mWuaM*PTafrQLIpf>Ry^bfuk#{b1~)2{*4u|LUg!fErCv#O%gZg z&!5q1a^87hWx~lo8>?_rk60lST5mg#y#q@R@o(bYEu1F>n2{F*x(L$T{9IiTi5L)*_G`u*ZhkIGhY6%;^c5+CZ{(D0wl)DKcGKUdkar`nvcJ6VGgeE{ zfuDf>0U>2hOpNLO+W=%#cOK`(OP3}x{u39-IMjY^mR0d=e+nO_m|^>_z;rX(C(?wv z&7BS3)EYCBN6O6Gn%jdw&CV#tSsC$&8-)99=LTc7Gon{{HkLxTJGrw#yPd&7@J3N9 ziogn~K=R$2X_mF#5^ip&GrlZtZa?i4uDE!{-m8}oMY}L*w9PAR!g+msrcMuUG*Xck zec-=@FKrF!SYAbxo>-&{9SkktFLG-|jk_6YZF6l)7wxxB!!&&l9dc+Q{O2y##J4q~ ztAyG;(GB`^=lgj9s8vdjl*X7QVPo$$lgzY911+r@l&Z3FX=?P#M>y zKmXP}3*&W!hiw#cN2E=iE5u%YJ+uP^xYYK(ZqVDVR*@ggrxfQmZI*aYrPMf%dlZM{3~F};XdKLup8rYe)4nf!9}g3hRQ_Nh3n>& z&)bFpnct01(Hh^G;AdR9pglNJ*DU3#7~kdGD8w}c-_-qy)EhO1Vl?7)qyjWR@`+%W zm2>`@qf=vLnkVD_!#PyTh1!}JDbJo5nhsoX%XP%SD!~9DT#O>^?mxNW@B-iKs$#?8F8JL9RP;#YNwuAB4WIilYu~mZ>aT=f;n;NyarRN7f@6WK!6p1#Q6{>8) zEAGVHU6+hMH8*Z+-<;l4Y-9~!)h<+xE&USHmU1`|DRTED>l!L^q=%B(es8pgUIN+< z4txDA`mJt)$y!Y3RS<=^Vl3Fr-ZGj}yD0(P!zp!c*e40dw5Tlv=|HZ=plgO%L5mkfY2k|YwtGb zm1g8M$TaCAris8VM=N(49BKHk8lBF=bSaB)UZj*xdA~+rOG&ylsc7v(x63zzw+aMN z!MZNJ(?ZU(-(^t657n9gF{eusLVBE2!`0$dNHTbB1lU>Kh@qxDYCW~ULq(!y`eY}<+!!! zZUc3fx~3jH=wQ^FtFf$C;623U0aR@i?S)n8l_I{H2~V9@tdW48Y!)M7Q5u?yWfR^P zUlr}AT6ER0y%-U6GnF0bu=Gtm?$vj8(t?tj(rRJsv071QC55W*hg+D9|G zo^a3+ynV;)Y@4m^0>PQaFk)KAI%U6RxbS+-5Tc+I;7Nsi56g-T00e-oXeO@ph01jn z0@>c{olKc?8-F$Mm4tqKT1*KFFPMVne9nSqZl|q3Ixu=7j0#T-H9fFD6c|K*X0<}s z$ei~bJC9#W(*hC!*Lylg6ERMSXKmlpZa3sh-|0Y2X>d=bA&QFEce*x#a$cDLh0@bx zgK{~O6o(VuAO>NfD803K3gCK_J>7KLhK6JRCX3HG=rZFhd@c=rfN-{VTnEGJMj~7v z^D~Qu@COYroJgBYmC}uchI|u};TlX)2ADStfP@xySy(vr3S{wrt7rUlt0Ce~$kJ9i^CEu6JgR}O; z^-!?N7Z`grgQLiorSX#7%ksJ$cM@=+IHvydIG&}N+Zp@<1uJemrXvD2P)-)j_!4ID zq5W+SycexQp$VaKK#0$5pc*hpX`bbCCb}9iCp2PzTIDwJ%{?;o$1lJ`4SQ!(jcY;b zE}NaI9r8T*A+X-NSI%jL@b`j2x(~{z+$Rp#NN*Vtr-lU2T(b&$z8?UWFRY!VhvL|Uj z>M52`3o~GoMia^NF&V`%ibX6-XV9bx>^ev&_V=>^ ziBDxMk^4$>ox(?ffGzLntEMH;HeZus-Z9W%e zLRM=Yal3Bt;zdr&Ce7mS-*uCPUM5qG<1O8{joSm_-NP$dOT=3bh+~J%5dj2y+YQ0Y zCIUNR6b00-gBMXY}!B3dByD^ zohq_*`b)OJ0E4%&6xW$&(bX9=K*!w-(z+%NafWx|G>q6n`E4Q0+Reyq$g$ z)|jEjb-0&sf6;GN7iHCUJovI=u&%$T1huOO7&mV9F3n4AZSMahg((>NpfKD3MlWrImW-W;tkj^FbfdzuMYiNGQ!Q%8fqO z^;#4m40g2&saURa$%H6a@c7$6NT!_fTlmHADCnd&!}&WjAM9L5gdRwbwOd3`y%)&y zw-6@Gh>dCQG?D~)MrOA|(>pi}+ulT9X`MSAt$(7&^Hh5)HHR}ph<(ck->QsqW_a$| zgh-}peZzUgUkqRFB#%!T={L;%&Rvv-88oxj*g2zHnv+QXN`kL_m=3&0W_;rBP z$Ig~Wr!`JImrU+g6GQ^+uE2xFVb(~z5N3TcL1b9O)ut?_XsJ0<=h$lcxli=ERjSWiW-;sm{((x60vL z(B(bJyPRzXbbw6{GWCPjNjJCJMO|6}G^O(2>U2K_zd9#9xjmY5pkHF)HG$}EqZ!|% zuTYJ4k#kU=I|&7k9{HyQTxtlh#>w=kd$$|FWa2uZvvr!ZHt3&~u=}bjvutzh_7W;{ zZh>l%{O1cLB(7;?aYrgteP!#&+X41_*aDkAS`OjG%Ykp|P=ql@WpP(Bj={m&zDEP^ zi2^cNEYKa&+GgNmjf&rdoJ022vAhnX;CoDmF<2CXuKiHr4!l_96#OOg(_j9O`ZY_< zI0ZAf+`-TxHxvzabfzlJ~(RJZN)?Wt{qe?)9PH|N29hOUK{CSK*@`1 z51w}oM;ac(R?fy`C0vb`4D6pt9&+E*7otJ2DOvC^B!J|BQ)Z z^kV8mhO5(E94eO~;pe;F0%=0`f8Ui$IK;IWZ^fNZql*Xty~2$(+y>w@SZp?}`8pIX zlU!PumiEDnHq^5op8BgyCV-)<9!CS|IUOK=ZQ=@SwhJW2VrIqZgvwtTa7?PSg1VZO z&zz2|D)GYunGCMfV>c%>4oJUeecoS7s1qtk5h{58qt`r~^V!08AZLzNh&(to;cKHJ zLo{swPt7+qd)Pogn;z8Xsm*ShLzCZ}!*s>>tO~RC4tMc;Py zeI)5JK0usTlu;DzY<9d(7%)hEpZbgZuv-JQ7-5@xK`fi>4lUltik=E+YEMNuJn7I} z?-6K!Nwj;K*C1Y?1J8Ix!sXH?;v*7zsz`_1VbL@Y9?RCy|9BP;c3${&vf6pG?8gCv zUR8i$@XoB9j`B&+64HYCTJ+HZ+s@|Jh+GD^D11>dPPpgNWg*s<;lFuD_D<)Ido2H# zd;DL#Tg%Z>ftDhA*lPF)hrQd}J`MxtE;!rq?+-Cd_18^b+n@VjA^EyA39n5Xk4aBY zVXE1Jj88QQBHWtN(#C}B7|9Jf23w5wpty_`Co-TUG%BjN3%mih~?FEk`mulH&-)J$iK81cg#;eEHuQLFsZa6&RI z`+|Mw{Er6X>7EI8q&R|Oup)S~3?59tZMweY1@Dz9GqX#sdRM1fU3EqAlX~VZ4A9-7 z;D1%K;}}f;`$CfSLfW&QbH|>xZ0wQZ-@NTjZGFOYW9vZNTa|j|~Czo!byVh1h; zPSq6M_XzUIxK+BKjzF-%2D#2JlB>rG+mVB&MNnQlW(z$%NU0)9qhC;mFC2SjbP~5~ zWpKX1iHNCHG>{{*^k3T9K@Xy_luR>f`XGm>nFar zW@JOsq5r#Me@|*<70A!(G&KGSOC7-vtD`@e1IjH^EjmA&d;!fpa(P#*{YC7Sd~ zPueE>d}tX8e-&XYz8UW%xsOjl<*#dKs3+v~g_BI7Eq_2kdWG<#Cp@6{>C5`>1_rG% zD=GIM_fGL1$X)gJT#+~U(_T9$Obx{?Q1_+2cL3)#Ym0zbI2e#6aR$OV6TLF}Vd7o> zPbzYo0(K&K()?%UNVv7v#HtM`gw0FXfo4xJi*zZpm}w-$K*$Q{EVV&67S?5W$Vru9 zrK~gzHLEZ%s%q>{Tye;ZKdK#&e+Z#2`v8#45}pI3><@$*vau%dmbltVq!g;7FHF%3 zfHGrY*I#&!6~^ToWWr9*8;lO!^&D_Y0BrSS*_3dZ%F2$I_U!C~ItuP;h{AWbXEDh} zdH!K}>Y296V2e2?wG*yGm&eZLli-oIQ$nm6k?&rdY4tm~C_Qy|GEe=cocPnxH+7U^*O>%R8Y6`WHu7rHc$Re~JD# zM;L$I!>B_D*Sq0cZ1eg>3dOq^6i-7dLrCSv(%iu5vg1s;>)fI0i4=v zNl6(+AmL`2Qkbp)frv_MB#~y`Z(fK>#z~ZkD*Yyduf^0;~HI z;C#leBY)_$A>j<@nN;<<0X~a<1(GgiL7v!R+v0mTZo_dRUYtBCw2}9yY#A6qd5`om z8&WuLKh*cMg8qm?>g%)qSG%=`KTA16G)GRQx-W~4^+8=0Cy5Vm#CK?g7ec2B4Xbea z1vkevNax>JW%pWd``Ny?bBq5?h0NNc_pKi~ZDTjys}0I3N5Syh;vczsM*Y~k=wLL4 ziADZ*WEAiFAMk(vKj5=IQuewqs=KbuXr!OujuCfMOcvS~KH(>nT(G2~K8U>s!12eA zw9~KHI~-{290J-!1UNqc3lW?|(+=Ig1@$>88)J2x3ue3@m?#vES5;wsyh+>-1(FJ) z_0}?mbKK(jjIYzxbJG1h1s}JyxCHG2OZ6sX+4v-?hVWb<87)Jad5q4Url* zJ85dUL4-A6{q^kdfwtlXw1Q-tJxp zDtH<>`!PCtEs>`rS}#sapwg`OX8QR?06XW)-rsoT2$LXwPfff8F2P-&uuT^02%pkF zaQ$98!T2@vRcg+`bm`)1j>xMwR(+P4l*dz6wbuXv?emRw7D&Z8>%PD8I_RaPiB){c z`~Ob3WP4-6Tq#<%gf3DRDClnhxG8|V$z(+N*&uSl49KF<>+#*BD92b(a=_GI^?Fdl z0P4&FnjpHL8qwB_2I@fq5rbeV#Mby#>n_1EzVJ7dMAs?=VT@3JBY&&juxi+|{4j-b zCx$eY3Gs{;eKQH7i7Q#llpmz0`a;p7qH@$M`BO$VM~C^8XT7StAA=^g1GYAzyr-7L znt$*7gmMQ~y@XLeWk4A$))}P~#E@1@ml488=Od7+E&0vU@H`m}Kg}VeVM3#AK$Jqc z^zW*MorM6z0{eZ_qVn~+9w-0vx@P|s7d1Y@_B$3RnQ602yQrwZ*zxqAB6f|xRD>=T zIcb7Z0H6@_VC#>ySDe>k2lTM^OUr7Sb7x7bVvvXBH}f~cTZo|jWHwdf++e>p@qu|8 zbW{rn1W2hlM*4uWkMi6O!TpP6pqH!etHlSecW!L8h-8hSUYwa?#;rU)$&Y`rJ)Im-sG%)MRPFmy2cCK73 zFDg|mPe!{X$mTFgQR0;9Y5kn8wxzS09{=o9`Wdm^ocTIQ6QeScV!NYF@#B$g{N7%1{~B~bWzC~VPkR6EKw~&u z5vPH2&!OaR*B*ZV@%WzWrFAxJ$2xfgsnMOfe1^{+L&~TVT2_f&qS6u^FUu1g3tHbx zM-wS$urw)?&?%Ql_HHzTRKFg-W;FHskX)xYk?Ogl*?TG%bgkbpc_#bOd7=9uQ8RUr z@*tC%4OLrZOIq)-SNwaGdJx|`Yx-j;+Ua8Dc%$$lCq1rW;#O0uM)%2G8Ud%T?bm^C z5;G}7UHGkxT^E;3FRvmi(>!Kq%X`p>-(4~&61oo!dW?-N06nDIDjJ` z3^`A45ZF;%N+z9xR!+)OR%hq7?f%9DGLA4zM3Ato7Gu-cr8JwsJE50h0p+x7u9tOl z3+a?Ta|BQ9D$+}Y?GDX$*aXtHsT1;My9p9K`b^OD6+kqT(P@s?Ubbc@d!2Rb!|hZ` znr%lkyL(uG+4ZZLjEs#njTXe|RlUUYpv9b!%awMEDW~g)wKt2XLZ{u#ifwW)AIdCj z*Nk)LBRX^z=tsN8Lzuk*86uK0E!H29#?MoQ`XbG&doqy8CAbz+R6j1{bk zPtOJ9{^hGfZL{!^Mljh^+aX1>fk8#ri0iSnXRc%R`Mt!$nsV3fxS>6P7BK{#5UVRg zDN)Wte^2vYk8)hvG#0?Y*O2I=pQk}@Iyy2Iaaq<m__+8LG)cLFu zAOb0|&?C3a$Ru!S{PCz@adFXzT9l2^CrIOi_RGEG=nGbb6MH7(g;g;-|JZ)|0v-d? zb#ODYp%I+zVDK(%v2NhN|H;5P$C5p*i-^VFvgaZEmy}XoGUfI5jrb#LI9PHi-nEJ4lQ2cF8BpvM^aSl z{K^u&r-&FH*ZU4n3wr4UCYPed4dm^{liHji`^)Y&W;8yn5uDSTpPbG%uj9(phhDhC zYB{$?R=@G^45;5ZEP2{UXbx-dTW~7Rdm>)feAVO~4Q&b1y4Sj+8wj|v9&8S7Whv2+ zHyH>Rp*WU);w<--{%@`(-k+(!32+*C$b2x947rE%f>4z5OT?TTbe)u?h?*nEPdiJT z?p)V=UEy*t*E9Z%I!Pdyi(G6~$=_Yp|8L12tXn1+zqN4J{g3rB^Vg-66FA{vApGgh zOjF26mlXR6njRPHZ*{Um|Kz)}|8M`8v1z8!n0;FF67^(c$1n6)O8EOFsiLYsiSpS$ ziSmE-@V}0`gnY&vPeJCgVNBTSn7^4;|7nR`4Kq&pKd}+3o6a9%d_(m#OgAxU7%#k= z=Wn+0e@?_@2>!`z31O5ye1U-4!Q0gya;60U9mKmDpIWKU9|7Bl0ex*1dVM?|x~R6+ z7w0-#xA9%;*8>{Gg-WV&bFD2-6BBj)2}vE?j`zP(Qz_SL;0t|u@wa5)U!(7I{1bH! z`1%(_T)LfQc4;k+g~rg2lEAg~_bu#wdcj3~Y|g57CQ~FWb9qK>FvqPvE8KzBgOgnJ zREOi#u4h)}COE6)$RoTf`WTb!-eUUCEdB!tp5Y%i4E@{|&!uciR0ZN(xG8hZIiA2G zUrGORvBIFL67{{P4I`T^nXfGrdT?+ixB#tAZlBxFbvs?n&`zKDUE?w|P<6#s9@XY}bBJSwq8Lniv~XlUN&Ec8!emaM3`(g#Y2NzoE&7tj$ZI3K>?da5?@aj!!U#*kks%KEHFcFIY-)+>abzEQF~ z@D1X4iDDAHDM%-?GiG$eqemgYJRPw5|D-cbRY-t(sKSsm{_NP+zL-SqgD9u5$$+Xa zzA8KBuBYXiC55ue{SWuoT*p5$O<41=Q3YG3JAgMgTEbB4r?yi^-)$Bq%b#=WRir)9 z=wjkdKdx68#8+F?)B^24-@W0|n&zL2t7fE6jBdk>V`1ybT$`z{k5$@gTw2~=BT27# zTF(?9j)ppY9qL+hv4om!Cg~| z6)*1Y?x7?&1&X@{Ed-Zh0fL?Mmgjx$xvzKTd^=}`%95j^QhXO z3LEx9?f#dX+X0VedH-X}xqwQ-@2qn|`ojt{S`8QK_;re|>aQ2DHRdL_{|Zk{9_5O+D%fwg|FY*RWYBXgi|iPuJL9 zr)H?L;7~lLoUt91pF-P(;{BUw&)Q|DhrXDVd6fz@wa?AzP7}JGTozjD^8B2fx@Z-n-k@5bK zFiHsiguA|kih#=U)V3u?^$`u2E__cYewom>O&bhPBRk++;dlslOdAt7pk$$#P?XSw zjTpKlo`}x<%6`?ELHZAh!=~sx{bK1|C8r;?TI+uh7sWEf0uG5No~9~z`P<6F@qvWj z-j%=IdqW6q3}G7`Gui|Ep$AiY;4%iU0BgbwB7R7#8_K#H`hd;}2Y!h{o3+~YgtY zrGsVEJDe*4MLEQ_s+REn|4B&y^P3FXqq^t)A@O~Ug6*PCX4Pdt^|_P?yubtEcd#pS z$x03C7T!e?=byLl5C~|c6br*VY*(`M7mn{phxHl-T}Ku;T_){0TqbqE-`kzg^iJlu z5_svZ1#GZT7EF6{kfRJf%6B^wp?L*1S`*D}rn7&y^CTwU zHLWVLa78D!D&-%KAQJrc34i^C2l+D#ptA|%KLO&Oy;LDkHBdE83<`2;qtMhO<^5HM1-9AHwPBlLmQ6NEZ*h z^~Wp1NO?gy3$)*`+ni@3C$R&G9=lJT?W46~mB#8`ILtFaQJTB`21J9ZS|w%ZCar0; zO&4;;`-GM0uaWVRK_4rB*$tOc?f|<4p0_HA;_ zuCLvqMWRS81lS-DinYy|ind*0>*VY3lxz1Ao6We)G~?HNEO=Df57$5pRBR>YX({v436c{jK78T-IX?J>?^H- z^Rvul9}z_mei^w#Jl1J)j5Y8vjn(i64Fl4P+S=0#ay@u2hH*g(evY4d>vQAWj%Eap zL~>s|lnNKotw?GTEl-yknMp8E*xy?QSHV!jBefU*3Y$ZB9JgGe`r6e|YO44RLY) zv;)o`+wvpX_o6Z8P2@f8?pkTA>a)d*Un;`$BeI~=f8_-QrE&Rs-XS$I+h6b&>|O7r zZlttYd2i=D8ki3A&sc<2w^V{PU_SNls${6R)lVs{?4q~Qyv$*}!qxjF`^vk{J;7xM z`=-mZ=TQF|NV-O!uUGZNkE`}^mSHl!hxCwDyiQ@j72z3I*84jHu9-%T0+|4$X>-!!%466;g4t)yy@1^>4za1z3 zK-?+xyS_Q^L;hFs$-=-;dh(ibY;hlfDk48uA^4lMLfaeE|C}7NKdXh9^Yb0Q-d$<1 z@x=aDJ;|^ZI{&xU@xLB~p+Cl2g4XjkE?AbkH!`9|kKa-BvpJu?LD{!@yZO>bqj{Iqx_(zjTc%C96d^o~N{wfP>}_BUd22AF&!w7f}PI`#-s`3#iF3;MeO z32$Dao2S^akJ@N$jnY*RScNN#+EF%FWV`6{t!!Eaqf(?OCaJZ2bXa;ut6G&}4#(fC z`AH*9P1LzBU-W;+(KnwzzyE_-sQyIKLS)Qzp(>ZQsqOuFKc=^XLsr?eZAJFtZ_zUQ zXvCo>@aS;xPi>)#7f^|o>r2oHR|>*;#`!mkdSumQ#j1E)I3#eR4PQaE6Dm0$Lo_X{ zPHIGKCii`(IZx?5!|(FDx*k%Xd_$N0uRaZHxv>vW6!hw2?luM5&lY0u()XA?w2L>~ z+5}Byhhop(VAOW+mn1sgSI_v6=dEOYf*tx)0eTaMTG5dgHy(mY`XP2GyF*d^$CA;Xv#mH0gzctpp;s0}NN8h3=GsfwWDQ!!gLHAp! ztAOC%GIT<%bZC|l<;>T25#^u;U1a6pL6-L#j80E&D4*I2H~TbhL`@5*mB$_qY!|$E z*ypnBE!%`;xc2J&sF!H2XlK4DsZ>{D<-}}Y2_`nEVXt|Y+UPb2%OM?y@`d-3Z4jaN#k84RXYrfZ=s(E4dqSC(-6aiY7jpmi+Wq@%{;4kF zWdGb6zCZDnw_fs~UTvB>6J8Olqvs0YM~p8wmN%^b24^G(+a+6~4SH|VU<|r|n=X#7 z>7eFn-`_1dGZ1?sL4qiznsb9fO_`tHQ9mKqJJ zd6>bGuQT_4iVxj*$4pw2`$AgquGUJ~c>ZkmWpmxVGH~m0vE4S!is&*7`G0w;b``7uYaKHrc_C#H&F6Oohr7uL;s<2kIkP%6WG90VOjFacni$nB z8SS>Sl&33g6gnK|Ja(F%#2I(nale+uqz&qK&ZPX-=+|ZW6~Mp@%rtQXmDv$lAY=rI8!qSGKfDn!kKRXzbq1BKlc){$gpeB zR9ELY(u=jTvfRzhK?=iCX$mHqTNB!_xx4A)^nAM)JLo<;DUECWoe@KD@dfy z0h_BEeU0wh0J}BCbBDyzb6P6ay+It%X;Y~t`~e=ddFHwHB>S0fMX`Xvyu1S0y%zTF zlyk<&ve5m_QVx$8ZzaOxBck{Zh5%jnDQmOeLSCt8URcU8eDwzD06tb#4Y>%O% z`x?blt!g9y1JFbGy92#u9iNi}Rbw*5GthyTIn%ou^{gU`8#Ps&An~o55Xt#c5A%>- z(TlGOJZG3qy7j2C3z~a+T}va_Kb$vN9lX!q{tebfTkQV19PiP~F>|Kl2Cay;KJZv* zM(H2$zbiz0C=}q!IfJ8>_C<_8r%wv081CE01IIpM=tdNSk3;lixI{OarQ4&H=Svd~jK*1sd>DTlZZBY9GD7 zZCHzXP-m9VB-2_&MecWIzr?-syUEzC?(e6G{Bd(av!wsD301%ax=@4Mv^J!-+rCwR zS}VjxJmI20O9O$-`FTdB^siIt( zULR2u0MPw`j<`!xwdzgRk1DC$^6#bZ49tZ^RefTnm7++!7Fvult68hHS3xsSW_@3) zRs;RtA)Bmv#SZde|A+onq~f$nV+;oD<$kOEGK9;EbdluB%*KiWs1yC ztPCxqUE)?{x$Unx61TG4t_O%;)Z*6ur+WKe zA?8EepDm!2Mpu;@s+HC+ce6AN8_U(F!7)UPqeEifjrAuqvKd%9AF#L|B~eDi<%c`3bGEok_nWo5;| z;)5|6OGHjhRBw5)p6-klbUQqZJ7d9m@P+L**wz~%DADvon1w6;gg@x@Zb4~D#3**|H@_N?+X^;!GO#G~Klu5%LIDUS9RU^x$f^nJ)$ zr^ZEhbr!iPB<7KAFV6$hfac9!+`)T_x?QDgBqVwf6*%5ijZrwoKefk2eK|yvLmacm zE%-Af>>;1P4m)sfK&rXuTdu%mYx`WyYi%l?lL3e>~cX3S&;RXxv z)?qz){404eN^BJs*NMI1gQLCUSou?>L*1sPhDlv}s`8hs8-Aa1noweRhi2oWXU;xf zPf%@)(K2EDN!P^%Kh9RMVT-4p)G-29Qo2$FA~I9Mcb9ilncU}ZbO;lO4Sk1NQF4~W zq*Terw<_2Emesq@b86JJ*D{PkDsi8(!ajANHkz#9)orqm$p;P#XD50t><=_Ng%9Qj zm~(jgh~UrRALS_Ym6kwKPM`Xfpe7$6er?5&xGGx#cLP43FR{b~iyk-ZC_W~T0;@0{ zvi4Q)r{GU#Jpo?aL4wpXYcHKJ)n}K*d~|fJ>?B-bn50cOnm9{+FJB5!&oY$9*#S4S zofIG3S}BQ`*Q?l=+6fEKkmx@kXHwwA<3o}J;5v)ws|#eX4sL~v+_*s|STJp@ZJ)m{ z*#`Lc-G(&H;GNqUDt{P_c1BgTMa@1+MEQ=4t#LEOG`n|lx;>TJlDYp0_q0Az*o?<~ zJ>JrZVU3>Zqlg-YC7%7h_VhH1#=ABZJ~iv(aL2QZ#OniUF}Kd+A}yA%+h>JKqf4l8fCp9@KOp1*# z8r}5hvAU$JBX-3RGWm$m@KQ}YRDu899RZUt=Hi|G(AVxlnzFLIlh7v5eKn8B57 zqPaEa4?4{+o<=q&8TeV?Bs$VNu)>nsZnAIXjO8k1{o}~eO_Hj^2q8qU=kP(fkn#No z+U^T00(vsDR6AEVMLtG8vrYVtJk4kJ6}Qx`5zaepcoN&|{&taX4Qy>G{MNqZF9Pg6 z_PB9e>NCQB;#a8AYOv4p%ubl|RLY!aX^05Bbs520+PzA`+m;q$Hzb$o$+X0Au}13I z*4s*YW#S`6_c>(KxOdjYhhAMSTgsJVINeA|iQ zuHQM?4!{evq96TH7ztt=b|+}_gKKWLl{>6sC&!oB?Z%mZ|BV_^2cx&A^nhnmTW==X zrB?=GwmAA#^UT-ZN!KYSjdJko9S57i^O%t8!|8fHuL+`qdM|`%zW=QKMP}c6 zsqPd0BkWG{R}H(Z5)I7f6O&&c(`?==fa~TX@%B5-vzKd62p}R_eP6nGxm?&4t`>`}Jnfkd=Fd3o zs`sIr-85g=@~?MaJ%_iwTgpHFT1dP?!kaLH=se3U5`gYH)}2&KQSVCy_=Q@A_$dxy z)q|gT?@4pDCjQLHZRS6VZ4qKbNZpCa0>4rvHeWfv6&MiI?mSaT9^^Tn9ji(ZLhZ3C zYuc+8irS>91jpa`Uvd}X7K;iWz`4&AM0(cXP2{WyT({Y;xNeyhHGY81E{) zOXT=%S0aiW;KB}zey)ky(xa4yR@L?|gtNle>BOD$E&|t1`kSMWdcCj_+pMZ+H}tAO+)q`~!N1s{$-rQ0~UYiR^TENfhUf1jb28r07?vD?a?- zbt8>;q5_~d2shg8Fb`YU%~#^B+y07f{YHfF@f`t=g0iPflk!BtVv))m@wxo)cM z;jxy|+-9~bse-88Be_L!K||j#cfjQUcq)C;i1c$p3owe!J^pH%^`^L(uW1pFn=9y@L>ntQBMs*Jj1!Cty7cQ$PFgG+xf>=FDOtZ$s5#dU)f^ zt-6Ia^x_USxiX*(>XOO@*J&}pB>k+cR}({|5-!UkPcxf#z07R_9n8xT<(d*V$H}In z&S3sEjMTf=stJ%AEiZ6*9BpPhgTdA?wTt7x_AEUL{R&>jN;4);ZWXw=H5ZIEblPdB4UQ+a~ztMHM zluqSswYW6RCHT}B1xI2x>@UN1dYYClv4Rh5ac?nik1r#3Y*qWlJ1WQr`mKvG;4@=4 z<%hZV3dau}cWz)i3ok|sjJ+tP=3+kuYqK=?oW3~g-a7*B(D4vPJo@?=A z^jYi87~$J;Eg9d#*1>1ePxJu=-+E6f7MWQEC^Wv@6+@yApJ}tj9F zAn`~DdG2%uWb_5RQ-f*gsHhMBt)aY0@Q&sS&XP=QYJ{2F*r~ek>{WJ(;YT?+^cm4l z#d_)Nm*u4}I#`56YC!X=WJruJ2AQiUn)&-)*=1--O-1MuY;rn8crr>0I&dKISmmM* zavrtLcO`xUlW3Dvbl4TZ)5(KRj3}pAHVVaGJBTN}jqE+OkolD?-7qo28{r&8RXeT{ z3cy|>ar_~pns7o2P;l>}zKb2o|5=>3%Dav!@xodNezLn^{v&m$J&|lslu|?y z-Y=Dw!O&qVK2nN&bj$m?uuI4up9_>eM$wXLYMK}5-pDfvo^C2ZjZxsxSt2Hhnk7(H z{^*1#>=?OFbFeexzOXnajr*wKQ&FVN2U6?R((7;R&ol8|UTo7s9t(uP!Nz2|4T(HM ztH%M|ew?^{bW<0CttuOcDHZz@d z++oAab+*=9Su16hg~xvW*bEXBsB9PxzoJ&U4F!W2d^^K(;=V_1SJ`;+%bcV-!QSq~10 z<>%IX)9gM+)XL>m2C$Y)$Y!q!t-dvu78SEY9PLJrbv(e>?p|Cyv?uVZ1|-qn8ZG*& z_(f=8yOku07^+AYyK-o}HjOz-#>!debbGQn%&#~%z<+|V4Zz(?T=$`R_ zaG`D|Oh`MaB9_-ZI*u`14(b?pk-}~iXW0Hkq{FxGl4(%uxjN9$mBxwNuB3eWBRx(L zLEsbIqEW()SLO6t?<__RCT37icqo(YdpPW`tGma%GHtNNChZUz6S>?GEAWp#kgS8` z`yVXs?+!%y4*Ak(D1&eKrk5^?e+~Jj8D@;$ej7O@f4wok5Q0YA?D3{o^hZFa1!p|X z#f#$a*5N1quK)^V*z0i=Ry#_8JJAw@vpR2WB|pYF_Ll1CTI zbV%1s^0=?pFjz!vB^8;wfr-qN^!8u7&rQ!>NItun8XUClXHo61HHtq=c?C-zr)xW_ zIqguIqlLL1kzZmAU+#m)C@sltR~jnDT}K`6B8rj;pZM7NNBDE@IqS61T{>ODyp!Te zYj^+@@f5k++lVLT*IwGI>N`n~N#!I8ZhrtYQukwCbnantDS7*o!Da51%`* z;6ZpE3fp_?kk#(+mL2z67r?)A9hR2XRDvps2KRiaeGEHvk~E+$_iG(uU(THI9qe7( z<`#c)4^hT8(+7&BQ}pvq#U5|~T@E<1g>r)I1PkjK-uoR(${lS-CH=zTyBucJ;SX0f zSTB+(;-26L@qKrL?-e$43)&h~zNhQ^UR;$_WjjTf51gd=u@mSUSK4NN=_nB6@e}9H zYtK;+CofZPhz$Ltg76UPYET72pfdFup^PyhjWJqfm}VxF{2Djc_IV~Q?FpJ&wDLo| zMTJ%O?<~+Rj;qdv6Xo=Pj$raF1%;@`HCVa;D12)d$)D)>QRX(j&-$_jJDrxqckzTY zxj7QB&*8|`Ml;%3PkpXc9M1?BnD^Coe!v0fjT~T=Z;jrr~t&fz4gs~s#F$eWfMNm&qXW? z+ZJyo@87IK_aG{LbRrEmf?%sy^Pl-O=G0F`R}3Y9m_Lk{C+d29z|X59`Vk7fBv-c# zpWtu0xneAISr7aCz~O1MoC{A?DM!6<&w%fQ^gXatiOKIBv{zQ;$!#`=y}Q$HkEMxs zAEGfz(Op%I@bOvw&d|6X_bc_YzO9vjrm;qzc`0=m=b!U08f^cksuVPW5*t=mfNx*h>7vw^%LcC+TVU~7{>IemlP}YLSKmv< z&pVi0tXI_BrmlBX*C2d-c1n59M)M|jm?nX4-D|0M9(o^Eyj6H_KN^1DV}R~`8MkMS zI$M|=9ow7!bk;1#R=}a6+H&+*0P!WbD%}&a_K`oKLl=z&L+aoF+a}ST1NsRs@Ny>W zwz=szvLj4MoF>ADCLN}%kB|FA0us$c8xzf-#_?<%CV$nyg72G}Ch@Y0PpSi-{7%+r zO5O@NpD24W{Vd$^Q=k9ES7YRa2SrRx<$^5cRj$a!59-MKM z=B!2Es^ptqv>3TU#=Wy{9lsIA8miSfX+2=O;M(SU?_*lEN~HNdta#rOz#Q=-qq{l4(&DSa$t$62#8g)RL_t6Ik-v6J zLb&q}>SAaTt#JA`56~@ZviUU=_oxjYoMl#lWw=3RsD^Oz_505CO8R_)W^qqMOfL+AcxngQ$-#Bf z^-2=l%e?&5=etJ0M(j+R_Pg<38soOAIevsx?}x0)twjo}!CG~be-OfuCUwPy-XiL7i%pD9%>)_gC9ob4`7V2gF zIanOl68G^2382c=&uoDPkGgnHwl;>w&{Se^UgN;=@9~gWhFd2F9RqNnqu1zWOgPbR zsUE(4*ERvav%7t90YO7ovtP+MjUY-Z@=uTm1i<{)1VuK1a!=;@!Aei7#KRigOTa~W@r7O zRLQzCu@I9+URpVQfzn|u>EWn>}}=n3Zj0YsyB zLv?UjxCQC}JG)31!PVzceWxCXZ<<822fajSGmq{m83L!}2w}ROIWzvbBtwIv78|Z( zrVj?4&m}ecGo!%2zpaWL#w@Rkg>z7QIr~#mn7se3D>TK9>Gk9JxRlpSRRh1rLwKI9 z1w4=X1YCO&c+CNq%KT|p@4>$9X6`<=xzF>~g`X)k80;chy7avsTirN7XR-aF!}y#> zZ^+&+Xc%vh%o^z4~ZRw z+RfF8>(Ha?#VG(U2&NcM>DtRsZSs_c+Tq%@bL=(w`=G=%-8sqT7LL-(((+x5@YK8+}Si`02AhLOhg#b?kla<7)eL z`pWnw#jbEZB;08N*YndX%>{<0rk(lhZH@&VAiJyS6LkLy!F&DJ5wZR?2O*QV4TphW z+Cj_${wwbf%_h;{PfJ=(V=!^0n(S_TtYuStBj*|0GgQ?ibzeo<5bQ{kjLUgvd_8oo zUiUV`)gCXHL5i1dg(kIXxp^q2c6!*&Ra>DxT4Rc*F>mZzjMwJ68Y9s%O`*({Nn^>L z>2$kYDv|HV{su=NbVcme6tb#)4I<5t8osObN?PIJ9+wMAC9JKQuA ziu9t}G!sebemSWSGZ~eYXUVksPf%rGSr(@wk$|q5z9vy7(7A=FLc{F^I8S(yHahi$ zgj7^0xy&7ulgvcwTRNVsG-vZ#qRks%ceBht64jKQOQLxPpzt_Rnia!ul~Ua%l4}>E zzET|2jhPIRTb!?(32s0R!>t+|=UXzX_}BLu#+68+4?J;0x{yoB{sYgKr+1sxoq1YM z1^`yXE7psUNLqv3Vfq&25IKC~3!VS$*5wgvexhb%ef6@QJBx$aCZo6d&sL8-OfpoV zE=kQ+XE#elh99-W=vRfpZw#9cI{W5J61X%F?*oOXFKBf;<10RMV_G2p0^PsWN#YHI zJ^)~bbVU#w4UqIGpdTl*!S&>|WQs+`a%axkSKzeK8>45DcckUoshKJKC9iYSC`#_% zuSA~bbxLfL-6U2=*?rlp%Um|(IPHtnUM+%aZ3%UtI>+9gG4R-S5IqMA-}B?jA0R~b zk#GHvNxIoY;)?m7#>zTn9xCcw+Y>I~*KodJc41IZyNDLm=Y^7fv`P)MER^P-py=)| zF%Q=?XuPkQNKl-a8g;!iMoh9bJQ!4N9{QPzDouPQFtRKY4`^&n1=7`XI@gv*Mz(eP z`r?S=F(-uOMOFS9{m^tW;Rnk)8LExYcX?~@T+(Nz`#Jnq%R6u95-x{qtpL%`WJw&N z`n4s)_oF}CREJbnZJS%Bhw$6d&72WIEu9UZl6r$Ywt=q+>XgICx1}rqLr*{E{F$hh zcUQ*}7u3erizT=5^64TWOkm~71|FkDf})mQ^QuYwBl*7a(>MCk3$2Gls?9OoiimQR zUfQkrGOD(dWZCGc3%5CAIGBrBb!Km+5_eIs!}Ta*j}KM`XY}RR>lfu6+L*@f6STmU zH?OkNJzU4#r6Mxy^Ad77@5;HZYi=J95PEx;qCfgm=^3gw}bzb)b7NV&6z5etn|EI#Q z{HOO5PCOF-NZ@AV=<8^11u!pD|2h#xQtU^WM=m2u3rAnXA3hOvO9NEJGa4GT2U}Rz ztur_=qLSdC740gBrpDt)%q8jWhI(w=j4bBjV zbhVx^&pATTwHNrgUP5-tq1*6hgu2LAb>biKTp6eQl z6v2ef;c`~f(<4|5u7~@U>giU!#qEf>WZ`oi?*k{P*oE)$gcbFAk8PnJ(5+KQwxP`Z z-Dx}H?CVT%CSI0eE-wh^z&2)VgJ15za;Evz3XWk|JN&+-8N|zE=D{F}48z+zR0oXr zh%T(6`7O&(v@J z+C&%UY+hq_?#ydR-*%oXuGFR(r($@bivY6{`y~vjGjj0x;?C1_61Pe)`5i=s$N$@T zn(B9mf#uitvjUQ%+E91k)(f_SUGx*3OB;|+@m<$O46cfg*VsA-q4!IcjD31C<3#2^ z*vjmwzQ9k^n5k!@DlYx1;@+CwZvaiTdSfSP2qAcbwtAcWJK^q9ed&ii%Auu89_G|@ z+oIGBi2{ZQ`RWaK@&0e`^jPdPEd};#4%$ib;&|f71xBiNAhdjyv`d0@P3A|?eSF|FNF~v>M|L<|0hvEw7|tu3 zQu~c7r6WGFuZQeTd1<1Ge#ycEM9ZKbbl< zj&2QA{_}Kn;a#LL7mipKYX@nlyw@`Jsa2aJ4W9tqr&~hqxPJ_3OvX6yR-hYQgdOV+ zzepNfCWdl&y0Fp$$P$vWpqB1>(^6$Sbts|24nn7|2+!FDoE%Xsq7|Z6UdCz@^9^%x z66>2+LUL+1b?Tu>Lcfn)nXQvfca7o&&8~*^;rpDT-(HNA=v2T{Q0|?I6=XV8Wx-_VOI3%nvcMu_e;6nyM9#lKSl`x*3;N z^$>C&e3H^!XF1c{WP+&Se&Ccms+WUo?IVNO3c-~bZhLMkZY>5E!ajwQ1fX`oZ|0HE zW2It$?Z}0#Cj+Y{V<*LBfnCN=dpRb~YPON437RY}k2dYSVJ>6Gv@yUhUFY8~Mp4|t zKg{S()zconI*3tAlkN$Qd#j?)8yvq?I`~2JAnU2vKw25ww_4Ab()BZ_997$JFu;VM z2>0f|0HqN3>de`V<@T!`&c$5JsZNz-+SorZIO=#qVvIP|lC*j~wf7g@U??5s zMHjwe+Hoxs&UIBVU^C(Q#_h7yT;V|KXJztHX!)Q(Wxpj9Bv}5Ud&BaqHdY>Ya1Zi6 zJXyC1rZyMCEX5g22@ylc2yEo<%(PYZl7~=Vt3`?lc(El(fSv>iekML>7yZG08$XnP z*pR5xztYIiYDN+k#NXkNOfX4fZMmp~LQY-BGvZSj1y{D)aSax=-zHzt3`#ZJ$)FD5 z)aVxP@~yhDE+0}JwMh5lp;W{|TG~=Fd!8QeHk-wSmXK}n+EV)%l>z)nF4hHIh4q>+ zf~Zpoj6Riet1DeE+zL@6IVh~kxFni)W0(@V-1iZp`8-YXbrNTz1B8G|TtkKQtlKAv zzrCi*Mf2<14;%AsefE1qo$Es$vDx_*@WgD^)hV`ohO@zYg-bi|A?ZVGHzulu=b*^j z+9Y>#3~82?7u%pNZs_vHzyrmTRc?@$@lv7fexQJoAKM)F2k7q>Yas#69{x`aaf!!y z!^&LeQ$@1kVun(5*eq*>vzb#9sWMl-db-*`(@-2pvgvg)PI~FnK|NI1?(%Um6!g;( zp}eK;%pYeD6$pvvXp~<%UrF>`%aV#8t^YVeoRa2L>O3NQC*^fj)WA`>R1mES+i9*p zbjDdX#9F9c9R>}YI9sXNvyMW?PBf`X3kPv9=Z$bi#pa3Djmo_&uGwrFTN~I{B4 z75oIS)Or<}`^J0t-9un|u$^~``kdxCDsyRm;ouzm-X+~F0fo*%AwoF`wgsiR zeVTdvK2Z6tAxL?|mE@bT+=@ku%Ihn6%EF3qgRiQ64Bd%Rg#I7W-_sHc4MBueQ@`Nd zh>F&HqutsX3-!8Cu8otvf7LR1oy+RsJ$pEry@MT+5r%Ed+wy#`Zz%K)mzgnKmMcT; zYDd95()T%iOj!kO)cs`8sI0WLPCrvQlA4Y%g|j$%(3S8|FHtxNF380<2W~-S0fEts zn|?$MU$hI~7Ig7~_~TTh7%+?AV^r_>^7szg6M$4vEs7k-Z(cNmUm2=Fqc=jCtxAhp zkIxj zqS}(^7PY@Dz<7fAy#nWAzFSb&j8xk_6Ugr&S+d5kJ!&|6nfGv8l^(?NLe+S0eqT=T znGhFYVVED=7#*t?@%D%dS4dY9mgrH{_1jF3NmAf9i8d8QFx0QCk{b?57-n89A7=I> zM@|Im=)_y)H&uctw@*gar_Wtg`i%s_2-zLzIK8%9vNA!;rqkGLv39bZ0FoP(Wxr$6 zmBR>?8}_Iw*FAFB?B@vfuHMwD+F9$F%&2B=Eqff30e|>YOIjN!j`D#)W~ZQf@m%2o zRz2P5a6r3C9x6aqT+8r33q*NAi#`xF(_2!)0fRk zR+=Ek>6-~Y#w1^xC@>G_T4lE+aZRL6g;@1%pOkvz8Ns!GR6ePCz&0NZ`Uk>K{;;wU z4;UH6WzMUvzxr}UmJ_u8W+Rzv|HmuI`w(J_Rs{fhQo2Qpl4lRj_X*Cj7(NkA3;j6v zN7qE-6YG9jp3s|P*C%M9!X}DKe>d+hT`N{D zEXo9#+q;+bG6}>La2+e#`R}|D2<)r=m0WfdCiDc~E_K0^VV=?>?#(aBN1|Cs(GR6G zA`PO})!r}c%gt_#PgJ39(NIu<$@``9f1Y<#f`UbRVukNC*@4$!R#ItQZ5nHJyx=f@ z96di@RnD|A z1Lj>F9g<_mrl__L2>-Wy$XD*XyS=We_>alF2uGNh8 z?BxB)8@?St&_&!v}mL3jbNUqH6;VPRpiQ4 zfNu1nvv@5?{{k2`2=PXOo<%JIFa*-kmjsaO-SN8k0g-WVlqwHWj6&EUynb$(pl=)G zNir7S7gmk9Ib|pp5}bPyMA!0lg?yRYIH}e8%lF+4G0XS!a`HXq9$=yGurm5=US3{I z)^T1y_1q{eN0q=nR!Cx8XA~Ih_g>$v;Dg=e+9D2Rj%;imRfjm|pP#pLx5^UOG~;Dl9Qq<4q8}G5M-Hj!@-|;CF5RGU6MCqr$rI@Z3ACrT;MA z_e9d#fzxy4=lVVZ%3xU(gm_~xu&6&82paKg^L*+DUp}MuvaVrBy2~MG*;sUC8htES z>MK`Bz+u>Odys`iw_UOidv+?YICA^3>Sl4HBvWmNIq$X(eqwxmp0JDFVQ1eOQ>yqfhZ#bIZf!6Yo| z-^6s;4+ruY%kPfc@!G(I;a7@liR#I-1#KbMGUiEN0Cg=FnH$5KYF=*m``B=~wI4U{ zbaZw>Y=|R_0y&OyNYLKC@rC3Wighv{PT4bPo;pG!KIKgFBT@%vsBO*=NrUM`K6Gz~ zBg}2^Y*Mt}`|atte0s$T|19T_%AFZK4x6HWA+|xb9EQaa7TZZTpa_si1K9HC_UwHl z=^F{2|k#R*E->;E4|H4Rn_^SH53VnAU z*)+LJukY~bL9HL<3oY|(1aJ34MT?|nkIbcdxV?IbtTvNbi>&cO$HKv)F^4zcg=%ZV zq>@+z9dA0n`(;rjo@>GL7Pc{kmG)T0a<2@LC zRrW1aLoFnw>T1+*%%jNf=QF|M*GrDOh_iRNPf$opMy;NzW$d%Z%jfWhQ|gUldW)zf z@1Cj_QBk$Q^n;g~-%^419FfU`<%w4P*e)rOv+4f)9Wws0K%yjKtwi&Pd96&f)StP6 zQUY>2A5m510^%6^mKDFHUFlVEoY`M;Q}e1@QYSY(Pt}FTut!LGvoU4clj_J*7qkf) zDKSl!{AzHZIgLB~MIOv)H+ zigM{t(SV&${L6~YvhN|~GJ^(gw02qt+s=6Epljiv+)gi;AUr{x4vW@UPcm)u5*t`Z zzcJ*nfoOEjp{3lr!I!O~K9hI(k}=D7takU&%er_gx}l5{ua&%qsaoX=y>*;_9!35j zorp+<6M&8Yh9&3oxkqmV%(=)B^VWK;WeZ1rv7L zHY4_{o7&xWoas~hiIMteEuCv;T@PH{#fmIv;;+P+6Bd|oD2w{OXJr}krP%+1NZ)Nl zB)23-Wj3eLACvlZ5Mu< zME`6oaptAA!Xt^U4Z95P9)@bC)QB_pEuy5vNb2xwzJ0T{0VoI=T*pdJ^6BS0UkxL2Q#d1s5jlUo+mVvMJmyov`tfC0Bh2&0sfa6njir7^R41aQ zhb@|lvu}?1dN0&=C$|?Tjl+!H&*^j4KJ{QIzG{ZQ5-Ktk_yD1tI89@&N_p$7_AII{ ze`@_{Y|{%q2MYDld+Gw#>MmXUi^|jT^lg^IK6?^@pb?kroGJ^m0kr`E+G=4b)nltZ zw;=ysL_3(tB>j^)??4|{JJ6?OMD42vKojesTG34zWubzPZM)z-xqyZ9h#YDdmk3WWUJKQm#?4gv$&x8}S;BDj?s&R2cpZ^!*@Glm zcykk4iRI&9nc zM3-acQNJiWtk5Sgsp4G%l3PIRAqn3a+9&sz`yQM=SwxePtHg+YpOf%izKVaZNM?!X zF4&*Mz9}kTkKVVCNRe~1FlJfO(p_YnUK;vRkvB#lNl+FuOLV|CWAjM22~XUz2k^Q5 ziyb>HZy+C;_$`4*Xz>EI@aP!&mMuN+y=LMj+qIwMMa!BXld$3J{83i@P-=z0h^C}o zCPgH4E=2@jdD~dAe<+#?2;HgrUPRY2t{arU3Vr7#+G#Q~mh((K&PK(l?(ih`LfoVxU%>dWZxc z<3;}qP9J#Ccz)_dlY1&O;h9={o3~=aaevb4l#$5w1zFMX={NG+kfVMwPFI@(4i~?; z{<-W5_NgYmgR`}g&d4okC%+GSwid!x8n)C%0$88h_1$q66Q=fhtKe}Q1?6yv9|2-d zm9og{wy|+mT@ukDLjz4b3la-IM)pV+F{b9N!2>$77)KaW*ew*giq`OI!MT6qs9K?idyq zV}xg#W7nO|#MKvXaq2Ga28>l3C6A>6U*?|GDf^N`3zeSDO&{#c6jO#Ib|?M9ei6lK zdj9q9Z#gu#>iCH`rdadW9o%U|w9egO}&6-$I>`m3H9v20AU#CmGVBgmvDA|3j zeYSO~v1Q#uMW!6+a9{qFT8tETsae7ZSTbdIM-thG3EL)~46qASv*xuAXorFV+Lz;z zeAzzRKdic3ADU~}6aUD4X~@ZPOLj8(5xYrq;0b`iR5HPKf?XMJeq3LfYD!#<20C^& z(BO^Y3|2ChEoSw&m>cNd67=pa2=IGw(#NVh5*05Tm zy>I&Kyc~U)6FOxFBvD2D_ZOnV?TyD7bDOS11wV?k;FhZE(p~)kedTFU{W){d7_Qs6 z?Onv}$~50C?58{p9m^mYggu)hb-W+~(}=e}8~){P9^IY^+;2(??pTu>c>YOdX+0VK z=!CkltLEz2bU(w7vzqVrc}!PP@t-_ILySM~8c#WXa8nY?8i2M2qd!1^2t2=Pe+bNr zcEc{2J^JFstd(8X=R1C*TGS;K-fOlb=#;+v+bSH?iyu^S_4ZAhB+~;(tO~<0mT0}J zqBWcSz1~ZftsnE(vVoFRB4S7#fnS$(`iI3$i+H z?sSpajR^nIFu2m2apQW7K65mhgzlYGBz{2U?}f6O8IUzpEBkBuDuh%NvhP62e*u{!B?D43CY07^XW%S*qYhv77YO38AH;P zd`^biKHH-nEzTys6641g{Fa@Lcc{tNQ4<%Rj0X~`-qaTjDy<_c)5 zit(9uf^zR%2FkWsbW=-$+*6Ew)^1V8B6&rB37eKONwM_d{2Gb$nzNLKq|T2NV;;WW zyT6v3Up_VCBm)5rJk-?+%RaZqBC>T%<}8n%0Ue4I5oWUi6|I88N}mDOuUa?~+^(^( zyzkbl#!12+fJz$)7Ava=4`%sXGn2u}`4{Wk81 z%$=C@y=D*T)PA^FW8-+Y4gKi(-nQJ3C1hVpKYsauWZ$>=sAoxj!1_6Mg6ynrf-IV# z+*YHP*CkqNdS((?e8ZiZsuUJIO}%+DKilX?r8MWJQJ)ZjRX-rB;1}NkBr1w`(8e2T zc3{x6*LZiCM)I)~?1N=xiFSW>WKS(C5S*h0Ca!D#=af$_88-MS|CFwdk5>; z9jq2CjVq6rES=FlrJMZ0e&2|(p8Z70KjQ#mCeJeN>TeCElGP&To&4YIy84{PtSEU?zI^kO4C`5rG9EivtmVCHNPxsHlKM5}Fn(GmEoLvs)3QQbMaF5{|Mg=2+ec4H z?qHDkW|KSxF=EdQ2WLMa@4XXBEQnE9wOh0qagM3rC=ZPqjBTBmRobtLicFv&TBYu( zpvSk&3UN$Y*x5jRuq(j$y*_DNEVKf-CV-v;Qv((T$%e_@mZ-1L9ty6ta+%kSUCp=B z75@Q=PEwMy)i#sQ@-x@gJAMm|S3ap0v_y2~p+o_G#}>vr5O zNSSco-1*l-r+Igsh)#j3rggwB%R0d5oey9|BLQEA>9Z3#vJ-0uyvHmpx_|Q@7uM=;Q+nMhsPz3p51sC`l#XElVxNO z$NUn;f3N(%K=2=pz~^|+thf99eiQOrUPwrOVfz(^CWFO>U-~pkG-z2}=6EiV>bE() zp1TNz^y@Brw@VobRBr4F?@ zr8T)`rQ##HGy5Hu%OeJRL~;HAJ2YTk{Dxk%Y>44>mf#^!+~ySni#R}1*Iws->qTFG z?N!w}Y(1~mGcpL3(%!b#$avbR-=e$gogOkO;-DF4L-xqRI9VvYFXW2E;w#jhtN!M# z^!aJem{Ly=vVHFA;2)&LDgr3>VXY#*t6JL|F8ROp;^uHX8C>dC;_dpr@?f8gL!HZ-2vB){$*^4U~xEaLcb9Rbm)TFS}zJ?UkkhM|* z-|Xf0?cMXBwD%NqXJ?_F$XZoF4F^~7Vv!f$F3f)VQa_i&#RU3Yb<1WNT zIjMpssPLpRo1y2}BdTgMH5B*H%YH$E#_F3#T367{GrjUEsVvQD(T$ObS=l@h_`g!g4dH4uM=MNTcvy`RB)G7e5Wy`(${tA)o zvl&*0C}|u^VLGqrv745&rX_gj^B)`+&7S}M z#tiIn&9>30o%w9sL^&k*%wRUVGlK_>(%5d6KQMqhxF_u^wzum1ZUQ78a=tcq9z;e{{eV+?xLc86VTiS+Q@KCE-gF87M)f* zQR^~D>9pZl1h*r&eP|)M_M~r>8b+Hvudr{@p$9}8C2R$G|GZYlzcx1q+Byy9U(NSi z5@XB*)@)cTyx5tD#_k)SLrZaQfjF8E7__jqz;AzECSA;5GR_q3#Dq@^Lno4vq>=hc z+5p+a^+FOCTx+a1IrU)srzJI%1S{KwLktAcyAv3GJQf<2AS{N%7w430TVzf9&Dx9j ztWeIJwb`UXdske$C7LW^d++|tT_b+Oqh+rW-|Uf{-Hn^)WaEmXgY@thq2P$~y&M^r zpq_@rz}ZB6L=rf8?EPcI+C6h6a(k%^y0n0Gq`~&)mRlG{c0Ue}D{np?Kre!MehK%F zz~A@zjY#(fv;$?~7saj!9aTyloLd>)phzMS90Vk3?|U^H1&qtmM9V&z!~k?bof$N- zVkek&yqyBcZ?q>mo4eoiW&R9Tv+bqh2=l+B_CLtTP~ry|Xz4Q(#Et%b9MQDH5eEA5 z<0tOF(dmCtE)(VN7pBn+6{F+N7<%(8n-sm}BWTci8p)rz6q;hGe|PugucQP2zjt>T zC$exb|9@M?9o!Zf+>GGM&DKvJ2x3B7Nzr;$t1N}}ANekNML2hRGCI+I&hH5R$WGAt zMP750Zq!l3ddRST;Qx^f&>f&c(PW2uM8$;p$6b$BCZ3|9s6+5~=JH=iLpO4=(L5NI z{R->bKajzH>j3C(u>ZH4|Axo^)GGcLHh(6a{|B(y@Cw^)KFvJ2su$lJz7pSbolrOh zDNsKmcdc%gZB$_7V7VOM&=9{})esMUZl|*N`cH!Wuk1WMl%bXe(=Lcb)&7Nz9G)wl zzQMqX(RmkI!l7KmQtrDMP~a83#)8B%@Du zKVdesMd+Av{U7%H2t}x+-t^7UDV9_XTHABa<8tOv|6G?=bxL`e$yHIzm*TO@o~b%~yGcZoI49^O zu_dkU5#16;8*7zsG?^FG}uVovNoQG+p>=`r&PHiRNAp;8(xwQuBQYE7lKc~?rU!s_$>=L#wW=D-2wUX-HRuZ=O zO0O9D6tFP=fvL_v9&yG;94FV3ZW}VslqW^c#>W$h?{_I!UA*E&IR(&y=29HFKw+JR z(@=^n#Hm$GUKOawt6sa1Hv6f5U7?L5P?g6(|KWM}!n5scusX9v0ilG6^_8u%b#oX6 zOsZ0N({O>lIScFqzs9pFvKPAtpn|MW!}1g6YfqSa!Hq3iBx_0C@Mxal(X<}5(B0f4 zlKQsp(Xh-tC#`~4E1f&5-;;Nr4D?wB{Dw6G3yt4yDN1q;+xw7~Nx%h^Gj`t`8 zm-5_|Q>%^O(b-n&_VM1xe&MOTT(mt z$Xrb{D;*a;f}xZ4uZhdQWK4Py@14HV%{XDDf3C~|AmR9jY5u}JN$>Q2%ms{jjMhxy zFy>J$V)In>746rOe7?Eimb2h>ooV5!PH%Oru-!d_spD87Ykn_op7|3xP1PDuRRS`^ zGhJ#WvFP*IP+`h67?sL*h42jr$pR4V^U&97LZra}tqB z6lY*yI{Y{o6|DJIuP-&KQAZdDl*oJPNF9*Z7)nD!t`MfEzl_KzYs^i~P-a;TC|K5( zb}YgSI2)1u_$GsnM$q9woEyayL%m#)X>!Tyhduq?@0^K8+E6$py;|qEGyuB-dq4ql z*3@a~PR+48y8}yGW;~@w5v;?oWV>K~E zhWB&bMP|Y!cOqDivc~B;WkV6z$S4rjx}IB> z+TFp#zJL$=wd_{zPfL1We}<>ljD`w`c7(4o$|I53L;+(#f~fAbodE9n+v||Af=B2) z0pI*SWk@SC+&HJmNSuEuc%ss^oo+%Ro94&TBCJ2U(2CP2UF+etd?dx069|=vuoWgG zUt&vLV@O$xtkxHXM**rNtE|>ja!P{-KNxnEnRV6WGiSnX0D4jR;YOf8nE{_3Sx z$nTD=?uQZ>FeG00;%q&XUZmr*qwddzld_F&Sjz$puolSE*pz~*>3?l08=b;wznpV& z3|gDGS!loJ;aqOf;55*ccEM4L4d-WfOYwzryKn3lg4HFljEgFotWJo!PU%g8dV zp_ytxY|%sBMz8aD)_df(V{L&WhB+dx7SW1T?^tJ^gs&*2`Zhms1?wMF*rq2Vd=Fso z2Xc=;=J0(sIhh|8?TaG}aV}`op3u>8Ve52Y`h$B2C^#6qD8ZH{&5=EGySEKTS=2hR-*< zS>#lAP;u=w84Q;TEPV_v6Y4&2lPNqFguZ|9`b(P&4*;ae|1QtmkAzR3$#FK$60(%F zajm*zU$|;4l!ea^kKSf_06^tu3&n?4`S!_y5q$(f@F8XU(G)8F%0nY~C-iKr6DM$! zz4e2kq=l9}5jj)Y#!vz}Zu*|!@uOLU9I8EYYX3PHO_1)S*{!c8GvhBS}7Gzjfe_Vku=0N`3#^Pk`N9I z`aG1*qd}6|UQ+9c3KIM-7(S4Ye_#*M7fb`!kH+GqkgjN4CIy37K-WX>3$BioCX{$X zjAG`v3L`9MRMy26(Qzo>+SVQBYQekCNk)TL4iiB>Bb{q`ul+-8_{>$>TbwCNUc}aF zv>vI6*9JCbQgs?_P8n7K?T<`e`;oYufy@MCOlrLVwKt^t&|7X>jMG}&O)Ywf7{Cy250VNh_%w6TOwcS#3lw%cjHMqtYXdD@h zHfvX18}?WC+#C-(`LQE>DR8XmLT=mF(&Krk;G{hF;=J{Q-NJkRaW?&lZj;~U%RUQl z>Lib(=cnJe@GJg79cK~@&9A5u(tPxJwQj7kO*|4CY4=>uj7>A-HKULxQ2_=f&MW|E zTbjoSJeTs3&}=sOA`(Vald;!yLq-E)XSZ#*$@iZTVfY+Rug*e25&qag5;9#IJ)|#= zF!lGGd_s1qbwMi;%xwS^`AodxM-DaEW3|JX9Q}OkQcH1XZP+zmy}RL9(`3|3h>M0k z>0wWY`dpGGob$}X@C_q%?!Iv|=$>ZNfDqnN0McBmuo%WuY>9S+L{+Gd_{*=ZKI+r8oxdAsbj z3PxXq@)Y86Tk*JJiKqgx*g{}DFNcUR_XoLzM}-9BjnTDzxY7bkau02s9h>Jb`g*$im_OIG>ISV>31I;=f7F;hjzU_ZIB6o-rX5SF|nWE}$ur$}tnQx`naqBgQ z+ECyD_bEtHeV$h<)X^<4-hRe#rsiG>j-Cnd>Y+rID64iGPhfabq^(v5VQHnV(y{Lv zYI`GKtQKx~am+!Sj|9*D?27|le=bqLv3liay902XAChqJ{EEZ8DMyziIj03&@|F`e zkUeF#Xcg=_$u1MUCJvlpFy!QWr|H6eA?c2@4vAju$uL;(9F9G9h@h5Kk@&8S;~>U2y?8w9x|SD%4}A+ zy*=SGE!V#t_A8i4Z)sTYFU&LPt$96&u}v;>Q!I25Dy}Xm(nV&id^zD-hy0vmV%v=_ zL)r&PauzYBxN_FTHfXnrTC%UGYm;jN)x#>xbFv0a+SJ3ULt5Kp{1()lLlUpPIJVch zcX+PZFQCKz-l;i{zEXzym2v5dE;RI)E7EdKKvCQM^RFq51s0`%JJ{puvl z?Vhb!KUwx<+^pYT+|jbdpwGr6%a;wXZ;@o!{A-F=ex>${WQGf5uEk2a>de)`QPXIc zfLC*&h0m(>oxEqTkc6SL3?Ri!%{@C?aeF?{v9fxSH@yUIYAD=e3YBLq?KXu>57Y{m zea$Eg z@$8p~&b6372v6$kPZJNZeG{mEI@QJhn{P4HC)fEvW`cR^&-#jr+d54pdmOrgZV31# zi#ra#IVjI^mHU+jEy3)|Tmm>J`~6eqiu~Sp-1`UJ@BNc!kLDGFf9bi=u$&bEl15&al3NS#Th?!JL(X3wX_HcX|3$`w&!&I?)NH;Ct^;&dNRGl zvLTKt#Le}{vn=q!U%iZoUT3^ty4j>r-N~{rRcP|1QCeYArluOHiLl>C76U(c#CM;9 zYym@(J`xdimY*#`Y8|y+)g=$Pp{yyDMjhoo6!M8w8v$Fn`vs0u?u9P|PdfUNqMKur zGAiO#IV}4$Sjx5w9V2vuoo$`t>b_M@Lo;dnzKU@f`0H_Oc(wot*DA;+1jck-*sBU- z(g#iXVSy=SKlRj#1e}}n#np%d=c?xnw4irY*4mfsk$HpR&eD*@oX;&DMpxr&-GGt? zVOyg9MRY(=vPoo-^iwRZ@fN&MBh%6CL03J}cJriLR%h4myv|bW$`rAy^b7{pWPd@<1R(`ZJt)_t zq=kUjN=^D5^OylB&xP-8ngy-BcP-g4O0Al(u!N21Lh|AZ+_6FASQsb)FW92w zninZcmQ!r-i8B-gZ|W1hzWWacFjCx;v`#~Ihm`A!$cf%gR4^5nBV&2}`@2T$&NAmQ zre#Q#2p(_eys^uj;RTph^HmN?gFPTX&e|Dg2=Ju7!V1KbE}}e0CTKsOteIusn5YC= z-?D87X4R={r$V!%WXw`T)eH&+ofZr2ta+XT9Fjb)Ufr6Cm3dXvbxlk=g{5U&u-OYA zY49db=?M0lOQ|vITJ} z#^#RjQxvHN!^7+)6V+&WJbZ5)SL{15ZIM?^E!bS+uhJ6}OiAsAjuu#wWyD7rDt;AU7OaxkAx0Z_>kY)TK{UBB=xH zFK1GW?z7Ru_&lWj&0Y=p42jfm9sFyPrgfB}Qx4!)A6eRc3DO5NB{||=jOGlaL(REF z!d5OVoFRUDu}-ekpEmiIwR_Z6Nz54qw4uPiM;ucXboy!ylgmbH{SmNGsq|#F?-hft3Ws9@5aiP!jj% z-P-+R^&Zy(euXRQjo}X+AvCL&YoPbu3WYp{jFxUo$e@Qe!D4QN|FH8|LkZkS;d7uT z_T-Gf{5;8?n8>#vL%3>~=1G4gQT|*xf#C!4`I8gttt#=&8};yMqFeWzG+v8K210Jm zqU*PJ`}+FuV*y)5Hld-ZBH;58DXX+S7tef=A+gyj*leA4tqDZjAjM#ymV-jy+CBk6n=4x=pu9ae{;MvOEsVRUFLW zx{jOdoE*QbOmE(^qm-^UeK|Nh+cpWoWVJ3gV%`@Yhq|@XH0asEX04kxOls!dkA(U7!96u3HTsF zANVGQqdsJKlW?Z?!2&eLSARjtL3zA8ngcP9>AC*-*g?$o8D)68k(znvznjF~B)lnU z-R<>gCq!@%3mX^TtiJI=^@W&bqRaK(ZhRIPbvsmV^)8ryW zx?l^Y?Sa*G4x^733OHv<%jv~#NBh%GHF|PpOyI4eeI`auFa}o*=+{hDF`vSP$bpj; zlX&OyqzdERRMu3>wpr8N*)K^jvh8|taJFVv{hTRuy1H>I`_!S^I?Gw_-u=5kxpdys zMh&Bbnw6i_9-Tgec8wQAd_omd{ooX^H|vhW+b$JGK3A1jsTQ~bI@Z**m^>fUODD>| z<^#G6`{}Z7N724;c2KpezL)ZnCJbQ^+t&FMVa&(E=4NHWOCJ4NS42L^b^Msn`#15! zZ;oCJz%rl?pijF~7JJ>krF(AAO53n!EGbE;*SgBH`?C4_#SPoUqWEuMW-MRyQt9~!ckfsh@6Plyey5GQG-~pL!mS%%-O07}*fkgkn`iAXpIFE57 zmXsg4Aa&IFv}Ls^NSrl^xG3h*VjIGuo@}gc=<+;TEUn@Tz8PdA6*y?Y1X{rcF+3>$ zrpj13QomW73Ny6z=lm>JKcEYKMXgrEq^S0Sq4=2mFpa~*_(m$XiV(KMsd|rbt>=9& zVBOTiA`$2QWI8N@u+ZA1k&{oLHaZC&C`-%^BpkXgoXTkvKUhTp+0H7d;(^-no`EQP z7Hac`*ck(5z7Qx3*ZVskr%z1wC2>Ip1L~rvA~aid!?lS&^t2jz ztkR&!<6DvY0$oLIa{nOQxGl%K`!n93?E+bC4MM7$oWj%+K{|z}qhSH%#q|@MGYb_? z)mo^-MF=`)Wer8MteWX@7Oq5}_HfqP;2R`&jquK_tI!P83<0@BNsMDF!2~{Ab+3J! z%1H?VSe88FPg3$v=HOx|;(M{C8TTE@RG!`nhPZd_6=z75bs@^^)@R)Z`0a($qX}|H zaGzsuzX`PWM;74vjHc5YwyL}cXf>$zD|F^c=@PWl?ekPLoOZ7QQ#E?qS$vOfY)qu& zHjYY^wp>DhlkahfmTYY%U@-$)WBIk32bNesn_oeTC_}-KA_0#Zz>KvV0Ajmk0p`4 zIA+ISM$(4Fex$XF8oV#E@0Bz_cOG9C^8nn4K2DbEWn%S@1>l>F^1inz6nRYU*W$lz zDWSc^swZGyw~sxj2FuO}HMITiUm5g5o32D9ydUv=Hxi|zUE8`B zvY_v>i-er9CI<%$$?j@6;T`_dt>Y)WlXSx0RtFt6u+@)&5#fj85)vioc&d0oVO`~I zQd3bI+&KDl^?E5I#jCC3FI8V6YoJgL=B|T+R)l>f@Jcvwcrt`%>io%|?Mudak3+#J zB@m5|U{cm>O=`jB4AWIak*gzgv^IhR*x2T|{@ru_2!E_(y~PuWI$5S4iyZv!A56QS zA#2opQ^XsXMLA59pS2(0BCXkcVX}VNsaShlLH&7wtmsHBDrkFS*-=E7Cdy&7NoF*5 zR4YbO-y9lT@Id-Z%k6r`{ZS~thzhhVBLD8%7C{tjsd{wqLo59Tux$O*O@oW z`bvR{U-fE~F1b&g!sVbB0<`jnm9G}bWLu1Xxqw}X9B<~C5ndJ+Dohkz12!)*eMTOJ zcpXHQz?aHGHn){8{WoJC3ztb{bZ^?xpfF;b6Xs<7oL7?)8Xc^HJx~e;*zexf@3UOo z_jari1T84JC@UNQx39HeUJT>439SdtC)MrTx%Q1837zcU7IsrHOn%oAw$cX?SVN7(((aI!&lR z*)jaqG;=+YgtORpBk?mdt;#KdgPDMybbx)4kOz{^dDLn2M#O~6UcBaIIOJ^@`M+U1 zG!@Gq6u!%6r9HxICSJl6@k7Qc*|rd!*Vf4yM8QhUE+UfR{wu`L&=9|_#skbYrRyOv zD#B_9H?a5Q*W@u!iNY4II=?gV`WdkFjXU;1#c{s!G0}O6r006@TN)=?6^$^E<0DRL zLo$CupwCOq^?J0?ipGo#mU!Js#>pAk%Wv@{=!AQ88%sxM~Zbt1D17VEuvFXiI=MZk3&QWw+k=nE9h09Ph?5yckK=y@Z0JyyE>&?<(rV( zk@HD@B|um@)$58v-wLc&f9FFS?{lTbis{;y0iG?c<4$OX=#qP+7TA) z&WH4r^1?UaiyHWF=rwuU<`H^;ggS9swomEWy9i^X@x!j8L zJUAoyWpr~b+@z5Hs(Sw?@!v;Bd&np-qb;RokGf%~%-WqeqS=~k`_ZFS6YJs0T1Q$X zeQT)Uwd*!hx+v#6WJZ=Exst32Z8-hhfB5O15QI+crO86kmkTDO%fCvf;0`e4^-c_o zW-97QUeICIM}pk{_~-xpZdt@VDeW};N(KOh+#0f>{H)keap#LAuIgDJFn(#Ofkfmv zn&(Y#TB->cpYmTGXeWPVW*o{yA`19NI9&e0 z`{}o^G#%3WJ&Q1JLC3mCf{Wb`q*u(<%G6ROC03JOFE7MwSqpBX_Ct#QDgu3kOER6@^HKLd>j(a=GFGS`x(eeE_`}^l{rLY{QQq9 z+i#j$E|B1(GlXmZAXvnHVk3#msLx*dnEIlVs*TC&dYQ_0zR3$Jp8f70i=;if6T0@e zDkpT;>h{v;VtzlEZ3bw#*RVol0=0|N*Vq5SQ$Hub%vkt2U@wkVWOd$W(Q6nrJJrUT zeKogk=P8ZzPgNd&SF7t+ebI5(%-(L-HTame5p{+rY-*ZC1tCE7QO7GSMfX9ORg-=} z2OT(j!&m$5d`6X)6zk_x?KfU_vrXcR6Sp;=dLzqC4Gwh-RHPWyL$#5jeMlFErM(Md zA}8^%ztydMHgk`Xy9$Nc58)dkKm_c!8W~nv@?>9*7r*)*P2uuf!oqm_9F7Od%i(5le;u& zi^ctC_WRAnm?05XWF;4{z}shu<)&|?Oo>3;FRvcP<-fj-&A8|Q9KjjKj&|P-tBrNn z@pk;IX0r{@Sd=o*5kvKN)qEU>IXF~d{B1K~U>*IQyi~whdGpy08o;~QFfHSNZAg7n z-7ssFm)5U?F5>x-Nj%`9?+T$0&s=zT_;r@Xp%D_!UlQ=d@G`QLX6BM_@aWaC@J!VM z@+LTs)qzyW4b`jTA?8MZC*r>EE6q=+6bI|J$_u*nK0%B*lAKc*yi0Gt?75obz^+z1 zOL_|2E9T9=9w*Dw-fyM(ho`T83?;7UUe9=iz1GZOln}_@f!L;okEq)@PXMM zd@Sy}oVPP8*xt-$M0TtEAB^L_mlm1;{rdJEtoIe%qUq<5#QuZz4r>6Rqq?;O0F;T7 z92XbYsLm6(F0shr-+a5HsPJ%P4_jZT~I-#bj=90W#>fEG4Hep}Ay{WwM7%lersic)UF%c{S za%2C-N?%0bqbG88)X(te@YD!s#5@`Zi4Gj68*cqA|O`g&a^MVT?kv%7%x1t~q* z+4hGj2khMjy7|L5-%fW#OZ?4)y>1*$_LH*ERpZLzU8f8yc!=Df)YOdak7{akLs}QN z^V>m#{w3q5uevMyl1A&FKrojlw)Z~8(U!&Zr^#yXxEq#NdQPh zH7#oyIWl#|^?S!PZt_2ti9HUW=@uv6TW*5K&JP~!oUBCeDbMaIPgtD)2tU2ZzB6Dq zV5>J}`)ZYESG2_Bq~S8~S3?czoyj!IU9N6{BmkvRP5&1zO-t~0;ul0%O#lVY0r4aX>wbZ%x;P5E5vuL`j zh2W^x)q>uO%8lIjbPGBu?K-;d$S};B`YOwy@#LNrvXCYY;}nAs&7cU&y{{aN*5@vM z&Cs!+{RhUUzxc&&Pf(W@)3X_mi?Yp#`na?gcn2kjdnJaVkOs^VWHO^`0i*RWAUwIt zF65wS>+pR=Sruc)&CmIU;HohnTUX`K66qXoAB|wo7iJ?Ot%J30lvACt6y(#EDfasT z&oe$gGRscMU1#uKSZf{HY1cjzcUIDuVxbzUU#;tqe)`ac(A~dk{?b2CDSp2sQGWe& zw8-*ypzLTMh`3k%ayWe2(Qy&Rj|;5dNwgU~e>G+48fSg`K+4jFEtnG_Oc7C4qF%fz zlYSm0lRKB8d)3eaKde#~F=sB`C~KEuy=~;O>nxnsYX&+5hg{hzjvm)9`s@EHBc|cl~$K zhnBSRXi1CEE7s~2X*-O&hX)KfjImPD(;JHo)BGx+_#$9!9B_0X%|_Wz3_RcXa2ObM zjGeGI8Vb=;aq@Z*Fh>k*1sQHTIXT;2*G;|spg6p|I|}tJgV=N~#&45sVE9;Q_=Ffh z1UJl&cV?Jc=1ZrNf`-bu$`Tgy6YAZI)6;3F8DKBrJQ1tQF%m65zgW4WxGGw`7xBby zrdeB=1CcqK%|WHXzTgVYaL9pUcJQ4sn<30pPnFXGqKKG$Lwa=5cuUXin)_UVu7hvS zyeG!DW-XzYMU`Fmg6OYP1bEbapg%YWA1hSAp?N76d?bBQ~|O`8OqeUfb4B(1kH zBiahyaUW1?smS`sL%i$NBfI0-4n%AW;!g?()N1b4n5+zQAe*GuJFY!6XdzCeCtelf zQ(_|{Yvv=2lD{5aP9NUb9DN<)U}$3_bkA$I5cV5PkI9}Wcv}x(R35WrzU_EzNmyq_ zqp%>()$u&CFRi1i#@e0LhL@}O%=J@{*3Z3^;{7R+ohvVOjZ3RJJG&Ix5a-y>P1*z1 zlkKEhAIt+6CsaU#4SVvhk9TfHD_6hDTzH_oRDzHuem^oZ_k{GVj?)jXuLfu2Uu<6- z-2ZPm`d2G-jWdT4S;tgaQNf#}R`}V{2L@b|uobfvw;e_b@sH#_{up`VXo$J_0l*ev zVAcw?x*e}CbKzm_6rW=)n_XX}>!v<)u+>;T`V?KiX;o34 z9M9mzBW3b>kX7Gau)e)@_{W!)V5Kbs`~67A#n;-+j_5L`6%}bxYMLh(S9zsVt_^kV z$mcQ}qEG`DO-E!F{B*=ipr`?Q~?Tv1BUkXv2 zcbho7PkT;`Z(3~sYJA4sPz37RH@P|FDYc(=9V^&U$I=?ilrJJGR5BP~T=_^jA@v{w z@PVLPv$l0O13)F?;XVqcj?JgG%=h5mmo9bH!?X##P|=<9svB==4AJwMA zoZ-{HX|r=RPWO%W-!uth;kz}@c`VXHL9I^v;>G^MnR@Fj*?X^=qtlt5lt!GoHy5mZSDz7hLSuI7UwG-=?juFm&%B#1dvOUdLZI;;w(#qP%hOou`x1eg#9ry!*2HeN++!7yMB%Nu z!c;QtEz65zartSM`KlAU_fAfett;A8g~TNb_G7GV*BUqv@M%39g_g4bWbgBXS9-3A zHI8J=pRTRNeLT1cV{l&dsb0Qv$pQRg`Y|_;lrN5qrV4cUDd{^G8Y3};ZV>|oMSfrVYm`8u^d+j z+gpyDbIHDyPTid;4WD;EDK`@#n1r$he9B6b0i!b0_nLdk2Pz zuqMyhK4^C}Cfu%C#Jir)ULu`9%q-t)k`)!Bk}0FU=UPmy3~f*f+U?Ldy>tMpd7n2i zn*T~E%vpB4i}<;5@-3Byp4ttBeR-+x>Qn4|Ui}>4l>dswt&7b5{(~}}f27>8Vj)GRC312RWoO>~DIn$m2WU3B*z|Z>e z4Le~MJt_EJZ&Ba(vB`p;r!oqQD47}9C!8joN3}6AW%jz?*D@#y(Hs1gsXl^yz%bxn zXU_w!aux;v?MFn&-8bD)g_KBl9*wJV=dF`&q8t=;Y==AUg;knQ0^g~Ojb-JWxyA7E zK-dvK4<&cn$l7YVUG`q0%mmyqnsFm6Jfi~#&-;bM&#;CwoCiz$>+43Ph{En0^NNp_ z5ps2==Pn}&N)t5O`gV0VmHgdh-%`O3w+taS1iK@|9!L8jdX@_h@!GZJ5`=7+uG{WQ z^oS-kApNVpcn^PL%r30F7x3>&Imi9L&bwyxEz^rkQ_kNm0mj>AWEW89%rd*TNlf2r z_=@m!%73x~&0cHyej(o>4iVvp7nAMsPt0uup%(Cy@^%-DO6^IUD3e?+sTkkoa=+&v@?oKKuMFS`_0V} z){Q&vDP-Qx?_JKd?mnDzG~@mv!e41(x^Zscr_z4e;SC&XhJnrHM(t|)CxiUPEU8m`0r}&F5o5(pQXMvMB zgl`dF#C>>DU7cIxx-(j(s{`6@o)tGXDk8q=mk(N%zC6ShZEB&;7$TPz<*;IN*Ib7At*4ylIePl@_x~E?48v!|Eza-7JXJ%Lk4M z3PthNt2ZiN08^W~YPCo6o_Qfmx5T(TG#q-sr+kRqo#=Sk`nA)c`8CI1mBG^+JwYNjsyp6@f_|7`?TgVP`Ac3G+#|@Jl=f1ar`*N_2=& z!zm%n6g5X&^EBkNNu}VRQ(SLo_)F&;KvH6L@yqaTa!q(8%GGu4xW^jDFBRe*Xw_9o z|BHZ$C&-qAd}?Q2cstbDU0^LTBoJyh?tU)v2~vS8*obk;_(y==-9F*(_h5zDKVmrM zuv9O+u!}4Tid{fjmknVtF&G5l z>$x4CT)gfefPZ2>9M$p(W4KadLx4=4OONu{rS0I!?&-@KbM!$i1Ow6MIG2U;canTh zLhF5v(kdHBmhQQoUxYqFwWF(r@DSuBMt=#)^76;8gx%dm5pAw%Bhu`f+xXrk?y=_k zx>n-m6IRi+TekeJamL*A{2oWkjvA#@Zh9BKKSnC37YP-(Rz*&Ym(=`P-zf=UPfa?Y zxu(eL?CC%Hxsf82&Geviz5ww=d)9AJ$jC_A=k{FKhm^(u8&%|PR#U%Rs7o9sH4Qv zPnDlK9-za9dwlH6iDF8FDvXipWM@XaphMW@R=>~)(08gy&Y|&Gwr||ve(3YCR!7I= z#(D51uwJaIgnrOhfG=}ZbX_AReN5ymsjj7Xy+Jkfc{VFsF*h&Pl35yj@r{U>A*k}!vQdd^I&&iK4<~x7oOf}#Qvqhl%lSdu2 z0jlH|ZpnH+jd0Y*!h@2^eIP55*~Tn5<33{Aoz$OWI#Bn5RWP8-$(`>2yiuyw7QX?u zT9H`alj3GT@K751a?=1!+Q#AF;P$OF=`A<#5B2JxmYiHEhp7u z9Gbny5>N5a8jqRVxsrdR@z4Q{((RJ8Q_4XpI@u)DDc)=m$$QXV#l0*ukr(-xE-yCB z8(yqKSFVR7T8Doe_%eF)MH?)7p+NrNglyRWw|rYicKa z`rABv<%8U9dfQnNZ_L(X-(u5#coHV33LYdX((NI-=+}}|l`OB|Ps;7YM{^P~S5fWL zEwY&t1cqFmZl{c-pEaxQGd;Ot0ZU#Tz>cfvLY{^<6k}tmOd4IsF}O&tXH5Uv$#A@e|dcq9Oe6hlUqmASMU?2go&#b~%5G9`Ld=;#AFi(N%% zZ$~0cKoiyNgZb;zr|RRDNI`yPjCCbG968&^t{Zz=YyW;5aY3`aojV+0Cvy|Ko0`B&Ix!Zl!%8gbmAJgdCHwaXO$12D)Nqi{Z&JQWeYt#PU&B&s;oYe zm+R_w32^uJ8B%m}g(DsT!D@ZM`~T^>=oEW5-x0Q4kp)~J%N|s zZ|}0yVe^@YdmP-Shi7Ix-3s_AIl_sed=fMlT*{P;TT1v4+Nx;p?ye~#BNOZyL(?QC z5;3ow6chLym>+T`io%_j)1Xukv92+-a8U5^Cueh>h|&5EdLoDo9tzrJDYmPYjwMObL7~G zMEZoYf5`*_N^f)X&%#Q*1?nPmTnyz&*9{l`&QX3%r-JT2mzQ{LBM~F11F2`pHjIWw z7maT<_y-1qM6@1^EqsH1{b8Se8Vh76a44E{U2yKzZF~_aIEod$45d-iXts)g&0f@8 z5t9A0#@$%DR{Gjo0XZX@A)7~Zs#bQZzZx(;-=Dzm)g0?%zGbf8C3YY7C15ylacYaa zH8d_i)FmQN#C%gH!Ba;_7_rOjA#n5fWb&g|xnrvUV}~^0SAD2d6%)_ryIDQSn{u@w zCh}XINrg2(*UInHSZ6W5`exfw@Mh?L%yRddUu^;iT|f6995!_Cz1rl>SFe=>L~hQ~ z26QR{LUk(Yh?AS5-VkNYt~N#J^ps2eRLZ~G7v8zIM%>g(>c8K?zxHc(^VO#ofgk?D zJ(It-TniEw$^8+`hSd%6TJw&*HSS_a)@D#PUOdUi#>}=q@n3@*VSTrEBx%dFN$)ZT rwO_cmW1oqqeEdt*U*z`x5B(}A1g7I4el!xhh5wwf0Gne^ddB|`3KeiN diff --git a/assets/select-swiftlint-plugin.png b/assets/select-swiftlint-plugin.png deleted file mode 100644 index b219cfaea72e5fc922380817c4a4eec8ba65000e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19530 zcmYIvb97|Q^Y_HI?QHC1W7`{hXQE9u+1Sa(wzaWs+vdjh#DK)c^p9SnziQ9uoZI62J%n04QR}Ns4K>L7XM`R#lKA z2kW*G;o+&utfZD)eg-~HTmE(O1vpajvApOCNLf7#*r&5A11o7ho9V*yT8L@&^rgNf z7Av!uIKK5?w+6C5(5fZ~!jv9%(g9K6_nDcF)rFBvIq;x4&^-qS&1R|s{ad)>kZt2~c7r=m(aigG;<>N|fJvpm z*G&C#c`zvv46EE5IZ62;m-k`ih0@O!O%-ea588U%Q~$6r_6mU5@nOKaa&xF7aaU(Y8rxHMyKOp9XxcD z+vPVzV=>luZ?c8;hFjJwgz=ZJgecLs&tA=IBr(Ht$4;#V@zl?n%EE~F>Y*_XLWq!J zRKwT<{zi)2vT!%><82E+xg{;)S8bZ>SD2zr4vA~mV+`OapuycnpbN=y@BB?wl^XRL ziHxw4?@Kipplz2q=ypK!TvbC8<7Z{!F#I z!LU}}eFEn1Y)HY9Zpy|}d6`la#0uBM^;du0Jm2DW1SLhjE#^6RDr{Nx$ z2S4JVqFe}uuO$l53*UUkE8iC|mW3LB+-~Zd)F2ISCoHQxhKc+MI=(1&6K*k#mZmzj zD(t~6eP7XLVMM@82KChybxZ2#2HyY46xbfAK-vX-;Qsc7bnBMX5LGQ@fXt=T%=L%X zfXS5&4V5g*ioQH2I#L#^-4B&vwdj`nH5dNm4^w zOiawk$mmGEs;H=_tt~yedozX6GvA&_dtj&26x)T|;)1j98;2isN$N8P=Kwi-u$@ng zov8%%*}Al*rlz5xVT~N7mR85WTded1CJ)A!u#8aNK-~!|vZ3g0VIUSk>ndb zw}D(yYOU|zw>CE~wkSYhLH4Oq#LZRoKMHSt!$-UwUdA9OG(zh?$6DLkUheGdTwGjS zUCo5N^-NAquB_;WM^SJ-AS$xLj*g4~hH4SQ8C7!$HM3(gGKgibqII2qd9%P_I`zQ~ zywv3mtk9F&p0oqa=y+J=ku;rMT$-AivNAFZ3=JV%U0nQY#>U3{V>*fpcunK7vsLWN zG|#1kQW6tYWzoa8hD%FIo_w)!an)wR(^FGf+1bU##Q_+Li;LbJqwDJ#u5mpdA0Ol6 z3L}GqQVI%41drdk_*4T~8e!(&L{zT+PnT=FD!VFpF|Hy|_U2co#{krlbcQW2&N4zWgCc zZVFBNIV)L`vA%AAlE_2-f>hVuj`Y}=bA4?;c-+!SseRtq*hoS`qGJsN`mV4(T!`kk z(IW0W1vz0rI72~vOG2bk&6O{MEYnET2v1BDrJz782p3m{gvVsiNV$G@TaJ#=Ch;{v zOEv#jk;Yej?~~p5unMEtN7fZiKc5y?T>J(2myee>H8u6rl zL8$DucKi7`jl>*`EOEG;Sw3OmV0>gl9i8pN&d$!$(^IxUl320z+%RrC%P6e6ZGKi( z)`vb0Ja-=-S5^_qd^&4yZ_*DB4-foi4%zpY7d>6wT(U|8D^fDD;h`ZgRtAGnP*9|+ zs;bZv<{k1oJB5~=tps>@cyN0VA;dnx1c$r3kkD(ZtHh-B>3{zG-v9X6oF5v3Et8g7 zT##qfC&1K#V>&H^#ASt{jb?7osBrO>(#pulII^=QWd!aAVr!XSLuwTj7qd$}nG}?l zBf+Gnr=y~wJ+sL~dFdD$9&BP0R1w5*gnuSD=dkhfm$6DhQneplUS6(6FkmD;$9c*u zQHMr&ygWaHfts`&Elxm4nD^cH-}yNT&Eda)UOdFPH^h;Gl8DA|O;gj;6v(9!31=4< zZTWPXWI189zC&B1qjFDH zgSD4fMs#$vB>y@u8ZI0xEK?B^7|t*rl-zMth7$R+Okphb$YS6$dxyYo93?N#B|c${ z$k-EaoNonLq;Z8Mi7O%~2<;R51L-u#RtGrT+bf1GoggbafZY?Xrx+Cz1NNx;R}B>o zRS4Xhc-dYWAOryrLzeK!7nA#(odg%iX;cDtf1D zAZ;9W_XEur`1C*~T3R!vl_2LD^N;+fy5~iKB)OEj*w)szHaHzX(j^bSoaC9Em6Z;I zp~1n;$tf{!C;Jl;G9HL2>YlZ{xj9vi1^sOA=$H`FkFu~wZP8aNC2?cSzbN_Yi#`1) zrj89~I-`obx`d+|?B!k>!&Q7|+)!`VFm2>x@Cink)vaT5 z3Q=}-{aUS{Wz;epMe_%o&U$EGB9`o>{2^T_`Je2hZvx|FDbkk@^JckS6lLLm3ZsTv zNZ}GllIe@$gcRSD|X z8pkehOvZ$dYLFnjeVZhlT^R);O$MgF)WVI}gF!Ak*| zqsk2@QL3o5Iyui}tF<#R>v&mejvkRPoRuQ8t|Hf(JFWi(Mu)bc3|s5^C+hSU6lnU6 zbada`JdHXBf)HvlN_Qu<^!Pi#0jQ7C~ysGt?R> z_eFEBY;edpn3Jr*aP>*VG3_<{h}Y%wI>0N(d3O@`dF(Ue9sl0Ij3i^#o`k6IN}{9L z`9}P$$A?!fqs&de@CoI1C_-C};rnicNpWyHer-?awQ*o+#VqU9uw}lJZ;lSJ_`$DK zL0qPXg}*Al%@>I#)SE^M?Ra!btwA%NXZtTf`15jd8b#sypTnEFcFp$IXkMS_Ln-*w zgYC5J3QbtWrtK4o5XHSk6BFyfV|OH^ByJOtWQE9N+wTp{GPZ3FT;+6Y3>Te;=F?{r z8||D{_e*KBCq{F8ln+W6*s$LAD`&ZaL;s>o&*oEO^vp0KrfMXSfdq}Y-89Id@7lfR zlgej@GdF7_d)@lu%#a(rMq*=ZMzmHFsiu^3MPKUDXp|Pe!DVooAQH?`9vMiPU3)7m zL)4sI*Lau*&M@SWrmKsLfjs`kIa(0?Z4D2HMB14zsXGJRS5W8OZNy$JV(@Bzn-!|C z>p8ItPKx#P-aC;#Ax5!X54x2qD=UKxnetIsMr0bWOm5S`q$Ska#BUoVu>rS~mBsdc z(WZQhM~8MsuCP<+3*4%VbIZp1elVb20&XQl#C;(~hoI|`k_853f+$D;jI%kKl)~uW z_uNX=ZW_ut4$nrjn!AZ6GulNYcILIg<)$wHw?l)kYY_r_8`2_B7c&@42TBPPFJA^! zs}vr(Bv*UZwcV;ZFU6fyaY*RKelX()8L`?WD4&v+=%q z_wn`6#`7^_ZA)Npd+lDRTAfM>i9t#Kq1%t(Kq?2U7!ZQj7haTo-<^7SjcZ@mPm>Af zH?VPro-`t2D7F_rh`W3-(8GS7M9JDN^?t#ndsTFyit5i}r*PwK(CGQJqK%J>@fznJ zS3!a1$Ak4o75;=~{vfESAhfL3*TFg0PSveNHuxiGnNNnpj8}%Qf*5`IOtfzJF}*RaSY3CEj?O$~z{$T&9Rioo54BPt5U&%G z-5+A~v9|Sb^XK~~;`{0MkGDOtci_KB%M+`@v(&W|VggBZDt4C9!j4|&spQeIl<(f` z-6ljlTszF1O{2{OiF2X^D9KUs4ek+fN~hlt)qD(0B5p-hn7onq?53E7#C{2}pR4S$ z^*T+4(|+0{+98FDd}@-{36FQNt|y6yK`Pn_|={4G;eyBbk3X zllm81H>TstUj?d@I5$BK97%(tYnL4oI%P7Xzt1upr$wyHFNS`t`Mk_!zh69di#&GR zT2`tk7S_9;5v4O@D*#%aQO9Fe`;tpnfK0Yu@Zb$nfJ<%7BUtRTu^M@`KwuI-NJ-;<91EbKgD zbE3U%wn`zf?ov1-_|KkuM;cfl#c?GR#{U5WLbNCJUSHe~6Z0*3#=7Q{>&J)`);puZ zlAto$iRV^{p||#!;pWkI+RW)gY9=y@JKmRB?8VQmPku_tZ7T9eYG`T=q<|gF0#!P@ zKgY++WZq8{5GU}5;E+Y&p_0lkMQU5WRrm?asfB9Mu%bLt zXGQEJMYMqw2bEyyzT^P#M4_DEC73uXqJ0Osd4QEqh&rB|C5HCeWBPJS=zUqTq|D+T z^1>{TmbHsye>wucj094&&;2!+HBV^bVBM((FSNg9s zf$Xzlr63NeufScN@3I`BLP?42JqTv4)$9DKqJ3XiJ~uZ6nz@6VHWT_Ai1hi<-=QwY zTD_~FbuKv2K>({(wt<@>Pa@zq8e<>(1{@vF-@sM{7#+;a=m`yIs$zhBd{=Bvthxgo zfa!)KwFhycW<AXqsN^W}oh8-QiwmogJ2KaqnU zXv~{BJ4V8u1MA_DC1Z={HM8@{mJ$3Z3LS%6%X>M*n+Kx&!lOui1Ja}R2b~<2AuzE5 zDsVO+$Gbwz;1=r?d9v@NZuk;-#PbR`i7253oMHusOkd(9ZvmmTX+8c_XCQV3V*=T9 z*pWUS+?L#l)!0C6rc*iq2d;-IGBUfRzmgmI3Wp_?&V?9dnu{2}=;*=3r6|55OCO8l z7)@lfFto1}0m7~Q<;CZMi%G#ki^8E0uVT8#k5r8N|FGq^f*i{BP?PN1PF+yu2&}Y7 z105WbVaGag1d4yjMoHOI4Mb+&AE(r6+duBZx6B09S`YZD*T7^Q2}SVY51e3XuvPaUO~nyA4SB=b1kQ@E~J|3pQDeQBB)-0`n+H__Mro;nr(axfj~XmtxF zi~-xFM%DFI&_b!~X_T%|cpT4pVKh5Ict)}`w*velKjV_9%mL9_8R`;@oWj0?|57Gu zN{0KJ-*?9ELfIy=jz@P1ioC0OAngDc8`f=98&DAhi&zWKL&)VHI5jsMDA)iwJ%&+L z6$Vv~$2gaC@am$%C~$pZAjBRhCrfJHi$3G0JCW+px;}{aT@u9^fFvl!QuK`pHjPD$ zQZU1FiVuupgvXRitam)BSRzpJVe2-sISuBuL+gNKWHSwZGJC%~74f%Qm0w=pBV<>& z_GYZPktLB$2CmG#jRK~WzNpnaKqC-3{`IJ|T<4!q9Oy@Wpw@wZ?Pky>w z;J5)_|8ZaKGd&fT?u3wpfBWw!RzOgwbHT^n=}*0>Ql)S&?Z>hkrpht0Z7i+hGbBHM zGB{_y?Xj#I3#JtXq7*w65JIsOB&j3*rLHvR^O$_>awI8wpyogH_fKqg8E^UmkQ%|0 zVeZ*2s3%B%^Z8r;7}YZyy2W?hrRPA(Q$M#`tjmm+XA&Vv_-f39ynyIC9>K0piU z3dIq&UpEU))Y|U({UK~vnqGj{DVa2YpnQ7gY#GV&0XPBB6&iwZffQemDO_K_!XZ&tim0&s6ElK1u{f2nt5w?{^K9H>DMHK?%^ z#pln>{gFHN-f&)`HYO@%H_RtF%=*b4OA2MaqHT_X5%=)7G5H(XC??xeTxskiKUx2b^yehpKI2yYQJ3ROE==Pw9VFFmrXbG2S7MQ4_;vs3;S;@BJEUd>|t zfct0@zOupozv3obd;K!X%op|uK>k3Doe3FHCnR~ZE$zyc*1ioidqv{j-N?E9H>;YD z!_7EZH2Noc5mH%lEdv$_seA=1BJJHs%;c7#eQNF1x;tpWduOVd^gOdRb;b4vNyUN6 z+&fgW_Eh!^+u^s@#vOt61AS99totm2M^Qz+K?I8%UB@s}wb0=Frf;PS9+btdAHd{iDkUXVsBrwz2wN~mpp|hZzyQ8}!Kem8Yc+W4v>H^E(O$)Hf2Ac4@{I?%pj{nTT`C_QV)${&0VBUGTs%Q|8U$U}Q;|Ef63E73zoA+24_ zZEX>!{8$5Tbo;BqVB=po zzXg48$DW@o2wxjQHJp){I1cD)qQ5XOATpubL-yoZLnQy6GxWphEGeO@;ot0614^;} z*Z5l0{;n@hUaZh(tD~WTtuv8u_U8hz!Uzio2L_k74oczch9{Vh6PiLwU?-S@zn{Zz z;gz!@H;77G^>YIQ2geZefr99j=S3Xim>uX>hT$_4@CTD!y)-vn>tl9(at=B9*Msci z#qb5fj;4VuQMHxc3C8JeYrQS$r3wmW{ko{rbnrE0NgM=^ZmV{)ed zXP}-wyjzNvzaLVpT)PrhNfe=wyzMF;{WNR2pU`2Ch=i3pDYIQfz}42}qU-ETXl13H zk4JgBE89OM1JdZv`nTKT9`ZJ5uOP8u&rsyb?(XdCn?1#|uq6ri^VLR!DNSQ6a>$el zy~dxTLxK4UJN zqqgCPN4PN7IcrJRO3^vy$EV-H`b2G9RqO1}>)+>?Pb*xfO}o#k*B%vaA_og+&%UHf ztrX#p5x68TC#P3FqlA*u=#f=!`7&CKh~&s(2+$xvJwoMJ3M-ny$$V+RBmlS7O*Kub z_zpNjuPm8(&9E6rTWA7A^fUPeUv?b|7aaB@-GJ_$<6GQEd=&d%{Ax@r@#`{SEZ&Hn z0`6BE!kUlqEzH$ZIoHD?jnX?!XT#xaJA}9S-#5BT&lrooXj-4HTA$5LOTIBIjuIY< ztpmk|L&QHJod6jLzrrxPXDtkxZ8m1}Wty#5`l_#Hs0iVP1Lga-zj_>@!Na#W9!`~f z%dY`LnQ4*^1u(~y}7wr z?QrK5UaB%2$Ln#^)?VWLF?Dyb(QeS{z`!d>1G1y&%|}dYQ~JXbDPp(Xvr_-V9>(J7 znv>QTw=1Wor{{dF*><@GbTF2*PX22omLiJiYqI{H-mE&;9aYLUK{NgxdO^bPua%bE z6&x)JN9*gOxw&0MQ~S^J``0y(WgUKNpMQOBt9LYBAsBJCnwOzmKQ?|_hFdOHPEon? z@p0K%S6D4}G^+l4IA5cur_UDgQC3nyK}5tfpVetI#zziL=e9DQ$QJp0zCB#8Zg2NA zHs0MEjyX2y@_IfPPk~X{KD$3%Dl6#o)xu*j=%HIZStuVqEz>M-QS}h^eoIYDd*0~} zSzcbAnVErrf<-3gWn*MSf-ECc!Z8*v!9?LOYIBln5)0?ymk<}<-P^mpxnc7U2oOv4 zD%do%w5`FM2m>&Aw&pH!0ZS3bjr-SQNFN2FmUjxOOKl6RmNs1ysAQr|X{Iv;@YalLeVNhFVuFzHrZV^vvfOX~ zF&nmFo2)ii;vZ##tn+h3zs`TB4!;C@3ruis>ywqi{x;KC$!14PIQizXBCe!2qnFaY$ry??v8 z@xCDG7wis3;GvNUj*uXve{)&K?#+SzF`1r}kul*G9G4JIT<>UZsic4)rn(}FAO%9G znb>6YU>+A$yI;GiC!MP%VxD96wtcC1-}J5QcGbtXdT0shbC_R()PXhe^#5`b7#JuM zLs~m^&}4bJ)!prWODioY2`w)#dk1!oE$t#eI5E6wZ=pQ6a55}J`*;8LUK>UimLLGuU{#NyOks~ZDEcH$g=bd!u zAwX!@52Ie1w>+{hUV)MFDk?JXJH*$r-ZFvr1P-y^YU5_Sig74T8E&LKt_MH zSr3hj9Dtn!Abo@Fe$umAD3kIifl#nAJ1r2HR90zAfnK~(ypj~QaJnxV+w|^1ELhAj z{IqMNukg&2zHpjfamxzEH_%= znQEwu_sHP7yuUb`;!(7=wz3QKh>P|T_HISsvC1w6qmm#NsQSb^a3JTxLFc9dkiOu{ z@&P1W!a9Gg@nB=QQY#-FMgV(UyI&38*hoVn@2;=Kj1bVn)YWF|^d|nM!!o^U>J$Vn zP}6upm9;7H&q=5KJJYCN8&E%gVYXiQW%^i}qEvs$xTzwGK=MZeLT74H&ta;fGcIgsmwjWc(SK&W&kbjN369m|Q zyt%Ka%s(JDKA?Os=l%wqh7Eppa$nW=a#U9SQHddFZc`HMccJL{IXk6!?L9;vqD<8! zaKd;@bi(g+CVrI@!olZEX-#N}4d{!NjNw)ZBMg^o8e9!V9U-U^9|17U@&X1;IS^_J zFspes|I+sum!m=z4!O}MBsj=hlKEe0b;^fZ0U~-z^y7BFS>Sz{uiQqhjk`c06DAhC zrk7$5KLsdI;_aWWwF|^_#rTsg?ZEZQ122Sr2W*)|y!RhvgdC`p1vK*VdIij8aOtI)2o( z3C`T$g&|-9&wRX2-o90Zi=8hsBeCw?9@%H=t9WkgS2?qA2h238M)!Su4@uu38%P3G z01;nuW@eOw`$r=RsbK1QxKn&g3;G)<7GGW-{sW)MomlPY?s)EIhQ>aB9aTt9+}$`a zK@`mf2?@z;8shT%h|G6k71irZxL*Wasjf;Zxps` zvg$Z6$C@*rl$x}Jd?nC*hW#HQvB5*L%cR!M zu&o!X~Ed_+Akx!!)Q^7h+tgO9cq`T`k83$4Mmv<^5N|T z-SdjsT`SV*#W~1dNA%-n?2FgMt&C!Kb#*1)u7vLA;O<7}mkq#vlsK}p*1=N*>&MHm z>?@{O+bd@YriIx>PoAUu+J!WaNcRNN_5Trsa6!J@>>Q8G>m%p(V~6?9u2&J6X+4wf zVyCg6_&dufCHn_JLi$m(83vvr*x?CrSQYdcoe98KV zRK;kHFn$d8tFISg*cj&v=SrZgbGs^c!BJVI450WI-}|loqOJVlK$JyLa<0W3HrII( zN5~#glc6NTFnBF(#EYE}N55CkD~kcMdIxQ{eMdqpj!-*#eKIcBLDe;=x9IK0H=VK1$jKx%&zAjp*cdIDNdq~aN*10H1ZI>R zw{?9IJ|sKZD_85D%dIoSm_vJ^EfSO1HNH-# z>}HB-F8p9Xme%Pd)><7I53Rq_?2wgH2c4UWP2yLJZ<@_3Nrj&{xIDaNKsiv=XfBf! zZ?TC0HiyX(VqYeiOKo5F+ch1{}fod+F zH4MXFjA~(=_QJQeQs#G=ydLe!ALt<^v0!{cyd;{l^sRieJAu}G<9)079CVW)MR!$O z!|y(CjW6NGM<&o-6y4>Pz>(RhkTnu>Hv(yHYm$uXOJO6J^Jlo4OPa8uG1kXlhy`Bf z`d4%1Fa-1hlP+KbdgCu3EJonRfo!QA6VgGwKsNWZ{cZl6(e7a*jH(kj$nR_xU$Uz$ zVFM@(_s#x}_3vVm(@%+}eHGYoJ5NedkNr$aDcZHAkUNM|cUclw975Hy9(9?iL+Gv+ zm;tgC2p?zB{zQRjLVOjz*olS_Rw(yS@~*HM6(O&{e~k+i&)f(i=+f<=E_fJe}g(EtmPXQoAI{$^@_7<4L{dC<<@(hCes!u3RWMkz;1 zwmy&CGi-Oq%7U>8sN^}=H*(yad2O!la+vGm3vr2Y)&BmwZ~N3rfo#KlB=b<2YYE%a zGdLWHG9z0`QsSsB2Q8ov*@0z5TW%V_`&GVhAAf{`JYWz-+zNj*g|+Jm(nkD=7zFiC zHc?ufiwTuYmBsshK^yBLNO}-r#kpCVK!){eBOAV=5iLyMAY~2C3qxqR?1b<6@D+9) zLk4_Z53@Wr!oOY7NwkH`j^)~eyV<2BT#>HRnc^z`qk^D^d~^M3AW$<>f~yk{ye9#_S9Oc9Xm;06K|JSYjL?H`?#!Fyj3Gl# zos>?zEbjDQdn9+km#r%t-i*T3-~#@oYN)s)fx`^P7UwGK4d9a&Ti;9EIAMVr`HSeO z4G1JQ6>XY(6&$y90wF)J9W9h$lD7ZR`9NFE%t%EQ`v)eGJcQvjXRzNK3x#ynnjQa}lSa+7 z<~Of$HtWE63^!dYb|rhcD&%ZD2vTHZ4&M*_eOxL*)&LZBz`9rFlcz2tCs!8pfxBN7 zUnCJzCUof);9`+9z(-IO=18lF9&IzLLI|3-q>if){#pTrFoqOR#x`>sc!O=d%cCc2 zF(RAVf$XzTZHST_)_qhR^pKzjjTr~CMk%T@5U?4YTlpihtI_#+@DwdLE31>1e^y=M zP4XYjXM{pi$S9(gO;VyrVSf_p>=XvGapDI zr-Cb4l0uqofug{vPJa~`2!plZ{qO__4#D-t*{_Sq>96*=W!r0oCt3*U^zk`_9N8;pOpbEmAw9!BPP(02Ehlg;?qhKT? zB`59ay9LGjMLXTBW;7L8_n`Oth&}dRsuPxe*SIP^o&bi%VO7p=p~w<2kBZxd+{RB@ zRn^dBwJ_#m+mexvEl=9z>{U>XD6kTU;(f@=Zxum1Oq7x*l^vb+*Fd}WGI^wJ(q#sC z=Q=;h^=Ogb7_OPCidfb>7~O**Cbed~p{u^QJNdMyIx99`8+(Dv%J((PpNe^96}*rN zJDRn4A!X(JkFv6VA3>R!rVjB7m}}s_G8_sJ>@n#1rYQpiPN-;%FgG0Fr%=Efj?$1` zU`>Glb+bM91`2Gz=y(B~gIA{m7WKjZ?pjX#$nXpxf?&CWo};8-IvCt@Mz+zuVMu2N z7LCG!^Y{YARtMTgb7#SJBLVW7Eh^)lAd^8EM|e59#ueSytL8G1OmN3kd zJOjqoJod<*XtJM5?5T2=bbr~eCHMGsEtHbtIYPwFsIl`W<@~E4RDV`G9(Y69VQbbA zcNy9x_s$dgOQbEQpf{C`#JIiMKJfmx)uW?7us0_zrz;{?P+ z{o67U_tX0khs$Qd3|tg6&@w&cl#%bAHy)=xw8ccHdpur+4gZ59%_e)g8Yyi?`-5Lj ze_JO$7}xQ18i3k?Zz1AmBl(ux?-nEXYD?Ykiw-v6vaAOPNfAhBgBn65LARiOmojTX zN=mv2ot%UQE;~_q)C@w`8X6i}ltSrPtyCImLsNIlPq?RW>LNlv=kJ%kR|~DJ>Ote^ zm9zH``N*f{nxWKaa$7g*FV>#lXOjpyuBhs3OC29b{K7+N;7Y>X;@P;p{x%1dRA@vO z@{7Ao(jMK~pL%iH`+;-bBm*8pX|D3VeQI z4hI&TeY(D+aKWbA5A^<;%BA4QDbTNpI#^|0!qGKufylCc{SYMs-Wd-?&v#E5MPcu& zZS@F=7QNq^X0DSDLY=&d)+34+#1{zNUR_kXT6Cbd!?(8!dO^*c|rnP%M6_`Z1Q^ z8KEXHg%s%De)q6ut1z5Nr}i=ui(#MV^a}rl0viJtHPPTpav!rXhO(b$kSIAd9kzg*DY@@MIcNFj?ekYbS06!IpH#`2xQ{ji0USnTdnB??BnVT;eue4d~1q zaEH5J-!FY)1iAJH(-HM_Cka9LJge$`6H09YeQnNVhfT+u5h1G=8OQpTrSH3`X^*Jc z_?4Az=9Z?Vt^W#>X4Tz|TMlXA8NVbqC!4^?Ms+`|T6Mpl+ZK8tll6*SK`JBejx;R9 z#dENr1>AV#ARzCu67H|t50j|Hxduw@mqeGvhYw4sdBNqdDHmVh;Gb|$mhO;?GK3p+ z6=bwhBP&l1$_^6@mlYSo6}sCq=ExAt%h5(aQB;hxc4u(5iOfdB2lyyCpn<0#;0iy( zKBNYfx3>PHaN*nPH^F)?uYR{fr{6RbJ5aM9uc#+6JX+nq2TWC@G zM8Zh+irGSKr2+@hvaI>#Xsn$bq=|I{2eT8K`@Z-K+jPIXSZ8pol8CFFTpYkhMB--JF+1=?cTS< zYVcD~MB_(_D#8)el9!f)C)g3lLW+`JOKWQiP^75eoQbMp)3thpV=>}rDJY!!LwQ5j z=+G2wNbKpv7_B(c-mrgAx5D;bW2{mFsAGnFLJDy30G|%hLW!pSgtXv7s3Hn2A!Rg& zzoJH7x?cP}sqm7N{dwfAN9;bS*y(G$$9IbgN_=XRY^6fTIN)XqKlN@6y4ubefKs?k zf$mshP3-T^Np`3bd67)GX+E2sJ9gqXe$j$pA}QJ|HK>sw=c`uP+C9xUr4UzmgdL3N z1xGn8^&LoTIb>Nvq-l7)f#$weDzU0RDygFsV|5tL@iN2R`HOy$_}a=<;k+0{0h$M= zwUA+)c?xeF7`T!{yDuVoB&Fb~s->ikfk6`)Be4+qyqezK*|S(0Iah4wFQc&KE%2fX_sui_^?iOF?Zh|ehCCZkEZ`fkvD0Qqag{NpHc6aF z+LS&;a9Nw`6beYBwLI&32_U^F|t`Pt|RuG9M_AJ7?=J(^j3#%}JVU|JG_e#x*2RZOhD zF-`e9xP{cGMzjx5r-qxA!XOZ2uOWHk)~rs!3!0qlheX~euH*(R5|%N1GE-~^ngzp1dU5|a z+NImRzI{&k2sH&$~vNB zGeSH)Xlzd3Kj$$aA>4Ir5d2C)O~G6`kY{@I`%?X3T4;zH7r`TFCWV@AOLrjqD!KL` zj3XnVvqF&@!J@P71;PX(Z&3Xu1lS@p28zxXdH(D`CO4AqO$T5zS)s7^=mj(f_Do~3 zLec5$>52C+gEXHte#5HPL}%8NjUh9_w$NzQNJBISMz|4>=h1NWL+*nhED*r5?3#g< z2TV%1TA}#5rMZJ|)|%*bL_d)g6jIT=WHtX|1ADZWJfjB%42GH6z+}+zZ4LwoePIII z%#FY|IN7e4-~EjkdSKiFLBiMnATSAKAB1p)1mM|N@>%JZ2i(+5)Bs|#{a_K3lhH@` zL8JYUkii#=ghLQkD4GY%6tO;in5+p91LHcxFqFX;H#J}x{!=9%2(fGC>y4P4>q(5x zYI1}cnga0>n)0oN763D@2X)o{tRX~>rT`Yu9{Xq~nXLr~fvBZ92xi8d>korG){n^w z1@;NpC6d&K4S`@`|7UU0y&0jCKp6ZsnL`l7O%0?C0t6=$GsS;e?*2yzy^a~JX9bu5 z+f5H@My3OKI}qn18QrdrqyImAa1D%CU?#3&LYnJ5hvoa`zP=EBVG{8{(P+f|()*2$S_66ATD%u*k|NNX!2rAPodT zDguRqT~YF%e&JwC2~H9;F9LL|O3EUe1AVcyy#LdP*4Q4K%_$`W2J8TfFt7uBVZq#C z7`=~B>2xR}z((-=&=(i&hy+`mPG=MhB!WeE`#!L>3INp6kWU&ycKJX}%?V_r|D^26 z5&RE21h~F}Ornww$_nr!{T%-bATHF6dSxBo23Yt1RPp^spe3yU@0RXp1U3>F6>YW% z;3%ey2O|a0^;SUxEe?*tioO40*DX!cUkz*-WJZzyME&jqj+cqmezh9k2_;uBntU6B zp(I>k7y-*pU!BOnA%ij6`5#@brjqS1BNB?h6GqdTZC8eZ$LzT@Wlooy9{n06qa%fD@zQsjyY7p z4M0qGOS8@a2Oi;n-eS(peFcGuL={@pGX=e)!IY4C;Fo3&eTdLEHPBB|0Ex#;Lfobh z7%-FmbSS3if3|H<;N(*Qz0I5}SOL*9v!U&13|6J=CYcS27evrD3&)oOC&-D$*{GQRf(P|jO{X>SpH z|6$md>8IJR-`CvSytK6R0@=fWQLcJd%)S1t27E&F;~BSy0h?;qEDL<(t{bKXQOZa1 z<^!RetmnFz@9;pULs7){!!6AlzV`k=K>r(-8hOW!1IEET?n@3 zATtG9uXjgea;#X@(rNcu#;gs57-OmD zpxoCS##nylqp+uIQxE3FwiE}cg#2tnIY~$eD1#LaK-3*_6?^fOIhWxlM8w$v4J_QM#ep5K0gHB{ zo?)fd_<=*MPNF=G1*Cx;s0J1*q%9Z11DXJmmfun!Q#mahR>R+E{x3bs0CuLq?zP(! zaLb9m)2Ny%4xT?k8AXJx7n8%!=RQCj{WnqzNN=4k7Dg_nA+HCuXMlmIS6uOUpD99V zX6*7&!bdTq>j+!>DgKjY|7rnI0SAWZ{{@{2V)b5P5k$`>zpN{DI-TqF+HSWqnM|+O zyId~KW)on+GO`h}n9XLCf^bJX9cgT{*~mtu8J!fX)yfJBS5YH3M3m7mnM{mCo&Yb> zIGfFGx7%nm%C*k|ivXFHV7~qR~tv)Rur%_s1>M@NF>hZGYU&w72h9KtJP3j-BnJE{_OcaW5e5cDs>XDA2pYVm!YC_(Lt?6ukO;zP|vh zAGS59jidjgC}5FbWEAqJP$(P@hfpX)o3unmVfW(kI1I|=a>wIwI2=Nv)9F;HRM-qf zeY@S}^Lf2q-|cp|NHUfboy}(Z{l3v?z@v{(_U?eAk|+%0_##FH?!XeH8!NnoWc%ZG;tyBYy3iixyzS>kd5P}o44OW%?U2=nS>?e$|e{I4sC z>|C}05D!b(427kyiE}2YhLu{~fF-+Bi%(8Y6qV!{X@DSM<;VxS2&JMZctG>t+}vDW zU;8b*{r!FL;^};`S65f{rRdt)+Ux7<{QSH@FrvKlPft&=N#0t?Np@kD^j=>1sFu)3;QKkl?=uTnP$r7TI=1HgTwqVrTk3q+#t0haAT0MakMR6WY4NGN84NEqX z4Aj%%;USl&439@7)$HsnY+YVn5)ObxZAoJZ$vHyO3 zv&nA!#Z3k_P)DSaALR&GXzpTig{UpxU9|dGLRG2m?r*Kuz~8NZ!1L6NSvZl|E=NwwFE3F(VO)VC(xo%zl@X(GbF6K?$sv{lC#LiUKmn(~Lu(y|i;^WQS6twY0^~jW7w8 zkW2Rxvbfz>Uw!p-VYL!Rsq(nJqsJv%=Npp7Bdm}TuG$GpDWT{>SbSEgkf$)O#OFEA zS!ELi+WV!89teui2#_#sP0`1~dhfmW%n>%I86FlFF~0x)`@~DsEk{@q)@dMT@uvLX zgAbTb;UgW!L2U_kc-;P!9?C84vBL?C011;|gRLH~FcWS+9v-%01Tw)^PfQ7^Xwv=P zL^D~uFS($c`KI4~`|Yp6K~RK7fF)a%;FHYg!){3aW>^prUsmF4vsIk1G{QO+gbgv6 zjV5Dyb8rw8p*2~x?wE5kM6xVP)AZUQeuM=YVTt|;Z|mdWAgG(1>t( z35B>B9M|#acL_aV9erVGJuD$ak2oW&VLeznRFLINLY7w4^l$5 zzOa-M3L*N(S*@Xwu(+O$t4I!qgM`&5LP%I>2l;&Z>8Fdu#!U&KC@g;IpH;rHEaSUL z39BE3kgyOA+Ce@jXt~@LMp(ycVI@g2nM~e!=N+!8=lZvB2aph=Ya}d$!%t+h#0_gG zuGbf7>Ie%}1z}C6Qx4`B?=~nQM0e;WQ{;1VbGzMMrfK%iBdpbG#h;9@xW$R}-x1!m z5JGeeszEsRLyAdqxV(Jn2&-z|oke_DyMDjlYu>##gwTvT+Ce_ys?o#27gjMVB$;ID zi)HE=a50%BXLW}VvK5j+H3%pFy6>to9}L2(a2A6sl1VOzV7pu{ZNNs7c_V}n&jd=b zNhc)p;fEh09Jb@}+@{-0!b(#|SXQ?SvgiWsksFd;A~Hr^b|1D7LPTQ=v7!{jLMDi0 zPz{$~jmI-QRhbXE!rJY2bi~%iSq#!hESU_Wjt;Xd;{lQ!j;gG%Ew+GPG0H7|pMK~5 zQ5ALPOuWwH!;CtU;fLAnnH13bD!GSRRp&_{>{B?rcy0+L;2ia!(F1{?5oCf=5DR)i zG9P^KVQwq_iO7n>D_>ZZ&O(GtgE4jgLk?Zz!n=pi0--%rJe-|foSj|%qn)2%m~2l! zOuet__cZS7cT|9F{mxMHWahmUs63_6kCh^5#C(ES&g@b{hntWQs;adWB`XNach)Yaw8PHfvKbc_7q;yP zA;dWo+S@JPqIFY}P+q;NEc;NBB$R^{bCb!4dXkiF6)!A^a8oBQ!1;OUPq0dpV~v{L zDt8XsCTCJlMCa6>H%#b1Oo$J&`zL&;?<;Jz-MkjoZuhcfc~xIxL{=d$N>Ejuu+r2Q z7Cc>87hT}LgkDSYox%TCeCG{!rqchJ{2#;gA8wHEtJl6-Z}3aJp}Myf#kZ9&tnLR{ zLWo`=BQ#;fm1oNk{lu`<@QU&xNs@SH`P!1XP68oeZ8qJ_VL7UbA6wPTUirdmlo-a( uwF}WB64th(>Gp_8cV~E&7K_=+6V~67BdWZ%jfcYk0000 Date: Wed, 15 May 2024 23:42:47 +0200 Subject: [PATCH 062/265] Fix wording of `static_over_final_class` rule's violation message (#5583) --- CHANGELOG.md | 4 +++- .../Rules/Idiomatic/StaticOverFinalClassRule.swift | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef970ac1c5..9a230fbf3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ #### Enhancements -* None. +* Clarify wording of `static_over_final_class` rule's violation message. + [SimplyDanny](https://github.com/SimplyDanny) + [#5570](https://github.com/realm/SwiftLint/issues/5570) #### Bug Fixes diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift index 7b501883d9..069acc1aaa 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift @@ -7,7 +7,7 @@ struct StaticOverFinalClassRule: Rule { static let description = RuleDescription( identifier: "static_over_final_class", name: "Static Over Final Class", - description: "Prefer `static` over `final class` for non-overridable declarations", + description: "Prefer `static` over `final class`", kind: .idiomatic, nonTriggeringExamples: [ Example(""" From 6499497a1bdc7deacb765e75d560f6b8c5e4de2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 15 May 2024 23:49:41 +0200 Subject: [PATCH 063/265] Update `swiftlint --help` output --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c1f5a68d5..8b5ee46e4a 100644 --- a/README.md +++ b/README.md @@ -455,8 +455,9 @@ OPTIONS: SUBCOMMANDS: analyze Run analysis rules docs Open SwiftLint documentation website in the default web browser - generate-docs Generates markdown documentation for all rules + generate-docs Generates markdown documentation for selected group of rules lint (default) Print lint warnings and errors + baseline Operations on existing baselines reporters Display the list of reporters and their identifiers rules Display the list of rules and their identifiers version Display the current version of SwiftLint From af142505087a5a38369e2310644737292d997936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 15 May 2024 23:50:37 +0200 Subject: [PATCH 064/265] Fix some markdownlint warnings --- README.md | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8b5ee46e4a..01f49e43ff 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ automatically or pin the dependency to a specific version: Use the following link to add SwiftLint as a Package Dependency to an Xcode project: -``` +```bash https://github.com/realm/SwiftLint ``` @@ -71,7 +71,7 @@ https://github.com/realm/SwiftLint ### [Homebrew](http://brew.sh) -``` +```bash brew install swiftlint ``` @@ -97,8 +97,8 @@ this directory to SCM such as Git is discouraged. ### [Mint](https://github.com/yonaskolb/mint) -``` -$ mint install realm/SwiftLint +```bash +mint install realm/SwiftLint ``` ### [Bazel](https://bazel.build) @@ -258,12 +258,15 @@ For unattended use (e.g. on CI), package plugin and macro validations can be disabled with either of the following: * Using `xcodebuild` options: - ``` + + ```bash -skipPackagePluginValidation -skipMacroValidation ``` + * Setting Xcode defaults: - ``` + + ```bash defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidation -bool YES defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES ``` @@ -282,10 +285,10 @@ arguments to build tool plugins (e.g., passing the config file path). If your project structure doesn't work directly with the build tool plugin, please consider one of the following options: -- To use a config file located outside the package/project directory, a config +* To use a config file located outside the package/project directory, a config file may be added to that directory specifying a parent config path to the other config file, e.g., `parent_config: path/to/.swiftlint.yml`. -- You can also consider the use of a +* You can also consider the use of a [Run Script Build Phase](#xcode-run-script-build-phase) in place of the build tool plugin. @@ -302,7 +305,7 @@ To do this, add a custom script to a `Run Script` phase of the `Build Phases` of the primary app target, after the `Compile Sources` phase. Use the following script implementation: -``` +```bash if command -v swiftlint >/dev/null 2>&1 then swiftlint @@ -311,8 +314,6 @@ else fi ``` -
- > [!TIP] > Uncheck `Based on dependency analysis` to run `swiftlint` on all incremental > builds, suppressing the unspecified outputs warning. @@ -323,7 +324,7 @@ fi > be required. Refer to the [installation](#installation) instructions for > more information. -**Consideration for Xcode 15.0+** +#### Consideration for Xcode 15.0 Xcode 15 made a significant change by setting the default value of the `ENABLE_USER_SCRIPT_SANDBOXING` build setting from `NO` to `YES`. @@ -335,13 +336,14 @@ To resolve this issue, it is necessary to manually set the `ENABLE_USER_SCRIPT_SANDBOXING` setting to `NO` for the specific target that SwiftLint is being configured for. -**Consideration for Apple Silicon** +#### Consideration for Apple Silicon If you installed SwiftLint via Homebrew on Apple Silicon, you might experience this warning: -> warning: SwiftLint not installed, download from -> https://github.com/realm/SwiftLint +```bash +warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint +``` That is because Homebrew on Apple Silicon installs the binaries into the `/opt/homebrew/bin` folder by default. To instruct Xcode where to find @@ -369,7 +371,7 @@ binary: ln -s /opt/homebrew/bin/swiftlint /usr/local/bin/swiftlint ``` -**Additional Considerations** +#### Additional Considerations If you wish to fix violations as well, your script could run `swiftlint --fix && swiftlint` instead of just `swiftlint`. This will mean @@ -417,17 +419,20 @@ swiftlint( SwiftLint is also available as a [Docker](https://www.docker.com/) image using `Ubuntu`. So just the first time you need to pull the docker image using the next command: + ```bash docker pull ghcr.io/realm/swiftlint:latest ``` Then following times, you just run `swiftlint` inside of the docker like: + ```bash docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest ``` This will execute `swiftlint` in the folder where you are right now (`pwd`), showing an output like: + ```bash $ docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest Linting Swift files in current working directory @@ -442,7 +447,7 @@ Here you have more documentation about the usage of ## Command Line Usage -``` +```bash $ swiftlint help OVERVIEW: A tool to enforce Swift style and conventions. @@ -511,7 +516,7 @@ You may also set the `TOOLCHAINS` environment variable to the reverse-DNS notation that identifies a Swift toolchain version: ```shell -$ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint --fix +TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint --fix ``` On Linux, SourceKit is expected to be located in @@ -536,6 +541,7 @@ Adjust `rev` to the SwiftLint version of your choice. `pre-commit autoupdate` can be used to update to the current version. SwiftLint can be configured using `entry` to apply fixes and fail on errors: + ```yaml - repo: https://github.com/realm/SwiftLint rev: 0.50.3 @@ -874,7 +880,7 @@ conflicts. Here's an example, assuming you have the following file structure: -``` +```txt ProjectRoot |_ .swiftlint.yml |_ .swiftlint_refinement.yml From 7957859f7edf34948c81f1c59258c46526803fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 15 May 2024 23:53:07 +0200 Subject: [PATCH 065/265] Use `txt` for `swiftlint --help` output to avoid odd coloring --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01f49e43ff..63c0e078a2 100644 --- a/README.md +++ b/README.md @@ -447,7 +447,7 @@ Here you have more documentation about the usage of ## Command Line Usage -```bash +```txt $ swiftlint help OVERVIEW: A tool to enforce Swift style and conventions. From fe9763104de752267320871b7c8833716e956c9d Mon Sep 17 00:00:00 2001 From: "Garric G. Nahapetian" Date: Wed, 15 May 2024 22:42:40 -0700 Subject: [PATCH 066/265] Move Xcode Run Script Build Phase note (#5584) --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 63c0e078a2..0065f065c6 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,12 @@ plugin, please consider one of the following options: ### Xcode Run Script Build Phase +> [!NOTE] +> Based upon the installation method used, the shell command syntax in the +> Run Script Build Phase may be different or additional configuration could +> be required. Refer to the [installation](#installation) instructions for +> more information. + If the build tool plugin does not work for your project setup or when additional custom setup is required, SwiftLint can be added as a Run Script Build Phase. This is useful when a project setup relies on the `--config` @@ -318,12 +324,6 @@ fi > Uncheck `Based on dependency analysis` to run `swiftlint` on all incremental > builds, suppressing the unspecified outputs warning. -> [!NOTE] -> Based upon the installation method used, the shell command syntax in the -> Run Script Build Phase may be different or additional configuration could -> be required. Refer to the [installation](#installation) instructions for -> more information. - #### Consideration for Xcode 15.0 Xcode 15 made a significant change by setting the default value of the From 161391de27f0465ae1f6d89f3433d9ac58cb9cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 16 May 2024 18:48:47 +0200 Subject: [PATCH 067/265] Treat conditional code as if it was always active (#5581) --- CHANGELOG.md | 6 ++ .../UnneededSynthesizedInitializerRule.swift | 56 ++++++++++--------- ...edSynthesizedInitializerRuleExamples.swift | 53 +++++++++++++++++- 3 files changed, 89 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a230fbf3a..836a357928 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,12 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5568](https://github.com/realm/SwiftLint/issues/5568) +* Treat condionally activatable variable declarations and initializer as if + they were always active in `unneeded_synthesized_initializer` rule to avoid + compilation issues when unexpected items are there after all. + [SimplyDanny](https://github.com/SimplyDanny) + [#5574](https://github.com/realm/SwiftLint/issues/5574) + * Silence `unused_enumerated` rule when `$0` in a closure is explicitly unpacked. [SimplyDanny](https://github.com/SimplyDanny) [#5573](https://github.com/realm/SwiftLint/issues/5573) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift index 92456c40cd..d40aa8b977 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift @@ -71,42 +71,48 @@ private extension UnneededSynthesizedInitializerRule { } } +private final class ElementCollector: SyntaxAnyVisitor { + var initializers = [InitializerDeclSyntax]() + var varDecls = [VariableDeclSyntax]() + + override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind { + node.isProtocol((any NamedDeclSyntax).self) ? .skipChildren : .visitChildren + } + + override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { + initializers.append(node) + return .skipChildren + } + + override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { + varDecls.append(node) + return .skipChildren + } +} + private extension StructDeclSyntax { var unneededInitializers: [InitializerDeclSyntax] { - let unneededInitializers = findUnneededInitializers() - let initializersCount = memberBlock.members.filter { $0.decl.is(InitializerDeclSyntax.self) }.count - if unneededInitializers.count == initializersCount { + let collector = ElementCollector(viewMode: .sourceAccurate) + collector.walk(memberBlock) + let unneededInitializers = findUnneededInitializers(in: collector) + if unneededInitializers.count == collector.initializers.count { return unneededInitializers } return [] } - // Collects all of the initializers that could be replaced by the synthesized + // Finds all of the initializers that could be replaced by the synthesized // memberwise or default initializer(s). - private func findUnneededInitializers() -> [InitializerDeclSyntax] { - var storedProperties: [VariableDeclSyntax] = [] - var initializers: [InitializerDeclSyntax] = [] - - for memberItem in memberBlock.members { - let member = memberItem.decl - // Collect all stored variables into a list. - if let varDecl = member.as(VariableDeclSyntax.self) { - if !varDecl.modifiers.contains(keyword: .static) { - storedProperties.append(varDecl) - } - } else if let initDecl = member.as(InitializerDeclSyntax.self), - initDecl.optionalMark == nil, - !initDecl.hasThrowsOrRethrowsKeyword { - // Collect any possible redundant initializers into a list. - initializers.append(initDecl) - } + private func findUnneededInitializers(in collector: ElementCollector) -> [InitializerDeclSyntax] { + let initializers = collector.initializers.filter { + $0.optionalMark == nil && !$0.hasThrowsOrRethrowsKeyword } - + let varDecls = collector.varDecls.filter { !$0.modifiers.contains(keyword: .static) } return initializers.filter { - self.initializerParameters($0.parameterList, match: storedProperties) && + self.initializerParameters($0.parameterList, match: varDecls) && (($0.parameterList.isEmpty && hasNoSideEffects($0.body)) || - initializerBody($0.body, matches: storedProperties)) && - initializerModifiers($0.modifiers, match: storedProperties) && !$0.isInlinable + initializerBody($0.body, matches: varDecls)) && + initializerModifiers($0.modifiers, match: varDecls) && !$0.isInlinable } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift index dfdb0d4437..868022aa67 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift @@ -197,7 +197,44 @@ enum UnneededSynthesizedInitializerRuleExamples { print("perform side effect") } } - """) + """), + Example(""" + struct Foo { + let bar: Int + + init(bar: Int) { + self.bar = bar + } + init?() { + return nil + } + } + """), + // Treat conditional code as if it was active. + Example(""" + struct Foo { + var bar: String + + init(bar: String) { + self.bar = bar + } + + #if DEBUG + init() { + self.bar = "" + } + #endif + } + """, excludeFromDocumentation: true), + Example(""" + struct Foo { + #if DEBUG + var bar: String + #endif + + init() {} + } + """, excludeFromDocumentation: true) ] static let triggering = [ @@ -328,6 +365,20 @@ enum UnneededSynthesizedInitializerRuleExamples { } } } + """), + Example(""" + struct Foo { + let i: Int + struct Bar { + let j: Int + ↓init(j: Int) { + self.j = j + } + } + ↓init(i: Int) { + self.i = i + } + } """) ] From de66fea453ba730a3636328dc5185226c026418d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 16 May 2024 19:31:26 +0200 Subject: [PATCH 068/265] Completely exclude the binary target from the Linux build (#5585) --- Package.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index 4bd04de7ff..47dd59fe71 100644 --- a/Package.swift +++ b/Package.swift @@ -143,11 +143,6 @@ let package = Package( "SwiftLintTestHelpers" ] ), - .binaryTarget( - name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.55.0/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "0a689bf8f851e4ab06bfce1bf5a01840984473ef720a63916611664e442499d6" - ), .macro( name: "SwiftLintCoreMacros", dependencies: [ @@ -167,3 +162,13 @@ let package = Package( ), ] ) + +#if os(macOS) +package.targets.append( + .binaryTarget( + name: "SwiftLintBinary", + url: "https://github.com/realm/SwiftLint/releases/download/0.55.0/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "0a689bf8f851e4ab06bfce1bf5a01840984473ef720a63916611664e442499d6" + ) +) +#endif From 8bc8160416a6b18e261ed564f531c30094e1239a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 16 May 2024 21:21:24 +0200 Subject: [PATCH 069/265] Mark rule registry as sendable (#5587) --- Source/SwiftLintCore/Models/RuleRegistry.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintCore/Models/RuleRegistry.swift b/Source/SwiftLintCore/Models/RuleRegistry.swift index 74c56e73a9..016ccd7240 100644 --- a/Source/SwiftLintCore/Models/RuleRegistry.swift +++ b/Source/SwiftLintCore/Models/RuleRegistry.swift @@ -1,5 +1,5 @@ /// Container to register and look up SwiftLint rules. -public final class RuleRegistry { +public final class RuleRegistry: @unchecked Sendable { private var registeredRules = [any Rule.Type]() /// Shared rule registry instance. From 2892e407a539c83d76f6a23adba2cf95d6508c7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 21:23:00 +0200 Subject: [PATCH 070/265] Bump rexml from 3.2.5 to 3.2.8 (#5588) --- Gemfile.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 51e0719663..a7b45bde06 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -122,7 +122,8 @@ GEM public_suffix (4.0.7) rchardet (1.8.0) redcarpet (3.6.0) - rexml (3.2.5) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (4.2.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) @@ -133,6 +134,7 @@ GEM faraday (>= 0.17.3, < 3) sqlite3 (1.7.2-arm64-darwin) sqlite3 (1.7.2-x86_64-linux) + strscan (3.1.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) typhoeus (1.4.0) From b515723b16eba33f15c4677ee65f3fef2ce8c255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 16 May 2024 21:42:01 +0200 Subject: [PATCH 071/265] Release 0.55.1 --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 836a357928..dd838b4ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Main +## 0.55.1: Universal Washing Powder #### Breaking diff --git a/MODULE.bazel b/MODULE.bazel index 42c7d4fd66..b13e876349 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "swiftlint", - version = "0.55.0", + version = "0.55.1", compatibility_level = 1, repo_name = "SwiftLint", ) diff --git a/Package.swift b/Package.swift index 47dd59fe71..f1e4b2208a 100644 --- a/Package.swift +++ b/Package.swift @@ -167,8 +167,8 @@ let package = Package( package.targets.append( .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.55.0/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "0a689bf8f851e4ab06bfce1bf5a01840984473ef720a63916611664e442499d6" + url: "https://github.com/realm/SwiftLint/releases/download/0.55.1/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "722a705de1cf4e0e07f2b7d2f9f631f3a8b2635a0c84cce99f9677b38aa4a1d6" ) ) #endif diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index b92a8e6ae9..39d1ef4920 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -4,5 +4,5 @@ public struct Version { public let value: String /// The current SwiftLint version. - public static let current = Version(value: "0.55.0") + public static let current = Version(value: "0.55.1") } From 21bdaf078490c8b1ae7538d1366c5758f8fe7aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 16 May 2024 21:43:52 +0200 Subject: [PATCH 072/265] Add new changelog section --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd838b4ddc..4dcb854369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Main + +#### Breaking + +* None. + +#### Experimental + +* None. + +#### Enhancements + +* None. + +#### Bug Fixes + +* None. + ## 0.55.1: Universal Washing Powder #### Breaking From 219f47cfaaa30e3b6f2fca1ceac49600bf247d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 16 May 2024 21:55:32 +0200 Subject: [PATCH 073/265] Fix indentation --- tools/update-artifact-bundle.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/update-artifact-bundle.sh b/tools/update-artifact-bundle.sh index 09bac52039..c98ef2b4e2 100755 --- a/tools/update-artifact-bundle.sh +++ b/tools/update-artifact-bundle.sh @@ -7,9 +7,9 @@ readonly artifactbundle="SwiftLintBinary-macos.artifactbundle.zip" readonly checksum="$(shasum -a 256 "$artifactbundle" | cut -d " " -f1 | xargs)" sed -i '' \ - "s/.*\/releases\/download\/.*/ url: \"https:\/\/github.com\/realm\/SwiftLint\/releases\/download\/$version\/SwiftLintBinary-macos\.artifactbundle\.zip\",/g" \ + "s/.*\/releases\/download\/.*/ url: \"https:\/\/github.com\/realm\/SwiftLint\/releases\/download\/$version\/SwiftLintBinary-macos\.artifactbundle\.zip\",/g" \ Package.swift sed -i '' \ - "s/.*checksum.*/ checksum: \"$checksum\"/g" \ + "s/.*checksum.*/ checksum: \"$checksum\"/g" \ Package.swift From d7cf2fe631651cbd0cc5a7d58c38f80e1a4a6306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 16 May 2024 22:55:52 +0200 Subject: [PATCH 074/265] Adapt and templatize test reference (#5589) --- Tests/SwiftLintFrameworkTests/ReporterTests.swift | 5 ++++- .../Resources/CannedSARIFReporterOutput.json | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Tests/SwiftLintFrameworkTests/ReporterTests.swift b/Tests/SwiftLintFrameworkTests/ReporterTests.swift index 20b91c4a04..9aaed87757 100644 --- a/Tests/SwiftLintFrameworkTests/ReporterTests.swift +++ b/Tests/SwiftLintFrameworkTests/ReporterTests.swift @@ -98,7 +98,10 @@ final class ReporterTests: SwiftLintTestCase { } func testSARIFReporter() { - let expectedOutput = stringFromFile("CannedSARIFReporterOutput.json") + let expectedOutput = stringFromFile("CannedSARIFReporterOutput.json").replacingOccurrences( + of: "${SWIFT_LINT_VERSION}", + with: SwiftLintCore.Version.current.value + ).trimmingCharacters(in: .whitespacesAndNewlines) let result = SARIFReporter.generateReport(generateViolations()) XCTAssertEqual(expectedOutput, result) } diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json index 590e84732c..b12a09a47b 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json @@ -82,12 +82,12 @@ ], "tool" : { "driver" : { - "informationUri" : "https:\/\/github.com\/realm\/SwiftLint\/blob\/0.55.0\/README.md", + "informationUri" : "https:\/\/github.com\/realm\/SwiftLint\/blob\/${SWIFT_LINT_VERSION}\/README.md", "name" : "SwiftLint", - "semanticVersion" : "0.55.0" + "semanticVersion" : "${SWIFT_LINT_VERSION}" } } } ], "version" : "2.1.0" -} \ No newline at end of file +} From ebf7c708b7546ddc4e75c6f5832be1ad137d57f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 17 May 2024 22:29:26 +0200 Subject: [PATCH 075/265] Stop triggering `mark` rule in the middle of another comment (#5593) --- CHANGELOG.md | 5 ++++- Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift | 7 +++---- .../Rules/Lint/MarkRuleExamples.swift | 8 ++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dcb854369..194b8df81d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,10 @@ #### Bug Fixes -* None. +* Stop triggering `mark` rule on "mark" comments in the middle of another + comment. + [SimplyDanny](https://github.com/SimplyDanny) + [#5592](https://github.com/realm/SwiftLint/issues/5592) ## 0.55.1: Universal Washing Powder diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift index 95379a476a..1a5b48e98f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift @@ -47,9 +47,8 @@ private struct ViolationResult { private extension TokenSyntax { private enum Mark { static func lint(in text: String) -> [() -> String] { - let range = NSRange(text.startIndex.. Bool { - regex(goodPattern).firstMatch(in: text, range: range) != nil + range.lowerBound != 0 || regex(goodPattern).firstMatch(in: text, range: text.fullNSRange) != nil } private static let goodPattern = [ diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift index 5686bb1a51..5ae104dc12 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift @@ -20,6 +20,14 @@ internal struct MarkRuleExamples { // MARK: good } """), + Example(""" + /// Comment + /// `xxx://marketingOptIn` + struct S {} + + /// //marketingOptIn + struct T {} + """, excludeFromDocumentation: true), issue1749Example ] From b42f6ffe77159aed1060bf607212a0410c7623b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 17 May 2024 23:06:09 +0200 Subject: [PATCH 076/265] Keep initializers with attributed parameters in `unneeded_synthesized_initializer` rule (#5594) --- CHANGELOG.md | 5 +++++ .../Idiomatic/UnneededSynthesizedInitializerRule.swift | 2 +- .../UnneededSynthesizedInitializerRuleExamples.swift | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 194b8df81d..376c93f074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5592](https://github.com/realm/SwiftLint/issues/5592) +* Keep initializers with attributed parameters in + `unneeded_synthesized_initializer` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5153](https://github.com/realm/SwiftLint/issues/5153) + ## 0.55.1: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift index d40aa8b977..dd789bae62 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift @@ -132,7 +132,7 @@ private extension StructDeclSyntax { } for (idx, parameter) in initializerParameters.enumerated() { - guard parameter.secondName == nil else { + guard parameter.secondName == nil, parameter.attributes.isEmpty else { return false } let property = storedProperties[idx] diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift index 868022aa67..507ade2774 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift @@ -198,6 +198,15 @@ enum UnneededSynthesizedInitializerRuleExamples { } } """), + Example(""" + struct Foo { + var bar: Int + + init(@Clamped bar: Int) { + self.bar = bar + } + } + """), Example(""" struct Foo { let bar: Int From da4ba02d162ee1044aa760bb9c0645ffb6295850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 18 Jun 2024 23:23:11 +0200 Subject: [PATCH 077/265] Add workflow to sync plugins upon change --- .github/plugins-sync.yml | 2 ++ .github/workflows/plugins-sync.yml | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 .github/plugins-sync.yml create mode 100644 .github/workflows/plugins-sync.yml diff --git a/.github/plugins-sync.yml b/.github/plugins-sync.yml new file mode 100644 index 0000000000..87c26302d6 --- /dev/null +++ b/.github/plugins-sync.yml @@ -0,0 +1,2 @@ +SimplyDanny/SwiftLintPlugins: + - Plugins/ diff --git a/.github/workflows/plugins-sync.yml b/.github/workflows/plugins-sync.yml new file mode 100644 index 0000000000..895f0eea9a --- /dev/null +++ b/.github/workflows/plugins-sync.yml @@ -0,0 +1,23 @@ +name: Plugins Sync + +on: + push: + branches: + - main + paths: + - 'Plugins/**' + workflow_dispatch: + +jobs: + sync: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run file sync + uses: BetaHuhn/repo-file-sync-action@v1 + with: + GH_PAT: ${{ secrets.SIMPLYDANNY_PLUGINS_SYNC }} + IS_FINE_GRAINED: true + CONFIG_PATH: .github/plugins-sync.yml + SKIP_PR: true From 5b2f3a4b7c06dec977dafb46ff3a7eaaa083c070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 19 Jun 2024 00:03:10 +0200 Subject: [PATCH 078/265] Customize commit message created by sync job --- .github/workflows/plugins-sync.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/plugins-sync.yml b/.github/workflows/plugins-sync.yml index 895f0eea9a..e517bd3158 100644 --- a/.github/workflows/plugins-sync.yml +++ b/.github/workflows/plugins-sync.yml @@ -21,3 +21,4 @@ jobs: IS_FINE_GRAINED: true CONFIG_PATH: .github/plugins-sync.yml SKIP_PR: true + COMMIT_PREFIX: 🔄 Workflow in 'realm/SwiftLint' From 61e92fea011e74fffa766076fcf3c4a996a2f467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 19 Jun 2024 22:53:48 +0200 Subject: [PATCH 079/265] Add workflow that releases the plugins for the same tag --- .github/workflows/plugins-release.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/plugins-release.yml diff --git a/.github/workflows/plugins-release.yml b/.github/workflows/plugins-release.yml new file mode 100644 index 0000000000..66b4c664e6 --- /dev/null +++ b/.github/workflows/plugins-release.yml @@ -0,0 +1,17 @@ +name: Plugins Release + +on: + release: + types: [released] + +jobs: + dispatch: + runs-on: ubuntu-latest + steps: + - name: Dispatch release of plugins package + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.SIMPLYDANNY_PLUGINS_SYNC }} + repository: SimplyDanny/SwiftLintPlugins + event-type: swiftlint-release + client-payload: '{"title": "${{ github.event.release.name }}", "tag": "${{ github.ref_name }}"}' From bab4c12fc777252d5fc24f1b14a1cc60fe7733c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 20 Jun 2024 22:08:01 +0200 Subject: [PATCH 080/265] Move command plugin section --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0065f065c6..0dd940d748 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ presentation recorded January 9th, 2017 by JP Simard (transcript provided): ### [Swift Package Manager](https://github.com/apple/swift-package-manager) SwiftLint can be used as a [command plugin](#swift-package-command-plugin) -or a [build tool plugin](#swift-package-build-tool-plugins). +or a [build tool plugin](#build-tool-plugins). Add @@ -192,18 +192,7 @@ To build SwiftLint, clone this repository and run `make install`. > confusing results, especially when executing with `--fix`/`--autocorrect` > command line arguments. -### Swift Package Command Plugin - -> [!NOTE] -> Requires installing via [Swift Package Manager](#swift-package-manager). - -The command plugin enables running SwiftLint from the command line as follows: - -```shell -swift package plugin swiftlint -``` - -### Swift Package Build Tool Plugins +### Build Tool Plugins SwiftLint can be used as a build tool plugin for both [Swift Package projects](#swift-package-projects) @@ -238,6 +227,17 @@ To do this, add the plugin to the target(s) to be linted as follows: ), ``` +### Swift Package Command Plugin + +> [!NOTE] +> Requires installing via [Swift Package Manager](#swift-package-manager). + +The command plugin enables running SwiftLint from the command line as follows: + +```shell +swift package plugin swiftlint +``` + ### Xcode Projects > [!NOTE] From 4c11a10cb8a41171a01509533c2c4317b3727d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 20 Jun 2024 22:42:56 +0200 Subject: [PATCH 081/265] Recommend SwiftLintPlugins in the README --- README.md | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0dd940d748..024c39a85e 100644 --- a/README.md +++ b/README.md @@ -42,18 +42,35 @@ or a [build tool plugin](#build-tool-plugins). Add ```swift -.package(url: "https://github.com/realm/SwiftLint.git", from: "") +.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", from: "") ``` to your `Package.swift` file to consume the latest release of SwiftLint automatically or pin the dependency to a specific version: ```swift -.package(url: "https://github.com/realm/SwiftLint.git", exact: "") +.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", exact: "") ``` +Therein, replace `` with the desired minimum or exact version. + > [!NOTE] -> Replace `` with the desired minimum or exact version. +> Consuming the plugins directly from the SwiftLint repository comes +> with several drawbacks. To avoid them and reduce the overhead imposed, it's +> highly recommended to consume the plugins from the dedicated +> [SwiftLintPlugins repository](https://github.com/SimplyDanny/SwiftLintPlugins) +> even though plugins from the SwiftLint repository are also absolutely +> functional. To do so, just use the URL `https://github.com/realm/SwiftLint` +> instead. +> +> However, [SwiftLintPlugins](https://github.com/SimplyDanny/SwiftLintPlugins) +> facilitates plugin adoption massively. It lists some of the reasons that +> drive the plugins as provided by SwiftLint itself very troublesome. Since +> the plugin code and the releases are kept in sync, there is no difference +> in functionality between the two, but you spare yourself a lot of time and +> trouble using the dedicated plugins repository. +> +> This document assumes you're relying on SwiftLintPlugins. ### [Xcode Package Dependency](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) @@ -61,14 +78,9 @@ Use the following link to add SwiftLint as a Package Dependency to an Xcode project: ```bash -https://github.com/realm/SwiftLint +https://github.com/SimplyDanny/SwiftLintPlugins ``` -> [!IMPORTANT] -> Do not add the `SwiftLintFramework` library or the -> `swiftlint` executable to any targets. Ensure `None` -> is selected when asked to choose package products. - ### [Homebrew](http://brew.sh) ```bash @@ -223,7 +235,7 @@ To do this, add the plugin to the target(s) to be linted as follows: ```swift .target( ... - plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLint")] + plugins: [.plugin(name: "SwiftLintBuildToolPlugin", package: "SwiftLintPlugins")] ), ``` From 3e8a0516b248cfa4f51d7caa321c842013c42572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 20 Jun 2024 23:34:24 +0200 Subject: [PATCH 082/265] Fix wording and sentence relations --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 024c39a85e..1ff57394b8 100644 --- a/README.md +++ b/README.md @@ -58,10 +58,10 @@ Therein, replace `` with the desired minimum or exact version. > Consuming the plugins directly from the SwiftLint repository comes > with several drawbacks. To avoid them and reduce the overhead imposed, it's > highly recommended to consume the plugins from the dedicated -> [SwiftLintPlugins repository](https://github.com/SimplyDanny/SwiftLintPlugins) +> [SwiftLintPlugins repository](https://github.com/SimplyDanny/SwiftLintPlugins), > even though plugins from the SwiftLint repository are also absolutely -> functional. To do so, just use the URL `https://github.com/realm/SwiftLint` -> instead. +> functional. If the plugins from SwiftLint are preferred, just use the URL +> `https://github.com/realm/SwiftLint` in the package declarations above. > > However, [SwiftLintPlugins](https://github.com/SimplyDanny/SwiftLintPlugins) > facilitates plugin adoption massively. It lists some of the reasons that From 47ef99c802169f038c45ae56dfef46f1ff96e11e Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 22 Jun 2024 08:38:38 +0100 Subject: [PATCH 083/265] Remove deprecated path argument (#5614) --- CHANGELOG.md | 4 +++- README.md | 4 +++- Source/swiftlint/Commands/Analyze.swift | 16 ++------------- Source/swiftlint/Commands/Lint.swift | 20 ++----------------- .../Helpers/LintOrAnalyzeArguments.swift | 4 ---- 5 files changed, 10 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 376c93f074..658c2e70ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ #### Breaking -* None. +* The deprecated `--path` argument has now been removed completely. + [Martin Redington](https://github.com/mildm8nnered) + [#5614](https://github.com/realm/SwiftLint/issues/5614) #### Experimental diff --git a/README.md b/README.md index 1ff57394b8..c19176c0a5 100644 --- a/README.md +++ b/README.md @@ -680,7 +680,9 @@ opt_in_rules: # some rules are turned off by default, so you need to opt-in analyzer_rules: # rules run by `swiftlint analyze` - explicit_self -included: # case-sensitive paths to include during linting. `--path` is ignored if present +# Case-sensitive paths to include during linting. Directory paths supplied on the +# command line will be ignored. +included: - Sources excluded: # case-sensitive paths to ignore during linting. Takes precedence over `included` - Carthage diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index ac74e32f3f..5b14d891ac 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -7,8 +7,6 @@ extension SwiftLint { @OptionGroup var common: LintOrAnalyzeArguments - @Option(help: pathOptionDescription(for: .analyze)) - var path: String? @Flag(help: quietOptionDescription(for: .analyze)) var quiet = false @Option(help: "The path of the full xcodebuild log to use when running AnalyzerRules.") @@ -19,18 +17,8 @@ extension SwiftLint { var paths = [String]() func run() async throws { - let allPaths: [String] - if let path { - // TODO: [06/14/2024] Remove deprecation warning after ~2 years. - Issue.genericWarning( - "The --path option is deprecated. Pass the path(s) to analyze last to the swiftlint command." - ).print() - allPaths = [path] + paths - } else if !paths.isEmpty { - allPaths = paths - } else { - allPaths = [""] // Analyze files in current working directory if no paths were specified. - } + // Analyze files in current working directory if no paths were specified. + let allPaths = paths.isNotEmpty ? paths : [""] let options = LintOrAnalyzeOptions( mode: .analyze, paths: allPaths, diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index e3ec05f07a..b15cf9e602 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -7,8 +7,6 @@ extension SwiftLint { @OptionGroup var common: LintOrAnalyzeArguments - @Option(help: pathOptionDescription(for: .lint)) - var path: String? @Flag(help: "Lint standard input.") var useSTDIN = false @Flag(help: quietOptionDescription(for: .lint)) @@ -27,26 +25,12 @@ extension SwiftLint { func run() async throws { Issue.printDeprecationWarnings = !silenceDeprecationWarnings - if path != nil { - // TODO: [06/14/2024] Remove deprecation warning after ~2 years. - Issue.genericWarning( - "The --path option is deprecated. Pass the path(s) to lint last to the swiftlint command." - ).print() - } - if common.fix, let leniency = common.leniency { Issue.genericWarning("The option --\(leniency) has no effect together with --fix.").print() } - let allPaths = - if let path { - [path] + paths - } else if !paths.isEmpty { - paths - } else { - [""] // Lint files in current working directory if no paths were specified. - } - + // Lint files in current working directory if no paths were specified. + let allPaths = paths.isNotEmpty ? paths : [""] let options = LintOrAnalyzeOptions( mode: .lint, paths: allPaths, diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift index e7ea89cf05..19d3a416f1 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -55,10 +55,6 @@ struct LintOrAnalyzeArguments: ParsableArguments { // It'd be great to be able to parameterize an `@OptionGroup` so we could move these options into // `LintOrAnalyzeArguments`. -func pathOptionDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp { - ArgumentHelp(visibility: .hidden) -} - func pathsArgumentDescription(for mode: LintOrAnalyzeMode) -> ArgumentHelp { "List of paths to the files or directories to \(mode.imperative)." } From ff96d164e46d460e9f3018b10da03365c4e6ee11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 22 Jun 2024 09:56:43 +0200 Subject: [PATCH 084/265] Split violation reason and provide a better description (#5627) --- .../Idiomatic/StaticOverFinalClassRule.swift | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift index 069acc1aaa..558e01676c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift @@ -7,7 +7,11 @@ struct StaticOverFinalClassRule: Rule { static let description = RuleDescription( identifier: "static_over_final_class", name: "Static Over Final Class", - description: "Prefer `static` over `final class`", + description: """ + Prefer `static` over `class` when the declaration is not allowed to be overridden \ + in child classes due to its context being final. Likewise, the compiler complains \ + about `open` being used in `final` classes. + """, kind: .idiomatic, nonTriggeringExamples: [ Example(""" @@ -100,12 +104,21 @@ private extension StaticOverFinalClassRule { // MARK: - private func validateNode(at position: AbsolutePosition, with modifiers: DeclModifierListSyntax) { - if modifiers.contains(keyword: .final), - modifiers.contains(keyword: .class) { - violations.append(position) - } else if modifiers.contains(keyword: .class), - classContexts.peek() == true { - violations.append(position) + let reason: String? = if modifiers.contains(keyword: .final), modifiers.contains(keyword: .class) { + "Prefer `static` over `final class`" + } else if modifiers.contains(keyword: .class), classContexts.peek() == true { + "Prefer `static` over `class` in a final class" + } else { + nil + } + if let reason { + violations.append( + ReasonedRuleViolation( + position: position, + reason: reason, + severity: configuration.severity + ) + ) } } } From 6431b954cbc764c0ad1519f77a0fc6865cadd97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 22 Jun 2024 09:57:38 +0200 Subject: [PATCH 085/265] Fix capitalization (#5626) --- .../Rules/Style/VerticalWhitespaceBetweenCasesRule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift index 5f9a026b75..bcc63cd45e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift @@ -137,7 +137,7 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { extension VerticalWhitespaceBetweenCasesRule: OptInRule { static let description = RuleDescription( identifier: "vertical_whitespace_between_cases", - name: "Vertical Whitespace between Cases", + name: "Vertical Whitespace Between Cases", description: "Include a single empty line between switch cases", kind: .style, nonTriggeringExamples: (violatingToValidExamples.values + nonTriggeringExamples).sorted(), From 72069bf5c04b5836c9c87422a578712d0258733b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 22 Jun 2024 10:34:10 +0200 Subject: [PATCH 086/265] Ignore ACL restricted to value setting in `extension_access_modifier` rule (#5625) --- CHANGELOG.md | 5 +++++ .../Idiomatic/ExtensionAccessModifierRule.swift | 12 +++++++++++- .../Extensions/SwiftSyntax+SwiftLint.swift | 10 ++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 658c2e70ff..4b2d793a25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5153](https://github.com/realm/SwiftLint/issues/5153) +* Ignore access level modifiers restricted to value setting in + `extension_access_modifier` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5623](https://github.com/realm/SwiftLint/issues/5623) + ## 0.55.1: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift index 6ec81d59d3..242bfa05a2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift @@ -97,6 +97,11 @@ struct ExtensionAccessModifierRule: OptInRule { set { Foo.shared.bar = newValue } } } + """), + Example(""" + public extension Foo { + private(set) var value: Int { 1 } + } """) ], triggeringExamples: [ @@ -156,6 +161,11 @@ struct ExtensionAccessModifierRule: OptInRule { ↓private func bar() {} ↓private func baz() {} } + """), + Example(""" + ↓extension Foo { + private(set) public var value: Int { 1 } + } """) ] ) @@ -198,7 +208,7 @@ private extension ExtensionAccessModifierRule { for decl in node.memberBlock.expandingIfConfigs() { let modifiers = decl.asProtocol((any WithModifiersSyntax).self)?.modifiers - let aclToken = modifiers?.accessLevelModifier?.name + let aclToken = modifiers?.accessLevelModifier()?.name let acl = ACL.from(tokenKind: aclToken?.tokenKind) if areAllACLsEqual, acl != aclTokens.last?.acl, aclTokens.isNotEmpty { areAllACLsEqual = false diff --git a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift index 326c5fa439..86b3921229 100644 --- a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift @@ -100,6 +100,16 @@ public extension DeclModifierListSyntax { first { $0.asAccessLevelModifier != nil } } + func accessLevelModifier(setter: Bool = false) -> DeclModifierSyntax? { + first { + if $0.asAccessLevelModifier == nil { + return false + } + let hasSetDetail = $0.detail?.detail.tokenKind == .identifier("set") + return setter ? hasSetDetail : !hasSetDetail + } + } + func contains(keyword: Keyword) -> Bool { contains { $0.name.tokenKind == .keyword(keyword) } } From 914fa02e4e93fc3d73eb84ec45de7291ae5e86bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 22 Jun 2024 11:14:14 +0200 Subject: [PATCH 087/265] Use SwiftSyntax version 600.0.0-prerelease-2024-03-11 (#5527) We can also switch back to an exact SwiftSyntax version now with the plugins in a separate repository. In fact, using the plugin, no direct dependency to SwiftSyntax is required whatsoever. --- MODULE.bazel | 6 ++--- Package.resolved | 4 +-- Package.swift | 2 +- .../UnneededSynthesizedInitializerRule.swift | 2 +- .../Rules/Style/ControlStatementRule.swift | 27 ++++++++----------- .../Extensions/SwiftSyntax+SwiftLint.swift | 2 -- .../SyntaxClassification+isComment.swift | 2 +- ...cceptableByConfigurationElementTests.swift | 4 +-- 8 files changed, 21 insertions(+), 28 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index b13e876349..f2c9c9de40 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,13 +5,13 @@ module( repo_name = "SwiftLint", ) -bazel_dep(name = "apple_support", version = "1.11.1", repo_name = "build_bazel_apple_support") +bazel_dep(name = "apple_support", version = "1.13.0", repo_name = "build_bazel_apple_support") bazel_dep(name = "bazel_skylib", version = "1.5.0") bazel_dep(name = "platforms", version = "0.0.8") -bazel_dep(name = "rules_apple", version = "3.1.1", repo_name = "build_bazel_rules_apple") +bazel_dep(name = "rules_apple", version = "3.3.0", repo_name = "build_bazel_rules_apple") bazel_dep(name = "rules_swift", version = "1.16.0", repo_name = "build_bazel_rules_swift") bazel_dep(name = "sourcekitten", version = "0.35.0", repo_name = "com_github_jpsim_sourcekitten") -bazel_dep(name = "swift-syntax", version = "510.0.2", repo_name = "SwiftSyntax") +bazel_dep(name = "swift-syntax", version = "600.0.0-prerelease-2024-04-02", repo_name = "SwiftSyntax") bazel_dep(name = "swift_argument_parser", version = "1.3.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") bazel_dep(name = "yams", version = "5.0.6", repo_name = "sourcekitten_com_github_jpsim_yams") diff --git a/Package.resolved b/Package.resolved index 0c9c7c9860..5f29f82167 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "303e5c5c36d6a558407d364878df131c3546fad8", - "version" : "510.0.2" + "revision" : "55c4e4669c031d697e1924022b8ba250cfde0f2f", + "version" : "600.0.0-prerelease-2024-04-02" } }, { diff --git a/Package.swift b/Package.swift index f1e4b2208a..f86d250cdd 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), - .package(url: "https://github.com/apple/swift-syntax.git", from: "510.0.2"), + .package(url: "https://github.com/apple/swift-syntax.git", exact: "600.0.0-prerelease-2024-04-02"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift index dd789bae62..eb5e9b657a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift @@ -234,7 +234,7 @@ private extension StructDeclSyntax { private extension InitializerDeclSyntax { var hasThrowsOrRethrowsKeyword: Bool { - signature.effectSpecifiers?.throwsSpecifier != nil + signature.effectSpecifiers?.throwsClause?.throwsSpecifier != nil } var isInlinable: Bool { attributes.contains(attributeNamed: "inlinable") diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift index 67fc9565f2..8ee4ab081b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift @@ -1,4 +1,3 @@ -@_spi(SyntaxTransformVisitor) import SwiftSyntax @SwiftSyntaxRule(explicitRewriter: true) @@ -166,27 +165,23 @@ private extension ControlStatementRule { } } -private class TrailingClosureFinder: SyntaxTransformVisitor { - func visitAny(_ node: Syntax) -> Bool { - false - } - - func visit(_ node: FunctionCallExprSyntax) -> Bool { - node.trailingClosure != nil - } - - func visit(_ node: SequenceExprSyntax) -> Bool { - node.elements.contains(where: visit) - } -} - private extension ExprSyntax { var unwrapped: ExprSyntax? { if let expr = self.as(TupleExprSyntax.self)?.elements.onlyElement?.expression { - return TrailingClosureFinder().visit(expr) ? nil : expr + return containsTrailingClosure(Syntax(expr)) ? nil : expr } return nil } + + private func containsTrailingClosure(_ node: Syntax) -> Bool { + switch node.as(SyntaxEnum.self) { + case .functionCallExpr(let node): + node.trailingClosure != nil + case .sequenceExpr(let node): + node.elements.contains { containsTrailingClosure(Syntax($0)) } + default: false + } + } } private extension ConditionElementListSyntax { diff --git a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift index 86b3921229..677faf7c0b 100644 --- a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift @@ -349,8 +349,6 @@ public extension ClosureCaptureSyntax { } } -extension PrecedenceGroupDeclSyntax: BracedSyntax {} - private extension String { var isZero: Bool { if self == "0" { // fast path diff --git a/Source/SwiftLintCore/Extensions/SyntaxClassification+isComment.swift b/Source/SwiftLintCore/Extensions/SyntaxClassification+isComment.swift index 80178a11c4..e579c65d4b 100644 --- a/Source/SwiftLintCore/Extensions/SyntaxClassification+isComment.swift +++ b/Source/SwiftLintCore/Extensions/SyntaxClassification+isComment.swift @@ -6,7 +6,7 @@ public extension SyntaxClassification { switch self { case .lineComment, .docLineComment, .blockComment, .docBlockComment: return true - case .none, .keyword, .identifier, .type, .operator, .dollarIdentifier, .integerLiteral, + case .none, .keyword, .identifier, .type, .operator, .dollarIdentifier, .integerLiteral, .argumentLabel, .floatLiteral, .stringLiteral, .ifConfigDirective, .attribute, .editorPlaceholder, .regexLiteral: return false } diff --git a/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift b/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift index 37bc9053e0..5f62738da1 100644 --- a/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift +++ b/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift @@ -61,7 +61,7 @@ final class MakeAcceptableByConfigurationElementTests: XCTestCase { .symbol(rawValue) } private init(fromAny value: Any, context ruleID: String) throws { - if let value = value as? String, let newSelf = Self (rawValue: value) { + if let value = value as? String, let newSelf = Self(rawValue: value) { self = newSelf } else { throw Issue.invalidConfiguration(ruleID: ruleID) @@ -89,7 +89,7 @@ final class MakeAcceptableByConfigurationElementTests: XCTestCase { .symbol(rawValue) } public init(fromAny value: Any, context ruleID: String) throws { - if let value = value as? String, let newSelf = Self (rawValue: value) { + if let value = value as? String, let newSelf = Self(rawValue: value) { self = newSelf } else { throw Issue.invalidConfiguration(ruleID: ruleID) From 2d28166d21288d00a54d757ccdbb5be142ff95e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 22 Jun 2024 11:22:55 +0200 Subject: [PATCH 088/265] Enable upcoming feature "Concise Magic File" (#5637) --- BUILD | 2 ++ Package.swift | 3 ++- .../DiscouragedOptionalBooleanRuleExamples.swift | 5 ++++- .../DiscouragedOptionalCollectionExamples.swift | 5 ++++- .../Idiomatic/UnneededBreakInSwitchRule.swift | 2 +- .../Lint/ProhibitedInterfaceBuilderRule.swift | 2 +- .../Rules/Lint/StrongIBOutletRule.swift | 2 +- .../Metrics/ClosureBodyLengthRuleExamples.swift | 14 +++++++------- .../Rules/Metrics/TypeBodyLengthRule.swift | 2 +- .../Rules/Style/EmptyEnumArgumentsRule.swift | 4 ++-- .../Rules/Style/SwitchCaseOnNewlineRule.swift | 2 +- Source/SwiftLintCore/Models/Example.swift | 2 +- Tests/IntegrationTests/IntegrationTests.swift | 6 +++--- .../FileNameNoSpaceRuleTests.swift | 2 +- .../FunctionBodyLengthRuleTests.swift | 4 ++-- .../FunctionParameterCountRuleTests.swift | 2 +- .../IndentationWidthRuleTests.swift | 8 ++++---- .../LinterCacheTests.swift | 6 +++--- .../XCTestCase+BundlePath.swift | 2 +- Tests/SwiftLintTestHelpers/TestHelpers.swift | 15 +++++++-------- 20 files changed, 49 insertions(+), 41 deletions(-) diff --git a/BUILD b/BUILD index 7475808562..086b7db35f 100644 --- a/BUILD +++ b/BUILD @@ -28,6 +28,8 @@ config_setting( copts = [ "-enable-upcoming-feature", "ExistentialAny", + "-enable-upcoming-feature", + "ConciseMagicFile", ] strict_concurrency_copts = [ diff --git a/Package.swift b/Package.swift index f86d250cdd..cb3645a4f2 100644 --- a/Package.swift +++ b/Package.swift @@ -3,7 +3,8 @@ import CompilerPluginSupport import PackageDescription let swiftFeatures: [SwiftSetting] = [ - .enableUpcomingFeature("ExistentialAny") + .enableUpcomingFeature("ExistentialAny"), + .enableUpcomingFeature("ConciseMagicFile") ] let swiftLintPluginDependencies: [Target.Dependency] diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift index 7a309d258d..883717df27 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift @@ -163,6 +163,9 @@ internal struct DiscouragedOptionalBooleanRuleExamples { // MARK: - Private -private func wrapExample(_ type: String, _ test: String, file: StaticString = #file, line: UInt = #line) -> Example { +private func wrapExample(_ type: String, + _ test: String, + file: StaticString = #filePath, + line: UInt = #line) -> Example { return Example("\(type) Foo {\n\t\(test)\n}", file: file, line: line) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift index 56030d9803..e2aaeee150 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift @@ -210,7 +210,10 @@ internal struct DiscouragedOptionalCollectionExamples { // MARK: - Private -private func wrapExample(_ type: String, _ test: String, file: StaticString = #file, line: UInt = #line) -> Example { +private func wrapExample(_ type: String, + _ test: String, + file: StaticString = #filePath, + line: UInt = #line) -> Example { return Example(""" \(type) Foo { \(test) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift index 85019f1d7a..1c9bb4a657 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift @@ -3,7 +3,7 @@ import SwiftSyntax private func embedInSwitch( _ text: String, case: String = "case .bar", - file: StaticString = #file, line: UInt = #line) -> Example { + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" switch foo { \(`case`): diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift index cd0e3af3bf..a03d759861 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift @@ -36,7 +36,7 @@ private extension ProhibitedInterfaceBuilderRule { } } -private func wrapExample(_ text: String, file: StaticString = #file, line: UInt = #line) -> Example { +private func wrapExample(_ text: String, file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" class ViewController: UIViewController { \(text) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift index 3a5a298efb..516aff6895 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift @@ -68,7 +68,7 @@ private extension VariableDeclSyntax { } } -private func wrapExample(_ text: String, file: StaticString = #file, line: UInt = #line) -> Example { +private func wrapExample(_ text: String, file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" class ViewController: UIViewController { \(text) diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift index d5e7cda8ba..899c013568 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift @@ -29,7 +29,7 @@ internal struct ClosureBodyLengthRuleExamples { // MARK: - Private -private func singleLineClosure(file: StaticString = #file, line: UInt = #line) -> Example { +private func singleLineClosure(file: StaticString = #filePath, line: UInt = #line) -> Example { return Example("foo.bar { $0 }", file: file, line: line) } @@ -37,7 +37,7 @@ private func trailingClosure(_ violationSymbol: String = "", codeLinesCount: Int, commentLinesCount: Int, emptyLinesCount: Int, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" foo.bar \(violationSymbol){ toto in @@ -50,7 +50,7 @@ private func trailingClosure(_ violationSymbol: String = "", private func argumentClosure(_ violationSymbol: String = "", codeLinesCount: Int, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" foo.bar(\(violationSymbol){ toto in @@ -61,7 +61,7 @@ private func argumentClosure(_ violationSymbol: String = "", private func labeledArgumentClosure(_ violationSymbol: String = "", codeLinesCount: Int, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" foo.bar(label: \(violationSymbol){ toto in @@ -72,7 +72,7 @@ private func labeledArgumentClosure(_ violationSymbol: String = "", private func multiLabeledArgumentClosures(_ violationSymbol: String = "", codeLinesCount: Int, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" foo.bar(label: \(violationSymbol){ toto in @@ -85,7 +85,7 @@ private func multiLabeledArgumentClosures(_ violationSymbol: String = "", private func labeledAndTrailingClosures(_ violationSymbol: String = "", codeLinesCount: Int, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" foo.bar(label: \(violationSymbol){ toto in @@ -98,7 +98,7 @@ private func labeledAndTrailingClosures(_ violationSymbol: String = "", private func lazyInitialization(_ violationSymbol: String = "", codeLinesCount: Int, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" let foo: Bar = \(violationSymbol){ toto in diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift index 1852f791e3..18486f8f29 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift @@ -4,7 +4,7 @@ private func wrapExample( _ template: String, _ count: Int, _ add: String = "", - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example("\(prefix)\(type) Abc {\n" + repeatElement(template, count: count).joined() + "\(add)}\n", file: file, line: line) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift index 63c22fa8f6..70ab89d64d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift @@ -3,7 +3,7 @@ import SwiftSyntax private func wrapInSwitch( variable: String = "foo", _ str: String, - file: StaticString = #file, line: UInt = #line) -> Example { + file: StaticString = #filePath, line: UInt = #line) -> Example { return Example( """ switch \(variable) { @@ -12,7 +12,7 @@ private func wrapInSwitch( """, file: file, line: line) } -private func wrapInFunc(_ str: String, file: StaticString = #file, line: UInt = #line) -> Example { +private func wrapInFunc(_ str: String, file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" func example(foo: Foo) { switch foo { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift index 6581f5ca9f..3d8254cc1e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift @@ -1,6 +1,6 @@ import SwiftSyntax -private func wrapInSwitch(_ str: String, file: StaticString = #file, line: UInt = #line) -> Example { +private func wrapInSwitch(_ str: String, file: StaticString = #filePath, line: UInt = #line) -> Example { return Example(""" switch foo { \(str) diff --git a/Source/SwiftLintCore/Models/Example.swift b/Source/SwiftLintCore/Models/Example.swift index 5a8a84eed4..bd4964fef1 100644 --- a/Source/SwiftLintCore/Models/Example.swift +++ b/Source/SwiftLintCore/Models/Example.swift @@ -61,7 +61,7 @@ public extension Example { /// Defaults to the line where this initializer is called. init(_ code: String, configuration: [String: any Sendable]? = nil, testMultiByteOffsets: Bool = true, testWrappingInComment: Bool = true, testWrappingInString: Bool = true, testDisableCommand: Bool = true, - testOnLinux: Bool = true, file: StaticString = #file, line: UInt = #line, + testOnLinux: Bool = true, file: StaticString = #filePath, line: UInt = #line, excludeFromDocumentation: Bool = false) { self.code = code self.configuration = configuration diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index 7a116f265f..ff49b170ca 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -5,7 +5,7 @@ import XCTest private let config: Configuration = { let bazelWorkspaceDirectory = ProcessInfo.processInfo.environment["BUILD_WORKSPACE_DIRECTORY"] - let rootProjectDirectory = bazelWorkspaceDirectory ?? #file.bridge() + let rootProjectDirectory = bazelWorkspaceDirectory ?? #filePath.bridge() .deletingLastPathComponent.bridge() .deletingLastPathComponent.bridge() .deletingLastPathComponent @@ -21,7 +21,7 @@ final class IntegrationTests: SwiftLintTestCase { forceExclude: false, excludeBy: .paths(excludedPaths: config.excludedPaths())) XCTAssert( - swiftFiles.contains(where: { #file.bridge().absolutePathRepresentation() == $0.path }), + swiftFiles.contains(where: { #filePath.bridge().absolutePathRepresentation() == $0.path }), "current file should be included" ) @@ -64,7 +64,7 @@ final class IntegrationTests: SwiftLintTestCase { """ } .joined(separator: "\n") - let referenceFile = URL(fileURLWithPath: #file) + let referenceFile = URL(fileURLWithPath: #filePath) .deletingLastPathComponent() .appendingPathComponent("default_rule_configurations.yml") XCTAssertEqual(defaultConfig + "\n", try String(contentsOf: referenceFile)) diff --git a/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift index d3cc871431..4aee8dcc7c 100644 --- a/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileNameNoSpaceRuleTests.swift @@ -2,7 +2,7 @@ import SourceKittenFramework @testable import SwiftLintBuiltInRules import XCTest -private let fixturesDirectory = #file.bridge() +private let fixturesDirectory = #filePath.bridge() .deletingLastPathComponent.bridge() .appendingPathComponent("Resources/FileNameNoSpaceRuleFixtures") diff --git a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift index bd5b729168..73e5eea7c7 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift @@ -3,13 +3,13 @@ import XCTest private func funcWithBody(_ body: String, violates: Bool = false, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { let marker = violates ? "↓" : "" return Example("func \(marker)abc() {\n\(body)}\n", file: file, line: line) } -private func violatingFuncWithBody(_ body: String, file: StaticString = #file, line: UInt = #line) -> Example { +private func violatingFuncWithBody(_ body: String, file: StaticString = #filePath, line: UInt = #line) -> Example { return funcWithBody(body, violates: true, file: file, line: line) } diff --git a/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift index 979d8872c3..c8f3e3ebf3 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionParameterCountRuleTests.swift @@ -2,7 +2,7 @@ private func funcWithParameters(_ parameters: String, violates: Bool = false, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) -> Example { let marker = violates ? "↓" : "" diff --git a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift index 26f836fa4f..627797f814 100644 --- a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift @@ -271,7 +271,7 @@ final class IndentationWidthRuleTests: SwiftLintTestCase { includeComments: Bool = true, includeCompilerDirectives: Bool = true, includeMultilineStrings: Bool = true, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) -> Int { var configDict: [String: Any] = [:] @@ -297,7 +297,7 @@ final class IndentationWidthRuleTests: SwiftLintTestCase { includeComments: Bool = true, includeCompilerDirectives: Bool = true, includeMultilineStrings: Bool = true, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { XCTAssertEqual( @@ -322,7 +322,7 @@ final class IndentationWidthRuleTests: SwiftLintTestCase { includeComments: Bool = true, includeCompilerDirectives: Bool = true, includeMultilineStrings: Bool = true, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { assertViolations( @@ -343,7 +343,7 @@ final class IndentationWidthRuleTests: SwiftLintTestCase { includeComments: Bool = true, includeCompilerDirectives: Bool = true, includeMultilineStrings: Bool = true, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { assertViolations( diff --git a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift index ad57ad2db7..b6426186ed 100644 --- a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift +++ b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift @@ -78,7 +78,7 @@ final class LinterCacheTests: SwiftLintTestCase { } private func cacheAndValidate(violations: [StyleViolation], forFile: String, configuration: Configuration, - file: StaticString = #file, line: UInt = #line) { + file: StaticString = #filePath, line: UInt = #line) { cache.cache(violations: violations, forFile: forFile, configuration: configuration) cache = cache.flushed() XCTAssertEqual(cache.violations(forFile: forFile, configuration: configuration)!, @@ -86,7 +86,7 @@ final class LinterCacheTests: SwiftLintTestCase { } private func cacheAndValidateNoViolationsTwoFiles(configuration: Configuration, - file: StaticString = #file, line: UInt = #line) { + file: StaticString = #filePath, line: UInt = #line) { let (file1, file2) = ("file1.swift", "file2.swift") // swiftlint:disable:next force_cast let fileManager = cache.fileManager as! TestFileManager @@ -97,7 +97,7 @@ final class LinterCacheTests: SwiftLintTestCase { } private func validateNewConfigDoesntHitCache(dict: [String: Any], initialConfig: Configuration, - file: StaticString = #file, line: UInt = #line) throws { + file: StaticString = #filePath, line: UInt = #line) throws { let newConfig = try Configuration(dict: dict) let (file1, file2) = ("file1.swift", "file2.swift") diff --git a/Tests/SwiftLintFrameworkTests/XCTestCase+BundlePath.swift b/Tests/SwiftLintFrameworkTests/XCTestCase+BundlePath.swift index 6aedcb8a4e..f20eb5b175 100644 --- a/Tests/SwiftLintFrameworkTests/XCTestCase+BundlePath.swift +++ b/Tests/SwiftLintFrameworkTests/XCTestCase+BundlePath.swift @@ -7,7 +7,7 @@ enum TestResources { return "\(rootProjectDirectory)/Tests/SwiftLintFrameworkTests/Resources" } - return URL(fileURLWithPath: #file, isDirectory: false) + return URL(fileURLWithPath: #filePath, isDirectory: false) .deletingLastPathComponent() .appendingPathComponent("Resources") .path diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index 7a0c4c5218..fffb3146d1 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -325,7 +325,7 @@ public extension XCTestCase { skipDisableCommandTests: Bool = false, testMultiByteOffsets: Bool = true, testShebang: Bool = true, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) { guard ruleDescription.minSwiftVersion <= .current else { return @@ -349,7 +349,8 @@ public extension XCTestCase { self.verifyLint(ruleDescription, config: config, commentDoesntViolate: commentDoesntViolate, stringDoesntViolate: stringDoesntViolate, skipCommentTests: skipCommentTests, skipStringTests: skipStringTests, disableCommands: disableCommands, - testMultiByteOffsets: testMultiByteOffsets, testShebang: testShebang) + testMultiByteOffsets: testMultiByteOffsets, testShebang: testShebang, + file: file, line: line) self.verifyCorrections(ruleDescription, config: config, disableCommands: disableCommands, testMultiByteOffsets: testMultiByteOffsets) } @@ -363,11 +364,11 @@ public extension XCTestCase { disableCommands: [String] = [], testMultiByteOffsets: Bool = true, testShebang: Bool = true, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line) { func verify(triggers: [Example], nonTriggers: [Example]) { verifyExamples(triggers: triggers, nonTriggers: nonTriggers, configuration: config, - requiresFileOnDisk: ruleDescription.requiresFileOnDisk, file: file, line: line) + requiresFileOnDisk: ruleDescription.requiresFileOnDisk) } func makeViolations(_ example: Example) -> [StyleViolation] { return violations(example, config: config, requiresFileOnDisk: ruleDescription.requiresFileOnDisk) @@ -458,9 +459,7 @@ public extension XCTestCase { } private func verifyExamples(triggers: [Example], nonTriggers: [Example], - configuration config: Configuration, requiresFileOnDisk: Bool, - file callSiteFile: StaticString = #file, - line callSiteLine: UInt = #line) { + configuration config: Configuration, requiresFileOnDisk: Bool) { // Non-triggering examples don't violate for nonTrigger in nonTriggers { let unexpectedViolations = violations(nonTrigger, config: config, @@ -527,7 +526,7 @@ public extension XCTestCase { // file and line parameters are first so we can use trailing closure syntax with the closure func checkError( - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line, _ error: T, closure: () throws -> Void) { From d5dc14231e0c2a558b06c0c39759f7715d367fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 22 Jun 2024 11:40:56 +0200 Subject: [PATCH 089/265] Enable upcoming Swift 6 features (#5639) * Import Objective-C Forward Declarations * Forward Trailing Closures * Internal Imports by Default * Implicit Open Existentials --- BUILD | 8 ++++++++ Package.swift | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/BUILD b/BUILD index 086b7db35f..afd327d672 100644 --- a/BUILD +++ b/BUILD @@ -30,6 +30,14 @@ copts = [ "ExistentialAny", "-enable-upcoming-feature", "ConciseMagicFile", + "-enable-upcoming-feature", + "ImportObjcForwardDeclarations", + "-enable-upcoming-feature", + "ForwardTrailingClosures", + "-enable-upcoming-feature", + "InternalImportsByDefault", + "-enable-upcoming-feature", + "ImplicitOpenExistentials", ] strict_concurrency_copts = [ diff --git a/Package.swift b/Package.swift index cb3645a4f2..5815d4e11d 100644 --- a/Package.swift +++ b/Package.swift @@ -4,7 +4,11 @@ import PackageDescription let swiftFeatures: [SwiftSetting] = [ .enableUpcomingFeature("ExistentialAny"), - .enableUpcomingFeature("ConciseMagicFile") + .enableUpcomingFeature("ConciseMagicFile"), + .enableUpcomingFeature("ImportObjcForwardDeclarations"), + .enableUpcomingFeature("ForwardTrailingClosures"), + .enableUpcomingFeature("InternalImportsByDefault"), + .enableUpcomingFeature("ImplicitOpenExistentials") ] let swiftLintPluginDependencies: [Target.Dependency] From 1f4b422adf44e6aeb4a033260cbf1c15b88ebeed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 22 Jun 2024 11:41:30 +0200 Subject: [PATCH 090/265] Add changelog entries associated with update to Swift 6 (#5638) --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2d793a25..775e8ef1e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,10 +12,16 @@ #### Enhancements -* None. +* Linting got around 20% faster due to the praisworthy performance + improvements done in the [SwiftSyntax](https://github.com/apple/swift-syntax) + library. #### Bug Fixes +* Fix a few false positives and negatives by updating the parser to support + Swift 6 with all its new language constructs. + [SimplyDanny](https://github.com/SimplyDanny) + * Stop triggering `mark` rule on "mark" comments in the middle of another comment. [SimplyDanny](https://github.com/SimplyDanny) From fa5f98f6f396fa8a0e1fe35fe51374eda0917fdb Mon Sep 17 00:00:00 2001 From: Muhammet Ilendemli Date: Sat, 22 Jun 2024 19:50:08 +0200 Subject: [PATCH 091/265] Make `vertical_whitespace_between_cases` rule work when case block ends with a string literal (#5628) --- CHANGELOG.md | 5 +++++ .../VerticalWhitespaceBetweenCasesRule.swift | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 775e8ef1e2..590831299b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,11 @@ `unneeded_synthesized_initializer` rule. [SimplyDanny](https://github.com/SimplyDanny) [#5153](https://github.com/realm/SwiftLint/issues/5153) + +* Make `vertical_whitespace_between_cases` rule work for + cases ending with a string literal. + [ilendemli](https://github.com/ilendemli) + [#5612](https://github.com/realm/SwiftLint/issues/5612) * Ignore access level modifiers restricted to value setting in `extension_access_modifier` rule. diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift index bcc63cd45e..55f28a2608 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift @@ -3,7 +3,7 @@ import SourceKittenFramework private extension SwiftLintFile { func violatingRanges(for pattern: String) -> [NSRange] { - return match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentAndStringKinds) + return match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentKinds) } } @@ -57,6 +57,22 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { ] private static let violatingToValidExamples: [Example: Example] = [ + Example(""" + switch x { + case 0..<5: + return "x is valid" + ↓ default: + return "x is invalid" + } + """): Example(""" + switch x { + case 0..<5: + return "x is valid" + + default: + return "x is invalid" + } + """), Example(""" switch x { case 0..<5: From 3b19e7d99b3a91ed95862659d0c306ca970126f0 Mon Sep 17 00:00:00 2001 From: miltenkot Date: Sat, 22 Jun 2024 19:51:24 +0200 Subject: [PATCH 092/265] Fix typo in README (#5621) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c19176c0a5..23bb9de2fd 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ validations can be disabled with either of the following: * Setting Xcode defaults: ```bash - defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidation -bool YES + defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES ``` From 251fb85cd4d330d09b2e128cb9f27efd946492aa Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 26 Jun 2024 18:05:10 +0200 Subject: [PATCH 093/265] Keep GitHub Actions up to date with GitHub's Dependabot (#5643) --- .github/dependabot.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..be006de9a1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Keep GitHub Actions up to date with GitHub's Dependabot... +# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + groups: + github-actions: + patterns: + - "*" # Group all Actions updates into a single larger pull request + schedule: + interval: weekly From 3afad91a1b8be8f8f220c896edba2d451c873392 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:20:28 +0000 Subject: [PATCH 094/265] Bump the github-actions group with 4 updates (#5644) Bumps the github-actions group with 4 updates: [actions/checkout](https://github.com/actions/checkout), [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action), [docker/login-action](https://github.com/docker/login-action) and [docker/build-push-action](https://github.com/docker/build-push-action). Updates `actions/checkout` from 3 to 4 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) Updates `docker/setup-buildx-action` from 1 to 3 - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v3) Updates `docker/login-action` from 1 to 3 - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v1...v3) Updates `docker/build-push-action` from 2 to 6 - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v2...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docker.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4c8cd4cadf..1d996c4639 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Extract DOCKER_TAG using tag name if: startsWith(github.ref, 'refs/tags/') @@ -31,16 +31,16 @@ jobs: REPOSITORY: '${{ github.repository }}' - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to GitHub registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io - - uses: docker/build-push-action@v2 + - uses: docker/build-push-action@v6 with: push: true tags: ghcr.io/${{ env.REPOSITORY_LC }}:${{ env.DOCKER_TAG }} From 8bed208416cad8b1db914238f0d4ff1bfc4eaf6d Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Thu, 27 Jun 2024 18:40:04 +0100 Subject: [PATCH 095/265] Adds `baseline` and `write_baseline` config file options (#5552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adds `baseline` and `write_baseline` config file options, so baseline can be used by people who can't pass command line arguments (e.g. plugin users). * Added PR number * Fixed change log entry * Update Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift Co-authored-by: Danny Mösch * updated --------- Co-authored-by: Danny Mösch --- CHANGELOG.md | 5 +++ README.md | 6 ++++ .../Extensions/Configuration+Merging.swift | 4 ++- .../Extensions/Configuration+Parsing.swift | 6 +++- .../SwiftLintCore/Models/Configuration.swift | 35 +++++++++++++++---- .../Helpers/LintOrAnalyzeCommand.swift | 8 ++--- .../ConfigurationTests.swift | 16 +++++++++ .../Resources/ProjectMock/.swiftlint.yml | 2 ++ 8 files changed, 70 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 590831299b..49e0578502 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ improvements done in the [SwiftSyntax](https://github.com/apple/swift-syntax) library. +* Adds `baseline` and `write_baseline` configuration file settings, equivalent + to the `--baseline` and `--write-baseline` command line options. + [Martin Redington](https://github.com/mildm8nnered) + [#5552](https://github.com/realm/SwiftLint/issues/5552) + #### Bug Fixes * Fix a few false positives and negatives by updating the parser to support diff --git a/README.md b/README.md index 23bb9de2fd..f287c0394d 100644 --- a/README.md +++ b/README.md @@ -697,6 +697,12 @@ allow_zero_lintable_files: false # If true, SwiftLint will treat all warnings as errors. strict: false +# The path to a baseline file, which will be used to filter out detected violations. +baseline: Baseline.json + +# The path to save detected violations to as a new baseline. +write_baseline: Baseline.json + # configurable rules can be customized from this configuration file # binary rules can set their severity level force_cast: warning # implicitly diff --git a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift index 0273b25ea2..1d58f464c8 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift @@ -25,7 +25,9 @@ extension Configuration { reporter: reporter, cachePath: cachePath, allowZeroLintableFiles: childConfiguration.allowZeroLintableFiles, - strict: childConfiguration.strict + strict: childConfiguration.strict, + baseline: childConfiguration.baseline, + writeBaseline: childConfiguration.writeBaseline ) } diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 5040ef8500..096e31f81f 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -15,6 +15,8 @@ extension Configuration { case analyzerRules = "analyzer_rules" case allowZeroLintableFiles = "allow_zero_lintable_files" case strict = "strict" + case baseline = "baseline" + case writeBaseline = "write_baseline" case childConfig = "child_config" case parentConfig = "parent_config" case remoteConfigTimeout = "remote_timeout" @@ -95,7 +97,9 @@ extension Configuration { cachePath: cachePath ?? dict[Key.cachePath.rawValue] as? String, pinnedVersion: dict[Key.swiftlintVersion.rawValue].map { ($0 as? String) ?? String(describing: $0) }, allowZeroLintableFiles: dict[Key.allowZeroLintableFiles.rawValue] as? Bool ?? false, - strict: dict[Key.strict.rawValue] as? Bool ?? false + strict: dict[Key.strict.rawValue] as? Bool ?? false, + baseline: dict[Key.baseline.rawValue] as? String, + writeBaseline: dict[Key.writeBaseline.rawValue] as? String ) } diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index fe7db20701..5e0c6be8ee 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -35,9 +35,15 @@ public struct Configuration { /// Allow or disallow SwiftLint to exit successfully when passed only ignored or unlintable files. public let allowZeroLintableFiles: Bool - /// Treat warnings as errors + /// Treat warnings as errors. public let strict: Bool + /// The path to read a baseline from. + public let baseline: String? + + /// The path to write a baseline to. + public let writeBaseline: String? + /// This value is `true` iff the `--config` parameter was used to specify (a) configuration file(s) /// In particular, this means that the value is also `true` if the `--config` parameter /// was used to explicitly specify the default `.swiftlint.yml` as the configuration file @@ -73,7 +79,9 @@ public struct Configuration { reporter: String?, cachePath: String?, allowZeroLintableFiles: Bool, - strict: Bool + strict: Bool, + baseline: String?, + writeBaseline: String? ) { self.rulesWrapper = rulesWrapper self.fileGraph = fileGraph @@ -85,6 +93,8 @@ public struct Configuration { self.cachePath = cachePath self.allowZeroLintableFiles = allowZeroLintableFiles self.strict = strict + self.baseline = baseline + self.writeBaseline = writeBaseline } /// Creates a Configuration by copying an existing configuration. @@ -102,6 +112,8 @@ public struct Configuration { cachePath = configuration.cachePath allowZeroLintableFiles = configuration.allowZeroLintableFiles strict = configuration.strict + baseline = configuration.baseline + writeBaseline = configuration.writeBaseline } /// Creates a `Configuration` by specifying its properties directly, @@ -122,8 +134,11 @@ public struct Configuration { /// - parameter reporter: The identifier for the `Reporter` to use to report style violations. /// - parameter cachePath: The location of the persisted cache to use whith this configuration. /// - parameter pinnedVersion: The SwiftLint version defined in this configuration. - /// - parameter allowZeroLintableFiles: Allow SwiftLint to exit successfully when passed ignored or unlintable files - /// - parameter strict: Treat warnings as errors + /// - parameter allowZeroLintableFiles: Allow SwiftLint to exit successfully when passed ignored or unlintable + /// files. + /// - parameter strict: Treat warnings as errors. + /// - parameter baseline: The path to read a baseline from. + /// - parameter writeBaseline: The path to write a baseline to. package init( rulesMode: RulesMode = .default(disabled: [], optIn: []), allRulesWrapped: [ConfigurationRuleWrapper]? = nil, @@ -137,7 +152,9 @@ public struct Configuration { cachePath: String? = nil, pinnedVersion: String? = nil, allowZeroLintableFiles: Bool = false, - strict: Bool = false + strict: Bool = false, + baseline: String? = nil, + writeBaseline: String? = nil ) { if let pinnedVersion, pinnedVersion != Version.current.value { queuedPrintError( @@ -163,7 +180,9 @@ public struct Configuration { reporter: reporter, cachePath: cachePath, allowZeroLintableFiles: allowZeroLintableFiles, - strict: strict + strict: strict, + baseline: baseline, + writeBaseline: writeBaseline ) } @@ -268,6 +287,8 @@ extension Configuration: Hashable { hasher.combine(reporter) hasher.combine(allowZeroLintableFiles) hasher.combine(strict) + hasher.combine(baseline) + hasher.combine(writeBaseline) hasher.combine(basedOnCustomConfigurationFiles) hasher.combine(cachePath) hasher.combine(rules.map { type(of: $0).description.identifier }) @@ -286,6 +307,8 @@ extension Configuration: Hashable { lhs.fileGraph == rhs.fileGraph && lhs.allowZeroLintableFiles == rhs.allowZeroLintableFiles && lhs.strict == rhs.strict && + lhs.baseline == rhs.baseline && + lhs.writeBaseline == rhs.writeBaseline && lhs.rulesMode == rhs.rulesMode } } diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift index 3c5e946b84..816c759a5e 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -44,7 +44,7 @@ struct LintOrAnalyzeCommand { private static func lintOrAnalyze(_ options: LintOrAnalyzeOptions) async throws { let builder = LintOrAnalyzeResultBuilder(options) let files = try await collectViolations(builder: builder) - if let baselineOutputPath = options.writeBaseline { + if let baselineOutputPath = options.writeBaseline ?? builder.configuration.writeBaseline { try Baseline(violations: builder.unfilteredViolations).write(toPath: baselineOutputPath) } try Signposts.record(name: "LintOrAnalyzeCommand.PostProcessViolations") { @@ -55,7 +55,7 @@ struct LintOrAnalyzeCommand { private static func collectViolations(builder: LintOrAnalyzeResultBuilder) async throws -> [SwiftLintFile] { let options = builder.options let visitorMutationQueue = DispatchQueue(label: "io.realm.swiftlint.lintVisitorMutation") - let baseline = try baseline(options) + let baseline = try baseline(options, builder.configuration) return try await builder.configuration.visitLintableFiles(options: options, cache: builder.cache, storage: builder.storage) { linter in let currentViolations: [StyleViolation] @@ -121,8 +121,8 @@ struct LintOrAnalyzeCommand { guard numberOfSeriousViolations == 0 else { exit(2) } } - private static func baseline(_ options: LintOrAnalyzeOptions) throws -> Baseline? { - if let baselinePath = options.baseline { + private static func baseline(_ options: LintOrAnalyzeOptions, _ configuration: Configuration) throws -> Baseline? { + if let baselinePath = options.baseline ?? configuration.baseline { do { return try Baseline(fromPath: baselinePath) } catch { diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 2225cbbd58..fea71880f7 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -56,6 +56,8 @@ final class ConfigurationTests: SwiftLintTestCase { XCTAssertEqual(reporterFrom(identifier: config.reporter).identifier, "xcode") XCTAssertFalse(config.allowZeroLintableFiles) XCTAssertFalse(config.strict) + XCTAssertNil(config.baseline) + XCTAssertNil(config.writeBaseline) } func testInitWithRelativePathAndRootPath() { @@ -70,6 +72,8 @@ final class ConfigurationTests: SwiftLintTestCase { XCTAssertEqual(config.reporter, expectedConfig.reporter) XCTAssertTrue(config.allowZeroLintableFiles) XCTAssertTrue(config.strict) + XCTAssertNotNil(config.baseline) + XCTAssertNotNil(config.writeBaseline) } func testEnableAllRulesConfiguration() throws { @@ -427,6 +431,18 @@ final class ConfigurationTests: SwiftLintTestCase { let configuration = try Configuration(dict: ["strict": true]) XCTAssertTrue(configuration.strict) } + + func testBaseline() throws { + let baselinePath = "Baseline.json" + let configuration = try Configuration(dict: ["baseline": baselinePath]) + XCTAssertEqual(configuration.baseline, baselinePath) + } + + func testWriteBaseline() throws { + let baselinePath = "Baseline.json" + let configuration = try Configuration(dict: ["write_baseline": baselinePath]) + XCTAssertEqual(configuration.writeBaseline, baselinePath) + } } // MARK: - ExcludeByPrefix option tests diff --git a/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/.swiftlint.yml b/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/.swiftlint.yml index fae3e10596..21acf08334 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/.swiftlint.yml +++ b/Tests/SwiftLintFrameworkTests/Resources/ProjectMock/.swiftlint.yml @@ -8,3 +8,5 @@ line_length: 10000000000 reporter: "json" allow_zero_lintable_files: true strict: true +baseline: Baseline.json +write_baseline: Baseline.json From 5c195a4bdbeefdfde2a486c35a4caffc198bb626 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Fri, 28 Jun 2024 01:53:40 +0100 Subject: [PATCH 096/265] Fixed baseline compare issues (#5605) --- CHANGELOG.md | 6 ++++ Source/SwiftLintCore/Models/Baseline.swift | 36 +++++++++++++++---- .../BaselineTests.swift | 17 +++++---- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49e0578502..c7fd247d31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,12 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5623](https://github.com/realm/SwiftLint/issues/5623) +* Fix `baseline compare` incorrectly reporting some violations + as new, and also now sorts the violations from `baseline compare` + deterministically. + [Martin Redington](https://github.com/mildm8nnered) + [#5606](https://github.com/realm/SwiftLint/issues/5606) + ## 0.55.1: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintCore/Models/Baseline.swift b/Source/SwiftLintCore/Models/Baseline.swift index 630537caaa..0df4326df6 100644 --- a/Source/SwiftLintCore/Models/Baseline.swift +++ b/Source/SwiftLintCore/Models/Baseline.swift @@ -4,7 +4,7 @@ private typealias BaselineViolations = [BaselineViolation] private typealias ViolationsPerFile = [String: BaselineViolations] private typealias ViolationsPerRule = [String: BaselineViolations] -private struct BaselineViolation: Codable, Hashable { +private struct BaselineViolation: Codable, Hashable, Comparable { let violation: StyleViolation let text: String var key: String { text + violation.reason } @@ -20,13 +20,23 @@ private struct BaselineViolation: Codable, Hashable { ) self.text = text } + + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.violation == rhs.violation && lhs.text == rhs.text + } + + static func < (lhs: Self, rhs: Self) -> Bool { + lhs.violation.location == rhs.violation.location + ? lhs.violation.ruleIdentifier < rhs.violation.ruleIdentifier + : lhs.violation.location < rhs.violation.location + } } /// A set of violations that can be used to filter newly detected violations. public struct Baseline: Equatable { private let baseline: ViolationsPerFile private var sortedBaselineViolations: BaselineViolations { - baseline.sorted(by: { $0.key < $1.key }).flatMap(\.value) + baseline.flatMap(\.value).sorted() } /// The stored violations. @@ -71,6 +81,16 @@ public struct Baseline: Equatable { } let relativePathViolations = BaselineViolations(violations) + let violationsWithAbsolutePaths = filter( + relativePathViolations: relativePathViolations, + baselineViolations: baselineViolations + ) + return violations.filter { violationsWithAbsolutePaths.contains($0) } + } + + private func filter( + relativePathViolations: BaselineViolations, baselineViolations: BaselineViolations + ) -> Set { if relativePathViolations == baselineViolations { return [] } @@ -106,8 +126,7 @@ public struct Baseline: Equatable { } } - let violationsWithAbsolutePaths = Set(filteredViolations.violationsWithAbsolutePaths) - return violations.filter { violationsWithAbsolutePaths.contains($0) } + return Set(filteredViolations.violationsWithAbsolutePaths) } /// Returns the violations that are present in another `Baseline`, but not in this one. @@ -116,8 +135,13 @@ public struct Baseline: Equatable { /// /// - parameter otherBaseline: The other `Baseline`. public func compare(_ otherBaseline: Baseline) -> [StyleViolation] { - otherBaseline.baseline.flatMap { - filter($1.violationsWithAbsolutePaths) + otherBaseline.baseline.flatMap { relativePath, otherBaselineViolations -> Set in + if let baselineViolations = baseline[relativePath] { + return filter(relativePathViolations: otherBaselineViolations, baselineViolations: baselineViolations) + } + return Set(otherBaselineViolations.violationsWithAbsolutePaths) + }.sorted { + $0.location == $1.location ? $0.ruleIdentifier < $1.ruleIdentifier : $0.location < $1.location } } } diff --git a/Tests/SwiftLintFrameworkTests/BaselineTests.swift b/Tests/SwiftLintFrameworkTests/BaselineTests.swift index 8d38050308..5f45b66c03 100644 --- a/Tests/SwiftLintFrameworkTests/BaselineTests.swift +++ b/Tests/SwiftLintFrameworkTests/BaselineTests.swift @@ -139,13 +139,16 @@ final class BaselineTests: XCTestCase { func testCompare() throws { try withExampleFileCreated { sourceFilePath in - let violations = Self.violations(for: sourceFilePath) - let oldViolations = Array(violations.dropFirst()) - let newViolations = Array(violations.dropLast()) - let oldBaseline = Baseline(violations: oldViolations) - let newBaseline = Baseline(violations: newViolations) - XCTAssertEqual(oldBaseline.compare(newBaseline), [violations.first]) - XCTAssertEqual(newBaseline.compare(oldBaseline), [violations.last]) + let ruleDescriptions = Self.ruleDescriptions + Self.ruleDescriptions + let violations = ruleDescriptions.violations(for: sourceFilePath) + let numberofViolationsToDrop = 3 + let oldBaseline = Baseline(violations: Array(violations.dropFirst(numberofViolationsToDrop)).reversed()) + let newViolations = Array( + try violations.lineShifted(by: 2, path: sourceFilePath).dropLast(numberofViolationsToDrop) + ) + let newBaseline = Baseline(violations: newViolations.reversed()) + XCTAssertEqual(oldBaseline.compare(newBaseline), Array(newViolations.prefix(numberofViolationsToDrop))) + XCTAssertEqual(newBaseline.compare(oldBaseline), Array(violations.suffix(numberofViolationsToDrop))) } } From 09edd528ddb6b387b82152fd898898eb980ee62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 28 Jun 2024 07:27:24 +0200 Subject: [PATCH 097/265] Print only file path when reporting a correction (#5596) Omit exact line and column information. Keep the internal logic available for a while in case people complain for good reasons. Then the change can be reverted easily. Reasons behind this change: * What is the position of a correction actually? The position where the rule triggered? The position of the transformed node? * If there's more than a single fix, it's highly likely that all positions (except for the first) are wrong no matter what the answer to the first question is. * Getting the positions right in a rewriter is hard. And there is always the feeling that something is wrong with them - probably because it is. * Even if you get the positions right in a single rule: One run collects positions for all rules that apply to a file and so rewrites in other rules might draw existing positions wrong. * We already have checks for more than one correction position disabled in tests due to these issues. --- CHANGELOG.md | 9 +++++++++ Source/SwiftLintCore/Models/Correction.swift | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7fd247d31..b2bee7f7fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ [Martin Redington](https://github.com/mildm8nnered) [#5614](https://github.com/realm/SwiftLint/issues/5614) +* When SwiftLint corrects violations automatically (`swiftlint lint --fix`) + it doesn't report the exact location of the fix any longer. The new format + is `: Correcting ` without line and column numbers. + Reason: Correction positions are likely just incorrect, especially when + multiple rules apply their rewrites. Fixing that is not trivial and likely + not worth the effort also considering that there haven't been any bug + reports about wrong correction positions so far. + [SimplyDanny](https://github.com/SimplyDanny) + #### Experimental * None. diff --git a/Source/SwiftLintCore/Models/Correction.swift b/Source/SwiftLintCore/Models/Correction.swift index 1dcfa0842f..44d9fa22d3 100644 --- a/Source/SwiftLintCore/Models/Correction.swift +++ b/Source/SwiftLintCore/Models/Correction.swift @@ -7,7 +7,7 @@ public struct Correction: Equatable, Sendable { /// The console-printable description for this correction. public var consoleDescription: String { - return "\(location) Corrected \(ruleDescription.name)" + return "\(location.file ?? ""): Corrected \(ruleDescription.name)" } /// Memberwise initializer. From c810459e6a80eb72eec183ab78ba8dc7db280fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 28 Jun 2024 07:36:50 +0200 Subject: [PATCH 098/265] Enforce mandatory trailing comma and fix all violations (#5640) --- .sourcery/BuiltInRules.stencil | 2 +- .sourcery/ReportersList.stencil | 2 +- .swiftlint.yml | 2 + .../SwiftLintBuildToolPlugin.swift | 4 +- .../SourceKittenDictionary+SwiftUI.swift | 4 +- .../Models/BuiltInRules.swift | 2 +- ...nymousArgumentInMultilineClosureRule.swift | 4 +- .../Rules/Idiomatic/BlockBasedKVORule.swift | 4 +- .../Rules/Idiomatic/ConvenienceTypeRule.swift | 4 +- .../Idiomatic/DiscouragedAssertRule.swift | 4 +- .../Idiomatic/DiscouragedNoneNameRule.swift | 4 +- .../DiscouragedObjectLiteralRule.swift | 4 +- ...scouragedOptionalBooleanRuleExamples.swift | 4 +- ...iscouragedOptionalCollectionExamples.swift | 4 +- .../Idiomatic/DuplicateImportsRule.swift | 2 +- .../DuplicateImportsRuleExamples.swift | 4 +- .../Rules/Idiomatic/ExplicitACLRule.swift | 6 +- .../Idiomatic/ExplicitEnumRawValueRule.swift | 4 +- .../Rules/Idiomatic/ExplicitInitRule.swift | 6 +- .../Idiomatic/ExplicitTopLevelACLRule.swift | 4 +- .../Idiomatic/ExplicitTypeInterfaceRule.swift | 4 +- .../ExtensionAccessModifierRule.swift | 6 +- .../Rules/Idiomatic/FallthroughRule.swift | 4 +- .../Idiomatic/FatalErrorMessageRule.swift | 4 +- .../Rules/Idiomatic/FileNameNoSpaceRule.swift | 10 ++- .../Rules/Idiomatic/FileNameRule.swift | 10 ++- .../Rules/Idiomatic/ForWhereRule.swift | 4 +- .../Rules/Idiomatic/ForceTryRule.swift | 4 +- .../Rules/Idiomatic/ForceUnwrappingRule.swift | 4 +- .../FunctionDefaultParameterAtEndRule.swift | 4 +- .../Rules/Idiomatic/GenericTypeNameRule.swift | 6 +- .../ImplicitlyUnwrappedOptionalRule.swift | 4 +- .../Rules/Idiomatic/IsDisjointRule.swift | 4 +- .../JoinedDefaultParameterRule.swift | 6 +- .../LegacyCGGeometryFunctionsRule.swift | 8 +- .../LegacyConstantRuleExamples.swift | 8 +- .../Idiomatic/LegacyConstructorRule.swift | 54 +++++++------ .../Rules/Idiomatic/LegacyHashingRule.swift | 4 +- .../Rules/Idiomatic/LegacyMultipleRule.swift | 4 +- .../LegacyNSGeometryFunctionsRule.swift | 8 +- .../Rules/Idiomatic/LegacyObjcTypeRule.swift | 6 +- .../Rules/Idiomatic/LegacyRandomRule.swift | 6 +- .../Rules/Idiomatic/NimbleOperatorRule.swift | 10 +-- .../NoExtensionAccessModifierRule.swift | 4 +- .../NoFallthroughOnlyRuleExamples.swift | 4 +- .../Idiomatic/NoGroupingExtensionRule.swift | 6 +- .../Rules/Idiomatic/NoMagicNumbersRule.swift | 4 +- .../Rules/Idiomatic/ObjectLiteralRule.swift | 6 +- .../Idiomatic/OneDelarationPerFileRule.swift | 4 +- .../PatternMatchingKeywordsRule.swift | 4 +- .../Rules/Idiomatic/PreferNimbleRule.swift | 4 +- .../PreferZeroOverExplicitInitRule.swift | 6 +- .../PrivateOverFilePrivateRule.swift | 6 +- .../RedundantNilCoalescingRule.swift | 2 +- .../RedundantObjcAttributeRuleExamples.swift | 6 +- .../RedundantOptionalInitializationRule.swift | 6 +- .../RedundantSetAccessControlRule.swift | 4 +- .../RedundantStringEnumValueRule.swift | 4 +- .../RedundantTypeAnnotationRule.swift | 6 +- .../Idiomatic/RedundantVoidReturnRule.swift | 6 +- .../ReturnValueFromVoidFunctionRule.swift | 2 +- ...urnValueFromVoidFunctionRuleExamples.swift | 6 +- .../ShorthandOptionalBindingRule.swift | 6 +- .../Rules/Idiomatic/StaticOperatorRule.swift | 4 +- .../Idiomatic/StaticOverFinalClassRule.swift | 4 +- .../Idiomatic/StrictFilePrivateRule.swift | 4 +- .../SyntacticSugarRuleExamples.swift | 6 +- .../Rules/Idiomatic/ToggleBoolRule.swift | 6 +- .../Idiomatic/TrailingSemicolonRule.swift | 6 +- .../Idiomatic/TypeNameRuleExamples.swift | 4 +- .../Idiomatic/UnavailableConditionRule.swift | 4 +- .../Idiomatic/UnavailableFunctionRule.swift | 6 +- .../Idiomatic/UnneededBreakInSwitchRule.swift | 6 +- ...edSynthesizedInitializerRuleExamples.swift | 6 +- .../Idiomatic/UntypedErrorInCatchRule.swift | 6 +- .../Idiomatic/UnusedEnumeratedRule.swift | 4 +- .../VoidFunctionInTernaryConditionRule.swift | 4 +- .../Rules/Idiomatic/XCTFailMessageRule.swift | 4 +- .../XCTSpecificMatcherRuleExamples.swift | 4 +- .../Lint/AccessibilityLabelForImageRule.swift | 2 +- ...cessibilityLabelForImageRuleExamples.swift | 4 +- .../AccessibilityTraitForButtonRule.swift | 4 +- ...essibilityTraitForButtonRuleExamples.swift | 4 +- .../Rules/Lint/AnyObjectProtocolRule.swift | 6 +- .../Rules/Lint/ArrayInitRule.swift | 4 +- .../Lint/BalancedXCTestLifecycleRule.swift | 4 +- .../Lint/BlanketDisableCommandRule.swift | 4 +- .../Rules/Lint/CaptureVariableRule.swift | 4 +- .../Lint/ClassDelegateProtocolRule.swift | 4 +- .../Rules/Lint/CommentSpacingRule.swift | 6 +- .../Rules/Lint/CompilerProtocolInitRule.swift | 16 ++-- .../Rules/Lint/DeploymentTargetRule.swift | 2 +- .../Lint/DeploymentTargetRuleExamples.swift | 4 +- ...cardedNotificationCenterObserverRule.swift | 4 +- .../Lint/DiscouragedDirectInitRule.swift | 4 +- .../Rules/Lint/DuplicateConditionsRule.swift | 4 +- .../Rules/Lint/DuplicateEnumCasesRule.swift | 4 +- ...DuplicatedKeyInDictionaryLiteralRule.swift | 4 +- .../Rules/Lint/DynamicInlineRule.swift | 4 +- .../Lint/EmptyXCTestMethodRuleExamples.swift | 4 +- .../Rules/Lint/ExpiringTodoRule.swift | 4 +- .../Lint/IBInspectableInExtensionRule.swift | 4 +- .../Rules/Lint/IdenticalOperandsRule.swift | 8 +- .../Rules/Lint/InertDeferRule.swift | 4 +- .../Lint/InvalidSwiftLintCommandRule.swift | 4 +- .../Rules/Lint/LocalDocCommentRule.swift | 4 +- .../Rules/Lint/LowerACLThanParentRule.swift | 6 +- .../Rules/Lint/MarkRule.swift | 4 +- .../Rules/Lint/MarkRuleExamples.swift | 6 +- .../Rules/Lint/MissingDocsRule.swift | 4 +- .../Rules/Lint/NSLocalizedStringKeyRule.swift | 4 +- .../NSLocalizedStringRequireBundleRule.swift | 4 +- .../NSNumberInitAsFunctionReferenceRule.swift | 4 +- .../NSObjectPreferIsEqualRuleExamples.swift | 4 +- .../NonOptionalStringDataConversionRule.swift | 4 +- ...ficationCenterDetachmentRuleExamples.swift | 4 +- .../Rules/Lint/OrphanedDocCommentRule.swift | 4 +- .../Rules/Lint/OverriddenSuperCallRule.swift | 4 +- .../Rules/Lint/OverrideInExtensionRule.swift | 4 +- .../Rules/Lint/PeriodSpacingRule.swift | 6 +- .../Rules/Lint/PrivateActionRule.swift | 4 +- .../Rules/Lint/PrivateOutletRule.swift | 4 +- .../Lint/PrivateSubjectRuleExamples.swift | 4 +- ...vateSwiftUIStatePropertyRuleExamples.swift | 6 +- .../Rules/Lint/PrivateUnitTestRule.swift | 6 +- .../Lint/ProhibitedInterfaceBuilderRule.swift | 4 +- .../Rules/Lint/ProhibitedSuperRule.swift | 4 +- .../QuickDiscouragedCallRuleExamples.swift | 4 +- ...ckDiscouragedFocusedTestRuleExamples.swift | 4 +- ...ckDiscouragedPendingTestRuleExamples.swift | 4 +- ...RawValueForCamelCasedCodableEnumRule.swift | 4 +- .../Rules/Lint/RequiredDeinitRule.swift | 4 +- .../Rules/Lint/RequiredEnumCaseRule.swift | 4 +- .../SelfInPropertyInitializationRule.swift | 4 +- .../Rules/Lint/StrongIBOutletRule.swift | 6 +- .../TestCaseAccessibilityRuleExamples.swift | 6 +- .../Rules/Lint/TodoRule.swift | 4 +- .../Rules/Lint/TypesafeArrayInitRule.swift | 4 +- .../Lint/UnhandledThrowingTaskRule.swift | 4 +- .../Lint/UnneededOverrideRuleExamples.swift | 6 +- .../Lint/UnownedVariableCaptureRule.swift | 4 +- .../Rules/Lint/UnusedCaptureListRule.swift | 4 +- .../UnusedClosureParameterRuleExamples.swift | 6 +- .../Lint/UnusedControlFlowLabelRule.swift | 6 +- .../Rules/Lint/UnusedDeclarationRule.swift | 8 +- .../Lint/UnusedDeclarationRuleExamples.swift | 8 +- .../Rules/Lint/UnusedImportRule.swift | 2 +- .../Rules/Lint/UnusedImportRuleExamples.swift | 18 ++--- .../Rules/Lint/UnusedSetterValueRule.swift | 4 +- .../Rules/Lint/ValidIBInspectableRule.swift | 8 +- .../Rules/Lint/WeakDelegateRule.swift | 6 +- .../Rules/Lint/YodaConditionRule.swift | 4 +- .../ClosureBodyLengthRuleExamples.swift | 4 +- .../Metrics/CyclomaticComplexityRule.swift | 4 +- .../EnumCaseAssociatedValuesLengthRule.swift | 4 +- .../Rules/Metrics/FileLengthRule.swift | 14 ++-- .../Metrics/FunctionParameterCountRule.swift | 4 +- .../Metrics/LargeTupleRuleExamples.swift | 4 +- .../Rules/Metrics/LineLengthRule.swift | 4 +- .../Rules/Metrics/NestingRuleExamples.swift | 20 ++--- .../Rules/Metrics/TypeBodyLengthRule.swift | 2 +- .../ContainsOverFilterCountRule.swift | 6 +- .../ContainsOverFilterIsEmptyRule.swift | 6 +- .../ContainsOverFirstNotNilRule.swift | 4 +- .../ContainsOverRangeNilComparisonRule.swift | 2 +- .../EmptyCollectionLiteralRule.swift | 4 +- .../Rules/Performance/EmptyCountRule.swift | 6 +- .../Rules/Performance/EmptyStringRule.swift | 4 +- .../Rules/Performance/FinalTestCaseRule.swift | 6 +- .../Rules/Performance/FirstWhereRule.swift | 4 +- .../FlatMapOverMapReduceRule.swift | 2 +- .../Rules/Performance/LastWhereRule.swift | 4 +- .../Rules/Performance/ReduceBooleanRule.swift | 4 +- .../Rules/Performance/ReduceIntoRule.swift | 4 +- .../Performance/SortedFirstLastRule.swift | 4 +- .../BlanketDisableCommandConfiguration.swift | 2 +- .../DeploymentTargetConfiguration.swift | 2 +- .../DiscouragedDirectInitConfiguration.swift | 2 +- .../FileTypesOrderConfiguration.swift | 2 +- .../InclusiveLanguageConfiguration.swift | 2 +- .../MissingDocsConfiguration.swift | 2 +- .../ModifierOrderConfiguration.swift | 2 +- .../OverriddenSuperCallConfiguration.swift | 2 +- .../ProhibitedSuperConfiguration.swift | 2 +- .../TypeContentsOrderConfiguration.swift | 2 +- .../Rules/Style/AttributesRuleExamples.swift | 4 +- .../Rules/Style/ClosingBraceRule.swift | 4 +- .../ClosureEndIndentationRuleExamples.swift | 6 +- .../Style/ClosureParameterPositionRule.swift | 4 +- .../Rules/Style/ClosureSpacingRule.swift | 8 +- .../Rules/Style/CollectionAlignmentRule.swift | 12 +-- .../Rules/Style/ColonRuleExamples.swift | 6 +- .../Rules/Style/CommaInheritanceRule.swift | 6 +- .../Rules/Style/CommaRule.swift | 6 +- .../ComputedAccessorsOrderRuleExamples.swift | 4 +- .../ConditionalReturnsOnNewlineRule.swift | 4 +- .../Rules/Style/ControlStatementRule.swift | 6 +- .../Rules/Style/DirectReturnRule.swift | 6 +- .../Rules/Style/EmptyEnumArgumentsRule.swift | 6 +- .../Rules/Style/EmptyParametersRule.swift | 6 +- ...tyParenthesesWithTrailingClosureRule.swift | 6 +- .../Rules/Style/ExplicitSelfRule.swift | 2 +- .../Style/ExplicitSelfRuleExamples.swift | 6 +- .../Rules/Style/FileHeaderRule.swift | 4 +- .../Style/FileTypesOrderRuleExamples.swift | 6 +- .../Style/IdentifierNameRuleExamples.swift | 4 +- .../Style/ImplicitGetterRuleExamples.swift | 4 +- .../Style/ImplicitReturnRuleExamples.swift | 32 ++++---- .../Style/InclusiveLanguageRuleExamples.swift | 10 +-- .../Rules/Style/IndentationWidthRule.swift | 4 +- .../Rules/Style/LeadingWhitespaceRule.swift | 12 ++- .../Rules/Style/LetVarWhitespaceRule.swift | 8 +- .../LiteralExpressionEndIndentationRule.swift | 6 +- .../Rules/Style/ModifierOrderRule.swift | 4 +- .../Style/ModifierOrderRuleExamples.swift | 4 +- .../MultilineArgumentsBracketsRule.swift | 4 +- .../MultilineArgumentsRuleExamples.swift | 4 +- .../Style/MultilineFunctionChainsRule.swift | 4 +- .../Style/MultilineLiteralBracketsRule.swift | 4 +- .../MultilineParametersBracketsRule.swift | 4 +- .../MultilineParametersRuleExamples.swift | 4 +- ...tipleClosuresWithTrailingClosureRule.swift | 4 +- .../Rules/Style/NoSpaceInMethodCallRule.swift | 6 +- .../NonOverridableClassDeclarationRule.swift | 6 +- .../Style/NumberSeparatorRuleExamples.swift | 9 ++- .../Style/OpeningBraceRuleExamples.swift | 6 +- .../OperatorFunctionWhitespaceRule.swift | 4 +- .../OperatorUsageWhitespaceRuleExamples.swift | 6 +- .../Style/OptionalEnumCaseMatchingRule.swift | 6 +- ...erSelfInStaticReferencesRuleExamples.swift | 6 +- .../PreferSelfTypeOverTypeOfSelfRule.swift | 6 +- .../Style/PrefixedTopLevelConstantRule.swift | 4 +- .../ProtocolPropertyAccessorsOrderRule.swift | 4 +- .../Style/RedundantDiscardableLetRule.swift | 6 +- .../RedundantSelfInClosureRuleExamples.swift | 6 +- .../Style/ReturnArrowWhitespaceRule.swift | 6 +- .../Rules/Style/SelfBindingRule.swift | 6 +- .../Rules/Style/ShorthandArgumentRule.swift | 4 +- .../Rules/Style/ShorthandOperatorRule.swift | 4 +- .../Rules/Style/SingleTestClassRule.swift | 4 +- .../Rules/Style/SortedEnumCasesRule.swift | 4 +- .../Style/SortedImportsRuleExamples.swift | 6 +- .../Rules/Style/StatementPositionRule.swift | 12 +-- .../Rules/Style/SuperfluousElseRule.swift | 6 +- .../Rules/Style/SwitchCaseAlignmentRule.swift | 12 +-- .../Rules/Style/SwitchCaseOnNewlineRule.swift | 4 +- .../Rules/Style/TrailingClosureRule.swift | 6 +- .../Rules/Style/TrailingCommaRule.swift | 4 +- .../Rules/Style/TrailingNewlineRule.swift | 14 ++-- .../Rules/Style/TrailingWhitespaceRule.swift | 4 +- .../Rules/Style/TypeContentsOrderRule.swift | 2 +- .../Style/TypeContentsOrderRuleExamples.swift | 6 +- ...ededParenthesesInClosureArgumentRule.swift | 6 +- .../Style/UnusedOptionalBindingRule.swift | 4 +- ...VerticalParameterAlignmentOnCallRule.swift | 4 +- ...rticalParameterAlignmentRuleExamples.swift | 4 +- .../VerticalWhitespaceBetweenCasesRule.swift | 6 +- ...lWhitespaceClosingBracesRuleExamples.swift | 4 +- .../VerticalWhitespaceOpeningBracesRule.swift | 4 +- .../Rules/Style/VerticalWhitespaceRule.swift | 6 +- .../Rules/Style/VoidReturnRule.swift | 6 +- .../Extensions/Configuration+Cache.swift | 2 +- .../Extensions/Request+SwiftLint.swift | 2 +- .../SwiftLintCore/Extensions/String+XML.swift | 2 +- ...ftDeclarationAttributeKind+Swiftlint.swift | 12 +-- .../SwiftDeclarationKind+SwiftLint.swift | 8 +- .../Extensions/SwiftSyntax+SwiftLint.swift | 2 +- .../Extensions/SyntaxKind+SwiftLint.swift | 20 +++-- Source/SwiftLintCore/Models/Command.swift | 6 +- .../SwiftLintCore/Models/ReportersList.swift | 2 +- .../SwiftLintCore/Reporters/CSVReporter.swift | 4 +- .../Reporters/CheckstyleReporter.swift | 6 +- .../Reporters/CodeClimateReporter.swift | 8 +- .../GitHubActionsLoggingReporter.swift | 2 +- .../Reporters/GitLabJUnitReporter.swift | 2 +- .../Reporters/JSONReporter.swift | 2 +- .../Reporters/MarkdownReporter.swift | 4 +- .../Reporters/RelativePathReporter.swift | 2 +- .../Reporters/SARIFReporter.swift | 22 ++--- .../Reporters/SonarQubeReporter.swift | 4 +- .../Reporters/SummaryReporter.swift | 6 +- .../Reporters/XcodeReporter.swift | 2 +- .../RegexConfiguration.swift | 2 +- .../SeverityLevelsConfiguration.swift | 6 +- Source/SwiftLintCore/Rules/CoreRules.swift | 2 +- .../Rules/SuperfluousDisableCommandRule.swift | 4 +- .../Visitors/ViolationsSyntaxVisitor.swift | 2 +- .../RuleConfigurationMacros.swift | 4 +- .../SwiftLintCoreMacros.swift | 2 +- .../SwiftLintCoreMacros/SwiftSyntaxRule.swift | 2 +- Source/swiftlint/Commands/Reporters.swift | 4 +- Source/swiftlint/Commands/Rules.swift | 4 +- Source/swiftlint/Commands/SwiftLint.swift | 2 +- .../Extensions/ProcessInfo+XcodeCloud.swift | 2 +- .../Helpers/CompilerArgumentsExtractor.swift | 2 +- Tests/CLITests/RulesFilterTests.swift | 18 ++--- Tests/IntegrationTests/IntegrationTests.swift | 6 +- Tests/MacroTests/AutoApplyTests.swift | 2 +- Tests/MacroTests/SwiftSyntaxRuleTests.swift | 2 +- .../AttributesRuleTests.swift | 25 +++--- .../BaselineTests.swift | 6 +- .../BlanketDisableCommandRuleTests.swift | 4 +- .../CollectingRuleTests.swift | 56 +++++++++---- .../ColonRuleTests.swift | 12 +-- .../CommandTests.swift | 18 ++--- .../ComputedAccessorsOrderRuleTests.swift | 4 +- ...ConditionalReturnsOnNewlineRuleTests.swift | 4 +- .../ConfigurationTests+MultipleConfigs.swift | 32 +++++--- .../ConfigurationTests.swift | 29 ++++--- .../CustomRulesTests.swift | 80 ++++++++++++------- ...clomaticComplexityConfigurationTests.swift | 10 ++- .../DeploymentTargetConfigurationTests.swift | 12 +-- .../DisableAllTests.swift | 2 +- .../DiscouragedDirectInitRuleTests.swift | 4 +- .../EmptyCountRuleTests.swift | 6 +- .../ExpiringTodoRuleTests.swift | 4 +- .../ExplicitInitRuleTests.swift | 4 +- ...licitTypeInterfaceConfigurationTests.swift | 10 ++- .../ExplicitTypeInterfaceRuleTests.swift | 22 ++--- .../FileHeaderRuleTests.swift | 25 +++--- .../FileLengthRuleTests.swift | 2 +- .../FileTypesOrderRuleTests.swift | 6 +- .../FunctionBodyLengthRuleTests.swift | 48 +++++++---- .../GenericTypeNameRuleTests.swift | 8 +- Tests/SwiftLintFrameworkTests/GlobTests.swift | 4 +- .../IdentifierNameRuleTests.swift | 16 ++-- .../ImplicitReturnConfigurationTests.swift | 6 +- ...yUnwrappedOptionalConfigurationTests.swift | 2 +- ...ImplicitlyUnwrappedOptionalRuleTests.swift | 6 +- .../LineLengthConfigurationTests.swift | 22 ++--- .../LineLengthRuleTests.swift | 4 +- .../LinterCacheTests.swift | 8 +- .../MissingDocsRuleTests.swift | 60 ++++++++------ .../ModifierOrderTests.swift | 44 +++++----- .../MultilineArgumentsRuleTests.swift | 12 +-- .../NameConfigurationTests.swift | 12 +-- .../NestingRuleTests.swift | 16 ++-- .../NumberSeparatorRuleTests.swift | 22 ++--- .../ObjectLiteralRuleTests.swift | 2 +- .../OpeningBraceRuleTests.swift | 6 +- .../PrefixedTopLevelConstantRuleTests.swift | 4 +- .../PrivateOverFilePrivateRuleTests.swift | 4 +- .../RegexConfigurationTests.swift | 18 ++--- .../SwiftLintFrameworkTests/RegionTests.swift | 8 +- .../ReporterTests.swift | 2 +- .../RuleConfigurationDescriptionTests.swift | 4 +- .../RuleConfigurationTests.swift | 18 +++-- .../TrailingClosureConfigurationTests.swift | 8 +- .../TrailingClosureRuleTests.swift | 4 +- .../TrailingCommaRuleTests.swift | 4 +- .../TrailingWhitespaceRuleTests.swift | 2 +- .../TypeContentsOrderRuleTests.swift | 18 ++--- .../TypeNameRuleTests.swift | 8 +- .../UnneededOverrideRuleTests.swift | 6 +- .../UnusedDeclarationConfigurationTests.swift | 2 +- .../VerticalWhitespaceRuleTests.swift | 2 +- Tests/SwiftLintTestHelpers/TestHelpers.swift | 5 +- 357 files changed, 1255 insertions(+), 1098 deletions(-) diff --git a/.sourcery/BuiltInRules.stencil b/.sourcery/BuiltInRules.stencil index 45ef080360..79ffcc8a7b 100644 --- a/.sourcery/BuiltInRules.stencil +++ b/.sourcery/BuiltInRules.stencil @@ -1,5 +1,5 @@ /// The rule list containing all available rules built into SwiftLint. public let builtInRules: [any Rule.Type] = [ -{% for rule in types.structs where rule.name|hasSuffix:"Rule" %} {{ rule.name }}.self{% if not forloop.last %},{% endif %} +{% for rule in types.structs where rule.name|hasSuffix:"Rule" %} {{ rule.name }}.self, {% endfor %}] diff --git a/.sourcery/ReportersList.stencil b/.sourcery/ReportersList.stencil index 404eda2942..6e35c46e6f 100644 --- a/.sourcery/ReportersList.stencil +++ b/.sourcery/ReportersList.stencil @@ -2,6 +2,6 @@ /// The reporters list containing all the reporters built into SwiftLint. public let reportersList: [any Reporter.Type] = [ {% for reporter in types.structs where reporter.name|hasSuffix:"Reporter" %} - {{ reporter.name }}.self{% if not forloop.last %},{% endif %} + {{ reporter.name }}.self, {% endfor %} ] diff --git a/.swiftlint.yml b/.swiftlint.yml index 456678cd5e..808f32ed4e 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -82,6 +82,8 @@ number_separator: redundant_type_annotation: consider_default_literal_types_redundant: true single_test_class: *unit_test_configuration +trailing_comma: + mandatory_comma: true type_body_length: 400 unneeded_override: affect_initializers: true diff --git a/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift b/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift index 65fbe02129..2005c4dfda 100644 --- a/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift +++ b/Plugins/SwiftLintBuildToolPlugin/SwiftLintBuildToolPlugin.swift @@ -57,7 +57,7 @@ struct SwiftLintBuildToolPlugin: BuildToolPlugin { // We always pass all of the Swift source files in the target to the tool, // so we need to ensure that any exclusion rules in the configuration are // respected. - "--force-exclude" + "--force-exclude", ] // Determine whether we need to enable cache or not (for Xcode Cloud we don't) let cacheArguments: [String] @@ -76,7 +76,7 @@ struct SwiftLintBuildToolPlugin: BuildToolPlugin { executable: executable.path, arguments: arguments + cacheArguments + swiftFiles.map(\.string), environment: environment, - outputFilesDirectory: outputPath) + outputFilesDirectory: outputPath), ] } } diff --git a/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift b/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift index caea996073..fc6a4d52fd 100644 --- a/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift +++ b/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift @@ -144,7 +144,7 @@ extension SourceKittenDictionary { SwiftUIModifier( name: "accessibility", arguments: [.init(name: "hidden", values: ["true"])] - ) + ), ], in: file ) @@ -158,7 +158,7 @@ extension SourceKittenDictionary { SwiftUIModifier( name: "accessibilityElement", arguments: [.init(name: "children", required: false, values: [".ignore"], matchType: .suffix)] - ) + ), ], in: file ) diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 3c1332980a..e0c198a06d 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -238,5 +238,5 @@ public let builtInRules: [any Rule.Type] = [ WeakDelegateRule.self, XCTFailMessageRule.self, XCTSpecificMatcherRule.self, - YodaConditionRule.self + YodaConditionRule.self, ] diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/AnonymousArgumentInMultilineClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/AnonymousArgumentInMultilineClosureRule.swift index ab214fade3..332668063b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/AnonymousArgumentInMultilineClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/AnonymousArgumentInMultilineClosureRule.swift @@ -21,14 +21,14 @@ struct AnonymousArgumentInMultilineClosureRule: OptInRule { closure { arg in nestedClosure { $0 + arg } } - """) + """), ], triggeringExamples: [ Example(""" closure { print(↓$0) } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/BlockBasedKVORule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/BlockBasedKVORule.swift index 0554ce90a4..e0115da924 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/BlockBasedKVORule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/BlockBasedKVORule.swift @@ -14,7 +14,7 @@ struct BlockBasedKVORule: Rule { let observer = foo.observe(\.value, options: [.new]) { (foo, change) in print(change.newValue) } - """#) + """#), ], triggeringExamples: [ Example(""" @@ -30,7 +30,7 @@ struct BlockBasedKVORule: Rule { change: Dictionary?, context: UnsafeMutableRawPointer?) {} } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ConvenienceTypeRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ConvenienceTypeRule.swift index 049817115c..50c4f7002a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ConvenienceTypeRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ConvenienceTypeRule.swift @@ -73,7 +73,7 @@ struct ConvenienceTypeRule: OptInRule { @globalActor actor MyActor { static let shared = MyActor() } - """) + """), ], triggeringExamples: [ Example(""" @@ -112,7 +112,7 @@ struct ConvenienceTypeRule: OptInRule { ↓class SomeClass { static func foo() {} } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedAssertRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedAssertRule.swift index f23f7cccf6..266cbc3269 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedAssertRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedAssertRule.swift @@ -14,13 +14,13 @@ struct DiscouragedAssertRule: OptInRule { Example(#"assert(true, "foobar")"#), Example(#"assert(true, "foobar", file: "toto", line: 42)"#), Example(#"assert(false || true)"#), - Example(#"XCTAssert(false)"#) + Example(#"XCTAssert(false)"#), ], triggeringExamples: [ Example(#"↓assert(false)"#), Example(#"↓assert(false, "foobar")"#), Example(#"↓assert(false, "foobar", file: "toto", line: 42)"#), - Example(#"↓assert( false , "foobar")"#) + Example(#"↓assert( false , "foobar")"#), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedNoneNameRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedNoneNameRule.swift index e80b19c359..a496e6e87f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedNoneNameRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedNoneNameRule.swift @@ -83,7 +83,7 @@ struct DiscouragedNoneNameRule: OptInRule { class MyClass { var none = MyClass() } - """) + """), ], triggeringExamples: [ Example(""" @@ -174,7 +174,7 @@ struct DiscouragedNoneNameRule: OptInRule { struct MyStruct { ↓static var none = MyStruct(), a = MyStruct() } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift index 0e5f7c6cf5..f818d0f2dc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedObjectLiteralRule.swift @@ -15,11 +15,11 @@ struct DiscouragedObjectLiteralRule: OptInRule { Example("let color = UIColor(red: value, green: value, blue: value, alpha: 1)"), Example("let image = NSImage(named: aVariable)"), Example("let image = NSImage(named: \"interpolated \\(variable)\")"), - Example("let color = NSColor(red: value, green: value, blue: value, alpha: 1)") + Example("let color = NSColor(red: value, green: value, blue: value, alpha: 1)"), ], triggeringExamples: [ Example("let image = ↓#imageLiteral(resourceName: \"image.jpg\")"), - Example("let color = ↓#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)") + Example("let color = ↓#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift index 883717df27..77b3056c03 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift @@ -47,7 +47,7 @@ internal struct DiscouragedOptionalBooleanRuleExamples { wrapExample("enum", "func foo(input: Bool = true) {}"), wrapExample("enum", "func foo(input: [String: Bool] = [:]) {}"), - wrapExample("enum", "func foo(input: [Bool] = []) {}") + wrapExample("enum", "func foo(input: [Bool] = []) {}"), ] static let triggeringExamples = [ @@ -157,7 +157,7 @@ internal struct DiscouragedOptionalBooleanRuleExamples { wrapExample("enum", "static func foo(input: [↓Bool?]) {}"), // Optional chaining - Example("_ = ↓Bool?.values()") + Example("_ = ↓Bool?.values()"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift index e2aaeee150..ea8e5b76df 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift @@ -51,7 +51,7 @@ internal struct DiscouragedOptionalCollectionExamples { wrapExample("enum", "func foo(input: [String] = []) {}"), wrapExample("enum", "func foo(input: [String: String] = [:]) {}"), - wrapExample("enum", "func foo(input: Set = []) {}") + wrapExample("enum", "func foo(input: Set = []) {}"), ] static let triggeringExamples = [ @@ -204,7 +204,7 @@ internal struct DiscouragedOptionalCollectionExamples { wrapExample("enum", "static func foo(input: [String: ↓[String: String]?]) {}"), wrapExample("enum", "static func foo(input: ↓[String: ↓[String: String]?]?) {}"), wrapExample("enum", "static func foo(_ dict1: [K: V], _ dict2: ↓[K: V]?) -> [K: V]"), - wrapExample("enum", "static func foo(dict1: [K: V], dict2: ↓[K: V]?) -> [K: V]") + wrapExample("enum", "static func foo(dict1: [K: V], dict2: ↓[K: V]?) -> [K: V]"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift index 30aa2332f4..87a41dfee2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift @@ -9,7 +9,7 @@ struct DuplicateImportsRule: SwiftSyntaxCorrectableRule { static let importKinds = [ "typealias", "struct", "class", "enum", "protocol", "let", - "var", "func" + "var", "func", ] static let description = RuleDescription( diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift index a2c29282b7..2cd2c8d6e8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift @@ -32,7 +32,7 @@ internal struct DuplicateImportsRuleExamples { #if TEST func test() { } - """) + """), ] static let triggeringExamples = Array(corrections.keys.sorted()) @@ -169,7 +169,7 @@ internal struct DuplicateImportsRuleExamples { """, excludeFromDocumentation: true): Example(""" import A - """) + """), ] DuplicateImportsRule.importKinds.map { importKind in diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift index a3cdde9f18..fa2891d567 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift @@ -76,7 +76,7 @@ struct ExplicitACLRule: OptInRule { let b = 2 } } - """) + """), ], triggeringExamples: [ Example("↓enum A {}"), @@ -101,7 +101,7 @@ struct ExplicitACLRule: OptInRule { ↓let b = 2 } } - """) + """), ] ) } @@ -121,7 +121,7 @@ private extension ExplicitACLRule { SubscriptDeclSyntax.self, VariableDeclSyntax.self, ProtocolDeclSyntax.self, - InitializerDeclSyntax.self + InitializerDeclSyntax.self, ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitEnumRawValueRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitEnumRawValueRule.swift index 2177f135ed..7191dbd589 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitEnumRawValueRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitEnumRawValueRule.swift @@ -39,7 +39,7 @@ struct ExplicitEnumRawValueRule: OptInRule { enum Numbers: Algebra { case one } - """) + """), ], triggeringExamples: [ Example(""" @@ -74,7 +74,7 @@ struct ExplicitEnumRawValueRule: OptInRule { case ↓one, ↓two } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitInitRule.swift index c25ead7e36..3a0add4f3a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitInitRule.swift @@ -48,7 +48,7 @@ struct ExplicitInitRule: OptInRule { obs2, resultSelector: MyType.init ).asMaybe() - """) + """), ], triggeringExamples: [ Example(""" @@ -86,7 +86,7 @@ struct ExplicitInitRule: OptInRule { .init(1.0) - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], corrections: [ Example(""" @@ -178,7 +178,7 @@ struct ExplicitInitRule: OptInRule { Example("_ = GleanMetrics.Tabs.GroupedTabExtra↓.init()"): Example("_ = GleanMetrics.Tabs.GroupedTabExtra()"), Example("_ = Set↓.init()"): - Example("_ = Set()") + Example("_ = Set()"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift index 56c30b7040..e5295b3e96 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift @@ -18,14 +18,14 @@ struct ExplicitTopLevelACLRule: OptInRule { Example("internal\nclass Foo {}"), Example("internal func a() {}"), Example("extension A: Equatable {}"), - Example("extension A {}") + Example("extension A {}"), ], triggeringExamples: [ Example("↓enum A {}"), Example("final ↓class B {}"), Example("↓struct C {}"), Example("↓func a() {}"), - Example("internal let a = 0\n↓func b() {}") + Example("internal let a = 0\n↓func b() {}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTypeInterfaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTypeInterfaceRule.swift index b37a318712..ec4fc88fe6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTypeInterfaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTypeInterfaceRule.swift @@ -34,7 +34,7 @@ struct ExplicitTypeInterfaceRule: OptInRule { func f() { if case .failure(let error) = errorCompletion {} } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -66,7 +66,7 @@ struct ExplicitTypeInterfaceRule: OptInRule { class Foo { let ↓myVar = Set(0) } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift index 242bfa05a2..107190ee69 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift @@ -102,7 +102,7 @@ struct ExtensionAccessModifierRule: OptInRule { public extension Foo { private(set) var value: Int { 1 } } - """) + """), ], triggeringExamples: [ Example(""" @@ -166,7 +166,7 @@ struct ExtensionAccessModifierRule: OptInRule { ↓extension Foo { private(set) public var value: Int { 1 } } - """) + """), ] ) } @@ -190,7 +190,7 @@ private extension ExtensionAccessModifierRule { .explicit(.keyword(.internal)), .explicit(.keyword(.private)), .explicit(.keyword(.open)), - .implicit + .implicit, ].contains(acl) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FallthroughRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FallthroughRule.swift index f8671cf27e..6b07fe9310 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FallthroughRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FallthroughRule.swift @@ -15,7 +15,7 @@ struct FallthroughRule: OptInRule { case .bar, .bar2, .bar3: something() } - """) + """), ], triggeringExamples: [ Example(""" @@ -25,7 +25,7 @@ struct FallthroughRule: OptInRule { case .bar2: something() } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FatalErrorMessageRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FatalErrorMessageRule.swift index b50be5e4de..4d7af1dc8b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FatalErrorMessageRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FatalErrorMessageRule.swift @@ -19,7 +19,7 @@ struct FatalErrorMessageRule: OptInRule { func foo() { fatalError(x) } - """) + """), ], triggeringExamples: [ Example(""" @@ -31,7 +31,7 @@ struct FatalErrorMessageRule: OptInRule { func foo() { ↓fatalError() } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameNoSpaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameNoSpaceRule.swift index 24f8afae05..892ca60313 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameNoSpaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameNoSpaceRule.swift @@ -19,8 +19,12 @@ struct FileNameNoSpaceRule: OptInRule, SourceKitFreeRule { return [] } - return [StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: filePath, line: 1))] + return [ + StyleViolation( + ruleDescription: Self.description, + severity: configuration.severity, + location: Location(file: filePath, line: 1) + ), + ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift index fc8839f43d..d3554619eb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift @@ -45,9 +45,13 @@ struct FileNameRule: OptInRule, SourceKitFreeRule { return [] } - return [StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: filePath, line: 1))] + return [ + StyleViolation( + ruleDescription: Self.description, + severity: configuration.severity, + location: Location(file: filePath, line: 1) + ), + ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForWhereRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForWhereRule.swift index e6cc7b2a51..5292e8d287 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForWhereRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForWhereRule.swift @@ -90,7 +90,7 @@ struct ForWhereRule: Rule { return derivedValue != 0 } } - """, configuration: ["allow_for_as_filter": true]) + """, configuration: ["allow_for_as_filter": true]), ], triggeringExamples: [ Example(""" @@ -113,7 +113,7 @@ struct ForWhereRule: Rule { subview.removeFromSuperview() } } - """, configuration: ["allow_for_as_filter": true]) + """, configuration: ["allow_for_as_filter": true]), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceTryRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceTryRule.swift index e86f4499ab..c1387dfb37 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceTryRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceTryRule.swift @@ -15,13 +15,13 @@ struct ForceTryRule: Rule { do { try a() } catch {} - """) + """), ], triggeringExamples: [ Example(""" func a() throws {} ↓try! a() - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceUnwrappingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceUnwrappingRule.swift index 0a2baaeab8..261f36df97 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceUnwrappingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceUnwrappingRule.swift @@ -29,7 +29,7 @@ struct ForceUnwrappingRule: OptInRule { Example("func foo() -> [Int]!"), Example("func foo() -> [AnyHashable: Any]!"), Example("func foo() -> [Int]! { return [] }"), - Example("return self") + Example("return self"), ], triggeringExamples: [ Example("let url = NSURL(string: query)↓!"), @@ -62,7 +62,7 @@ struct ForceUnwrappingRule: OptInRule { Example("open var computed: String { return foo.bar↓! }"), Example("return self↓!"), Example("[1, 3, 5, 6].first { $0.isMultiple(of: 2) }↓!"), - Example("map[\"a\"]↓!↓!") + Example("map[\"a\"]↓!↓!"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift index 0663543107..764162b808 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift @@ -41,12 +41,12 @@ struct FunctionDefaultParameterAtEndRule: OptInRule { """), Example(""" func expect(file: String = #file, _ expression: @autoclosure () -> (() throws -> T)) -> Expectation {} - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example("↓func foo(bar: Int = 0, baz: String) {}"), Example("private ↓func foo(bar: Int = 0, baz: String) {}"), - Example("public ↓init?(for date: Date = Date(), coordinate: CLLocationCoordinate2D) {}") + Example("public ↓init?(for date: Date = Date(), coordinate: CLLocationCoordinate2D) {}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift index 0864c43827..154a6b6173 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift @@ -28,7 +28,7 @@ struct GenericTypeNameRule: Rule { Example("func configureWith(data: Either)"), Example("typealias StringDictionary = Dictionary"), Example("typealias BackwardTriple = (T3, T2, T1)"), - Example("typealias DictionaryOfStrings = Dictionary") + Example("typealias DictionaryOfStrings = Dictionary"), ], triggeringExamples: [ Example("func foo<↓T_Foo>() {}"), @@ -37,14 +37,14 @@ struct GenericTypeNameRule: Rule { Example("func foo<↓type>() {}"), Example("typealias StringDictionary<↓T_Foo> = Dictionary"), Example("typealias BackwardTriple = (T3, T2_Bar, T1)"), - Example("typealias DictionaryOfStrings<↓T_Foo: Hashable> = Dictionary") + Example("typealias DictionaryOfStrings<↓T_Foo: Hashable> = Dictionary"), ] + ["class", "struct", "enum"].flatMap { type -> [Example] in return [ Example("\(type) Foo<↓T_Foo> {}"), Example("\(type) Foo {}"), Example("\(type) Foo<↓T_Foo, ↓U_Foo> {}"), Example("\(type) Foo<↓\(String(repeating: "T", count: 21))> {}"), - Example("\(type) Foo<↓type> {}") + Example("\(type) Foo<↓type> {}"), ] } ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ImplicitlyUnwrappedOptionalRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ImplicitlyUnwrappedOptionalRule.swift index 8bbad1c1c4..6b64ce7901 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ImplicitlyUnwrappedOptionalRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ImplicitlyUnwrappedOptionalRule.swift @@ -21,7 +21,7 @@ struct ImplicitlyUnwrappedOptionalRule: OptInRule { @IBOutlet weak var bar: SomeObject! } - """, configuration: ["mode": "all_except_iboutlets"], excludeFromDocumentation: true) + """, configuration: ["mode": "all_except_iboutlets"], excludeFromDocumentation: true), ], triggeringExamples: [ Example("let label: ↓UILabel!"), @@ -38,7 +38,7 @@ struct ImplicitlyUnwrappedOptionalRule: OptInRule { class MyClass { weak var bar: ↓SomeObject! } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/IsDisjointRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/IsDisjointRule.swift index 696c31fbe0..63709b730e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/IsDisjointRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/IsDisjointRule.swift @@ -13,11 +13,11 @@ struct IsDisjointRule: Rule { Example("_ = Set(syntaxKinds).isDisjoint(with: commentAndStringKindsSet)"), Example("let isObjc = !objcAttributes.isDisjoint(with: dictionary.enclosedSwiftAttributes)"), Example("_ = Set(syntaxKinds).intersection(commentAndStringKindsSet)"), - Example("_ = !objcAttributes.intersection(dictionary.enclosedSwiftAttributes)") + Example("_ = !objcAttributes.intersection(dictionary.enclosedSwiftAttributes)"), ], triggeringExamples: [ Example("_ = Set(syntaxKinds).↓intersection(commentAndStringKindsSet).isEmpty"), - Example("let isObjc = !objcAttributes.↓intersection(dictionary.enclosedSwiftAttributes).isEmpty") + Example("let isObjc = !objcAttributes.↓intersection(dictionary.enclosedSwiftAttributes).isEmpty"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/JoinedDefaultParameterRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/JoinedDefaultParameterRule.swift index d688abea81..d5e0a435c9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/JoinedDefaultParameterRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/JoinedDefaultParameterRule.swift @@ -12,7 +12,7 @@ struct JoinedDefaultParameterRule: OptInRule { nonTriggeringExamples: [ Example("let foo = bar.joined()"), Example("let foo = bar.joined(separator: \",\")"), - Example("let foo = bar.joined(separator: toto)") + Example("let foo = bar.joined(separator: toto)"), ], triggeringExamples: [ Example("let foo = bar.joined(↓separator: \"\")"), @@ -24,7 +24,7 @@ struct JoinedDefaultParameterRule: OptInRule { func foo() -> String { return ["1", "2"].joined(↓separator: "") } - """) + """), ], corrections: [ Example("let foo = bar.joined(↓separator: \"\")"): Example("let foo = bar.joined()"), @@ -33,7 +33,7 @@ struct JoinedDefaultParameterRule: OptInRule { Example("func foo() -> String {\n return [\"1\", \"2\"].joined(↓separator: \"\")\n}"): Example("func foo() -> String {\n return [\"1\", \"2\"].joined()\n}"), Example("class C {\n#if true\nlet foo = bar.joined(↓separator: \"\")\n#endif\n}"): - Example("class C {\n#if true\nlet foo = bar.joined()\n#endif\n}") + Example("class C {\n#if true\nlet foo = bar.joined()\n#endif\n}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyCGGeometryFunctionsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyCGGeometryFunctionsRule.swift index 69fa8e97c0..2cfecead4f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyCGGeometryFunctionsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyCGGeometryFunctionsRule.swift @@ -27,7 +27,7 @@ struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule { // "rect.divide(atDistance: 10.2, fromEdge: edge)", No correction available for divide Example("rect1.contains(rect2)"), Example("rect.contains(point)"), - Example("rect1.intersects(rect2)") + Example("rect1.intersects(rect2)"), ], triggeringExamples: [ Example("↓CGRectGetWidth(rect)"), @@ -49,7 +49,7 @@ struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule { Example("↓CGRectIntersection(rect1, rect2)"), Example("↓CGRectContainsRect(rect1, rect2)"), Example("↓CGRectContainsPoint(rect, point)"), - Example("↓CGRectIntersectsRect(rect1, rect2)") + Example("↓CGRectIntersectsRect(rect1, rect2)"), ], corrections: [ Example("↓CGRectGetWidth( rect )"): Example("rect.width"), @@ -73,7 +73,7 @@ struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule { Example("↓CGRectContainsPoint(rect ,point)"): Example("rect.contains(point)"), Example("↓CGRectIntersectsRect( rect1,rect2 )"): Example("rect1.intersects(rect2)"), Example("↓CGRectIntersectsRect(rect1, rect2 )\n↓CGRectGetWidth(rect )"): - Example("rect1.intersects(rect2)\nrect.width") + Example("rect1.intersects(rect2)\nrect.width"), ] ) @@ -97,7 +97,7 @@ struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule { "CGRectContainsRect": .function(name: "contains", argumentLabels: [""]), "CGRectContainsPoint": .function(name: "contains", argumentLabels: [""]), "CGRectIntersectsRect": .function(name: "intersects", argumentLabels: [""]), - "CGRectIntersection": .function(name: "intersection", argumentLabels: [""]) + "CGRectIntersection": .function(name: "intersection", argumentLabels: [""]), ] func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstantRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstantRuleExamples.swift index 81676f5557..b7267bae49 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstantRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstantRuleExamples.swift @@ -9,7 +9,7 @@ internal struct LegacyConstantRuleExamples { Example("NSSize.zero"), Example("CGRect.null"), Example("CGFloat.pi"), - Example("Float.pi") + Example("Float.pi"), ] static let triggeringExamples: [Example] = [ @@ -22,7 +22,7 @@ internal struct LegacyConstantRuleExamples { Example("↓NSZeroSize"), Example("↓CGRectNull"), Example("↓CGFloat(M_PI)"), - Example("↓Float(M_PI)") + Example("↓Float(M_PI)"), ] static let corrections: [Example: Example] = [ @@ -37,7 +37,7 @@ internal struct LegacyConstantRuleExamples { Example("↓CGRectInfinite\n↓CGRectNull"): Example("CGRect.infinite\nCGRect.null"), Example("↓CGFloat(M_PI)"): Example("CGFloat.pi"), Example("↓Float(M_PI)"): Example("Float.pi"), - Example("↓CGFloat(M_PI)\n↓Float(M_PI)"): Example("CGFloat.pi\nFloat.pi") + Example("↓CGFloat(M_PI)\n↓Float(M_PI)"): Example("CGFloat.pi\nFloat.pi"), ] static let patterns = [ @@ -48,6 +48,6 @@ internal struct LegacyConstantRuleExamples { "NSZeroPoint": "NSPoint.zero", "NSZeroRect": "NSRect.zero", "NSZeroSize": "NSSize.zero", - "CGRectNull": "CGRect.null" + "CGRectNull": "CGRect.null", ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstructorRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstructorRule.swift index 3a2aabaa37..c61fb0bdeb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstructorRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyConstructorRule.swift @@ -31,7 +31,7 @@ struct LegacyConstructorRule: Rule { Example("NSEdgeInsets(top: 0, left: 0, bottom: 10, right: 10)"), Example("NSEdgeInsets(top: aTop, left: aLeft, bottom: aBottom, right: aRight)"), Example("UIOffset(horizontal: 0, vertical: 10)"), - Example("UIOffset(horizontal: horizontal, vertical: vertical)") + Example("UIOffset(horizontal: horizontal, vertical: vertical)"), ], triggeringExamples: [ Example("↓CGPointMake(10, 10)"), @@ -57,7 +57,7 @@ struct LegacyConstructorRule: Rule { Example("↓NSEdgeInsetsMake(top, left, bottom, right)"), Example("↓CGVectorMake(10, 10)\n↓NSMakeRange(10, 1)"), Example("↓UIOffsetMake(0, 10)"), - Example("↓UIOffsetMake(horizontal, vertical)") + Example("↓UIOffsetMake(horizontal, vertical)"), ], corrections: [ Example("↓CGPointMake(10, 10)"): Example("CGPoint(x: 10, y: 10)"), @@ -95,33 +95,37 @@ struct LegacyConstructorRule: Rule { Example("↓CGPointMake(calculateX(), 10)"): Example("CGPoint(x: calculateX(), y: 10)"), Example("↓UIOffsetMake(0, 10)"): Example("UIOffset(horizontal: 0, vertical: 10)"), Example("↓UIOffsetMake(horizontal, vertical)"): - Example("UIOffset(horizontal: horizontal, vertical: vertical)") + Example("UIOffset(horizontal: horizontal, vertical: vertical)"), ] ) - private static let constructorsToArguments = ["CGRectMake": ["x", "y", "width", "height"], - "CGPointMake": ["x", "y"], - "CGSizeMake": ["width", "height"], - "CGVectorMake": ["dx", "dy"], - "NSMakePoint": ["x", "y"], - "NSMakeSize": ["width", "height"], - "NSMakeRect": ["x", "y", "width", "height"], - "NSMakeRange": ["location", "length"], - "UIEdgeInsetsMake": ["top", "left", "bottom", "right"], - "NSEdgeInsetsMake": ["top", "left", "bottom", "right"], - "UIOffsetMake": ["horizontal", "vertical"]] + private static let constructorsToArguments = [ + "CGRectMake": ["x", "y", "width", "height"], + "CGPointMake": ["x", "y"], + "CGSizeMake": ["width", "height"], + "CGVectorMake": ["dx", "dy"], + "NSMakePoint": ["x", "y"], + "NSMakeSize": ["width", "height"], + "NSMakeRect": ["x", "y", "width", "height"], + "NSMakeRange": ["location", "length"], + "UIEdgeInsetsMake": ["top", "left", "bottom", "right"], + "NSEdgeInsetsMake": ["top", "left", "bottom", "right"], + "UIOffsetMake": ["horizontal", "vertical"], + ] - private static let constructorsToCorrectedNames = ["CGRectMake": "CGRect", - "CGPointMake": "CGPoint", - "CGSizeMake": "CGSize", - "CGVectorMake": "CGVector", - "NSMakePoint": "NSPoint", - "NSMakeSize": "NSSize", - "NSMakeRect": "NSRect", - "NSMakeRange": "NSRange", - "UIEdgeInsetsMake": "UIEdgeInsets", - "NSEdgeInsetsMake": "NSEdgeInsets", - "UIOffsetMake": "UIOffset"] + private static let constructorsToCorrectedNames = [ + "CGRectMake": "CGRect", + "CGPointMake": "CGPoint", + "CGSizeMake": "CGSize", + "CGVectorMake": "CGVector", + "NSMakePoint": "NSPoint", + "NSMakeSize": "NSSize", + "NSMakeRect": "NSRect", + "NSMakeRange": "NSRange", + "UIEdgeInsetsMake": "UIEdgeInsets", + "NSEdgeInsetsMake": "NSEdgeInsets", + "UIOffsetMake": "UIOffset", + ] } private extension LegacyConstructorRule { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyHashingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyHashingRule.swift index 3d64c4ca1f..9ef7c6db57 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyHashingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyHashingRule.swift @@ -50,7 +50,7 @@ struct LegacyHashingRule: Rule { set { bar = newValue } } } - """) + """), ], triggeringExamples: [ Example(""" @@ -70,7 +70,7 @@ struct LegacyHashingRule: Rule { return bar } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyMultipleRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyMultipleRule.swift index ea7b51a000..971647780e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyMultipleRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyMultipleRule.swift @@ -22,7 +22,7 @@ struct LegacyMultipleRule: OptInRule { let constant = 56 let secret = value % constant == 5 """), - Example("let secretValue = (value % 3) + 2") + Example("let secretValue = (value % 3) + 2"), ], triggeringExamples: [ Example("cell.contentView.backgroundColor = indexPath.row ↓% 2 == 0 ? .gray : .white"), @@ -34,7 +34,7 @@ struct LegacyMultipleRule: OptInRule { Example(""" let constant = 56 let isMultiple = value ↓% constant == 0 - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyNSGeometryFunctionsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyNSGeometryFunctionsRule.swift index 4dcf209e85..e73654907c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyNSGeometryFunctionsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyNSGeometryFunctionsRule.swift @@ -24,7 +24,7 @@ struct LegacyNSGeometryFunctionsRule: SwiftSyntaxCorrectableRule { // "rect.divide(atDistance: 10.2, fromEdge: edge)", No correction available for divide Example("rect1.contains(rect2)"), Example("rect.contains(point)"), - Example("rect1.intersects(rect2)") + Example("rect1.intersects(rect2)"), ], triggeringExamples: [ Example("↓NSWidth(rect)"), @@ -47,7 +47,7 @@ struct LegacyNSGeometryFunctionsRule: SwiftSyntaxCorrectableRule { Example("↓NSIntersectionRect(rect1, rect2)"), Example("↓NSContainsRect(rect1, rect2)"), Example("↓NSPointInRect(rect, point)"), - Example("↓NSIntersectsRect(rect1, rect2)") + Example("↓NSIntersectsRect(rect1, rect2)"), ], corrections: [ Example("↓NSWidth( rect )"): Example("rect.width"), @@ -72,7 +72,7 @@ struct LegacyNSGeometryFunctionsRule: SwiftSyntaxCorrectableRule { Example("↓NSIntersectsRect( rect1,rect2 )"): Example("rect1.intersects(rect2)"), Example("↓NSIntersectsRect(rect1, rect2 )\n↓NSWidth(rect )"): Example("rect1.intersects(rect2)\nrect.width"), - Example("↓NSIntersectionRect(rect1, rect2)"): Example("rect1.intersection(rect2)") + Example("↓NSIntersectionRect(rect1, rect2)"): Example("rect1.intersection(rect2)"), ] ) @@ -97,7 +97,7 @@ struct LegacyNSGeometryFunctionsRule: SwiftSyntaxCorrectableRule { "NSContainsRect": .function(name: "contains", argumentLabels: [""]), "NSIntersectsRect": .function(name: "intersects", argumentLabels: [""]), "NSIntersectionRect": .function(name: "intersection", argumentLabels: [""]), - "NSPointInRect": .function(name: "contains", argumentLabels: [""], reversed: true) + "NSPointInRect": .function(name: "contains", argumentLabels: [""], reversed: true), ] func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyObjcTypeRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyObjcTypeRule.swift index 21b8a792ab..82da70f894 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyObjcTypeRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyObjcTypeRule.swift @@ -25,7 +25,7 @@ private let legacyObjcTypes = [ "NSURLComponents", "NSURLQueryItem", "NSURLRequest", - "NSUUID" + "NSUUID", ] @SwiftSyntaxRule @@ -43,7 +43,7 @@ struct LegacyObjcTypeRule: OptInRule { Example("var formatter: NSDataDetector"), Example("var className: String = NSStringFromClass(MyClass.self)"), Example("_ = URLRequest.CachePolicy.reloadIgnoringLocalCacheData"), - Example(#"_ = Notification.Name("com.apple.Music.playerInfo")"#) + Example(#"_ = Notification.Name("com.apple.Music.playerInfo")"#), ], triggeringExamples: [ Example("var array = ↓NSArray()"), @@ -63,7 +63,7 @@ struct LegacyObjcTypeRule: OptInRule { return Foundation.Notification.Name("org.wordpress.reachability.changed") } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyRandomRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyRandomRule.swift index 5b0686589b..d20cb859f7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyRandomRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/LegacyRandomRule.swift @@ -12,12 +12,12 @@ struct LegacyRandomRule: Rule { nonTriggeringExamples: [ Example("Int.random(in: 0..<10)"), Example("Double.random(in: 8.6...111.34)"), - Example("Float.random(in: 0 ..< 1)") + Example("Float.random(in: 0 ..< 1)"), ], triggeringExamples: [ Example("↓arc4random()"), Example("↓arc4random_uniform(83)"), - Example("↓drand48()") + Example("↓drand48()"), ] ) } @@ -27,7 +27,7 @@ private extension LegacyRandomRule { private static let legacyRandomFunctions: Set = [ "arc4random", "arc4random_uniform", - "drand48" + "drand48", ] override func visitPost(_ node: FunctionCallExprSyntax) { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift index 59950d7f02..093c569751 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NimbleOperatorRule.swift @@ -29,7 +29,7 @@ struct NimbleOperatorRule: OptInRule { expect(value).to(equal(expectedValue), description: "Failed") return Bar(value: ()) } - """) + """), ], triggeringExamples: [ Example("↓expect(seagull.squawk).toNot(equal(\"Hi\"))"), @@ -45,7 +45,7 @@ struct NimbleOperatorRule: OptInRule { Example("↓expect(success).to(beFalse())"), Example("↓expect(value).to(beNil())"), Example("↓expect(value).toNot(beNil())"), - Example("expect(10) > 2\n ↓expect(10).to(beGreaterThan(2))") + Example("expect(10) > 2\n ↓expect(10).to(beGreaterThan(2))"), ], corrections: [ Example("↓expect(seagull.squawk).toNot(equal(\"Hi\"))"): Example("expect(seagull.squawk) != \"Hi\""), @@ -65,7 +65,7 @@ struct NimbleOperatorRule: OptInRule { Example("↓expect(success).toNot(beTrue())"): Example("expect(success) != true"), Example("↓expect(value).to(beNil())"): Example("expect(value) == nil"), Example("↓expect(value).toNot(beNil())"): Example("expect(value) != nil"), - Example("expect(10) > 2\n ↓expect(10).to(beGreaterThan(2))"): Example("expect(10) > 2\n expect(10) > 2") + Example("expect(10) > 2\n ↓expect(10).to(beGreaterThan(2))"): Example("expect(10) > 2\n expect(10) > 2"), ] ) } @@ -94,7 +94,7 @@ private extension NimbleOperatorRule { let elements = ExprListSyntax([ expectation.baseExpr.with(\.trailingTrivia, .space), operatorExpr.with(\.trailingTrivia, .space), - expectedValueExpr.with(\.trailingTrivia, node.trailingTrivia) + expectedValueExpr.with(\.trailingTrivia, node.trailingTrivia), ].map(ExprSyntax.init)) return super.visit(SequenceExprSyntax(elements: elements)) } @@ -111,7 +111,7 @@ private extension NimbleOperatorRule { "beLessThanOrEqualTo": (to: "<=", toNot: nil, .withArguments), "beTrue": (to: "==", toNot: "!=", .nullary(analogueValue: BooleanLiteralExprSyntax(booleanLiteral: true))), "beFalse": (to: "==", toNot: "!=", .nullary(analogueValue: BooleanLiteralExprSyntax(booleanLiteral: false))), - "beNil": (to: "==", toNot: "!=", .nullary(analogueValue: NilLiteralExprSyntax(nilKeyword: .keyword(.nil)))) + "beNil": (to: "==", toNot: "!=", .nullary(analogueValue: NilLiteralExprSyntax(nilKeyword: .keyword(.nil)))), ] static func predicateDescription(for node: FunctionCallExprSyntax) -> PredicateDescription? { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoExtensionAccessModifierRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoExtensionAccessModifierRule.swift index 94234273c0..e6a8ae4680 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoExtensionAccessModifierRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoExtensionAccessModifierRule.swift @@ -11,14 +11,14 @@ struct NoExtensionAccessModifierRule: OptInRule { kind: .idiomatic, nonTriggeringExamples: [ Example("extension String {}"), - Example("\n\n extension String {}") + Example("\n\n extension String {}"), ], triggeringExamples: [ Example("↓private extension String {}"), Example("↓public \n extension String {}"), Example("↓open extension String {}"), Example("↓internal extension String {}"), - Example("↓fileprivate extension String {}") + Example("↓fileprivate extension String {}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoFallthroughOnlyRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoFallthroughOnlyRuleExamples.swift index ccb04a8ede..81b1b0637e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoFallthroughOnlyRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoFallthroughOnlyRuleExamples.swift @@ -78,7 +78,7 @@ internal struct NoFallthroughOnlyRuleExamples { @unknown default: print("it's not a") } - """) + """), ] static let triggeringExamples = [ @@ -154,6 +154,6 @@ internal struct NoFallthroughOnlyRuleExamples { case "abc": let two = 2 } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift index 9b0b45ac03..0c4a79e2af 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift @@ -12,13 +12,13 @@ struct NoGroupingExtensionRule: OptInRule { nonTriggeringExamples: [ Example("protocol Food {}\nextension Food {}"), Example("class Apples {}\nextension Oranges {}"), - Example("class Box {}\nextension Box where T: Vegetable {}") + Example("class Box {}\nextension Box where T: Vegetable {}"), ], triggeringExamples: [ Example("enum Fruit {}\n↓extension Fruit {}"), Example("↓extension Tea: Error {}\nstruct Tea {}"), Example("class Ham { class Spam {}}\n↓extension Ham.Spam {}"), - Example("extension External { struct Gotcha {}}\n↓extension External.Gotcha {}") + Example("extension External { struct Gotcha {}}\n↓extension External.Gotcha {}"), ] ) @@ -55,7 +55,7 @@ private extension NoGroupingExtensionRule { FunctionDeclSyntax.self, VariableDeclSyntax.self, InitializerDeclSyntax.self, - SubscriptDeclSyntax.self + SubscriptDeclSyntax.self, ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift index 8756548670..3af3d6e77a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift @@ -80,7 +80,7 @@ struct NoMagicNumbersRule: OptInRule { Example("let range = 12..."), Example("let (lowerBound, upperBound) = (400, 599)"), Example("let a = (5, 10)"), - Example("let notFound = (statusCode: 404, description: \"Not Found\", isError: true)") + Example("let notFound = (statusCode: 404, description: \"Not Found\", isError: true)"), ], triggeringExamples: [ Example("foo(↓321)"), @@ -106,7 +106,7 @@ struct NoMagicNumbersRule: OptInRule { } """), Example("let imageHeight = (width - ↓24)"), - Example("return (↓5, ↓10, ↓15)") + Example("return (↓5, ↓10, ↓15)"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift index 3986128c6b..04e03df62f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift @@ -17,7 +17,7 @@ struct ObjectLiteralRule: OptInRule { Example("let color = UIColor(red: value, green: value, blue: value, alpha: 1)"), Example("let image = NSImage(named: aVariable)"), Example("let image = NSImage(named: \"interpolated \\(variable)\")"), - Example("let color = NSColor(red: value, green: value, blue: value, alpha: 1)") + Example("let color = NSColor(red: value, green: value, blue: value, alpha: 1)"), ], triggeringExamples: ["", ".init"].flatMap { (method: String) -> [Example] in ["UI", "NS"].flatMap { (prefix: String) -> [Example] in @@ -26,7 +26,7 @@ struct ObjectLiteralRule: OptInRule { Example("let color = ↓\(prefix)Color\(method)(red: 0.3, green: 0.3, blue: 0.3, alpha: 1)"), // swiftlint:disable:next line_length Example("let color = ↓\(prefix)Color\(method)(red: 100 / 255.0, green: 50 / 255.0, blue: 0, alpha: 1)"), - Example("let color = ↓\(prefix)Color\(method)(white: 0.5, alpha: 1)") + Example("let color = ↓\(prefix)Color\(method)(white: 0.5, alpha: 1)"), ] } } @@ -75,7 +75,7 @@ private extension ObjectLiteralRule { return names.flatMap { name in [ name, - name + ".init" + name + ".init", ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift index 82b918e008..3e691d20c1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift @@ -21,7 +21,7 @@ struct OneDelarationPerFileRule: OptInRule { struct S { struct N {} } - """) + """), ], triggeringExamples: [ Example(""" @@ -35,7 +35,7 @@ struct OneDelarationPerFileRule: OptInRule { Example(""" struct Foo {} ↓struct Bar {} - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PatternMatchingKeywordsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PatternMatchingKeywordsRule.swift index fe11d6f614..3bf67d9400 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PatternMatchingKeywordsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PatternMatchingKeywordsRule.swift @@ -21,7 +21,7 @@ struct PatternMatchingKeywordsRule: OptInRule { Example("case var (x, y)"), Example("case .foo(var x)"), Example("case var .foo(x, y)"), - Example("case (y, let x, z)") + Example("case (y, let x, z)"), ].map(wrapInSwitch), triggeringExamples: [ Example("case (↓let x, ↓let y)"), @@ -34,7 +34,7 @@ struct PatternMatchingKeywordsRule: OptInRule { Example("case (.yamlParsing(↓let x), .yamlParsing(↓let y))"), Example("case (↓var x, ↓var y)"), Example("case .foo(↓var x, ↓var y)"), - Example("case (.yamlParsing(↓var x), .yamlParsing(↓var y))") + Example("case (.yamlParsing(↓var x), .yamlParsing(↓var y))"), ].map(wrapInSwitch) ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferNimbleRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferNimbleRule.swift index 9b2993c352..18d9d28952 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferNimbleRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferNimbleRule.swift @@ -11,7 +11,7 @@ struct PreferNimbleRule: OptInRule { kind: .idiomatic, nonTriggeringExamples: [ Example("expect(foo) == 1"), - Example("expect(foo).to(equal(1))") + Example("expect(foo).to(equal(1))"), ], triggeringExamples: [ Example("↓XCTAssertTrue(foo)"), @@ -19,7 +19,7 @@ struct PreferNimbleRule: OptInRule { Example("↓XCTAssertNotEqual(foo, 2)"), Example("↓XCTAssertNil(foo)"), Example("↓XCTAssert(foo)"), - Example("↓XCTAssertGreaterThan(foo, 10)") + Example("↓XCTAssertGreaterThan(foo, 10)"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift index cc8061f73a..3658911bd1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift @@ -14,7 +14,7 @@ struct PreferZeroOverExplicitInitRule: OptInRule { Example("CGPoint(x: 0, y: -1)"), Example("CGSize(width: 2, height: 4)"), Example("CGVector(dx: -5, dy: 0)"), - Example("UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 1)") + Example("UIEdgeInsets(top: 0, left: 1, bottom: 0, right: 1)"), ], triggeringExamples: [ Example("↓CGPoint(x: 0, y: 0)"), @@ -23,7 +23,7 @@ struct PreferZeroOverExplicitInitRule: OptInRule { Example("↓CGRect(x: 0, y: 0, width: 0, height: 0)"), Example("↓CGSize(width: 0, height: 0)"), Example("↓CGVector(dx: 0, dy: 0)"), - Example("↓UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)") + Example("↓UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)"), ], corrections: [ Example("↓CGPoint(x: 0, y: 0)"): Example("CGPoint.zero"), @@ -31,7 +31,7 @@ struct PreferZeroOverExplicitInitRule: OptInRule { Example("↓CGRect(x: 0, y: 0, width: 0, height: 0)"): Example("CGRect.zero"), Example("↓CGSize(width: 0, height: 0.000)"): Example("CGSize.zero"), Example("↓CGVector(dx: 0, dy: 0)"): Example("CGVector.zero"), - Example("↓UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)"): Example("UIEdgeInsets.zero") + Example("↓UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)"): Example("UIEdgeInsets.zero"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift index b317c6bcfc..14d2187300 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift @@ -41,7 +41,7 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule { fileprivate struct Inner {} } } - """) + """), ], triggeringExamples: [ Example("↓fileprivate enum MyEnum {}"), @@ -54,7 +54,7 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule { ↓fileprivate actor MyActor { fileprivate let myInt = 4 } - """) + """), ], corrections: [ Example("↓fileprivate enum MyEnum {}"): @@ -64,7 +64,7 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule { Example("↓fileprivate class MyClass { fileprivate(set) var myInt = 4 }"): Example("private class MyClass { fileprivate(set) var myInt = 4 }"), Example("↓fileprivate actor MyActor { fileprivate(set) var myInt = 4 }"): - Example("private actor MyActor { fileprivate(set) var myInt = 4 }") + Example("private actor MyActor { fileprivate(set) var myInt = 4 }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantNilCoalescingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantNilCoalescingRule.swift index 0aa0e0ae6f..093556e41d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantNilCoalescingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantNilCoalescingRule.swift @@ -18,7 +18,7 @@ struct RedundantNilCoalescingRule: OptInRule { ], corrections: [ Example("var myVar: Int? = nil; let foo = myVar ↓?? nil"): - Example("var myVar: Int? = nil; let foo = myVar") + Example("var myVar: Int? = nil; let foo = myVar"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantObjcAttributeRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantObjcAttributeRuleExamples.swift index 08ef48ede0..1b82b89f99 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantObjcAttributeRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantObjcAttributeRuleExamples.swift @@ -129,7 +129,7 @@ struct RedundantObjcAttributeRuleExamples { case bar } } - """) + """), ] static let triggeringExamples = [ @@ -195,7 +195,7 @@ struct RedundantObjcAttributeRuleExamples { return 0 } } - """) + """), ] static let corrections = [ @@ -335,6 +335,6 @@ struct RedundantObjcAttributeRuleExamples { return 0 } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift index 6bd29aa345..a936b35c53 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift @@ -43,7 +43,7 @@ struct RedundantOptionalInitializationRule: Rule { func funcName() { let myVar: String? = nil } - """) + """), ], triggeringExamples: triggeringExamples, corrections: corrections @@ -63,7 +63,7 @@ struct RedundantOptionalInitializationRule: Rule { func funcName() { var myVar: String?↓ = nil } - """) + """), ] private static let corrections: [Example: Example] = [ @@ -102,7 +102,7 @@ struct RedundantOptionalInitializationRule: Rule { func foo() { var myVar: String?, b: Int } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantSetAccessControlRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantSetAccessControlRule.swift index c2b4dce9f7..c7af821b59 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantSetAccessControlRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantSetAccessControlRule.swift @@ -29,7 +29,7 @@ struct RedundantSetAccessControlRule: Rule { extension Color { public internal(set) static var someColor = Color.anotherColor } - """) + """), ], triggeringExamples: [ Example("↓private(set) private var foo: Int"), @@ -55,7 +55,7 @@ struct RedundantSetAccessControlRule: Rule { fileprivate class A { ↓fileprivate(set) var value: Int } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantStringEnumValueRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantStringEnumValueRule.swift index a20647b78e..e39ffed5a9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantStringEnumValueRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantStringEnumValueRule.swift @@ -38,7 +38,7 @@ struct RedundantStringEnumValueRule: Rule { enum Numbers: String { case one, two } - """) + """), ], triggeringExamples: [ Example(""" @@ -56,7 +56,7 @@ struct RedundantStringEnumValueRule: Rule { enum Numbers: String { case one, two = ↓"two" } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index 5be4a8b2dd..f13e745de4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -56,7 +56,7 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { Example("var bol: Bool = true"), Example("var dbl: Double = 0.0"), Example("var int: Int = 0"), - Example("var str: String = \"str\"") + Example("var str: String = \"str\""), ], triggeringExamples: [ Example("var url↓:URL=URL()"), @@ -109,7 +109,7 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { Example("var bol↓: Bool = true", configuration: ["consider_default_literal_types_redundant": true]), Example("var dbl↓: Double = 0.0", configuration: ["consider_default_literal_types_redundant": true]), Example("var int↓: Int = 0", configuration: ["consider_default_literal_types_redundant": true]), - Example("var str↓: String = \"str\"", configuration: ["consider_default_literal_types_redundant": true]) + Example("var str↓: String = \"str\"", configuration: ["consider_default_literal_types_redundant": true]), ], corrections: [ Example("var url↓: URL = URL()"): Example("var url = URL()"), @@ -174,7 +174,7 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { Example("var int: Int = 0", configuration: ["consider_default_literal_types_redundant": true]): Example("var int = 0"), Example("var str: String = \"str\"", configuration: ["consider_default_literal_types_redundant": true]): - Example("var str = \"str\"") + Example("var str = \"str\""), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantVoidReturnRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantVoidReturnRule.swift index 369a7459fa..432dc89f0d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantVoidReturnRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantVoidReturnRule.swift @@ -32,7 +32,7 @@ struct RedundantVoidReturnRule: Rule { doSomething { arg -> Void in print(arg) } - """, configuration: ["include_closures": false]) + """, configuration: ["include_closures": false]), ], triggeringExamples: [ Example("func foo()↓ -> Void {}"), @@ -57,7 +57,7 @@ struct RedundantVoidReturnRule: Rule { doSomething { arg↓ -> Void in print(arg) } - """) + """), ], corrections: [ Example("func foo()↓ -> Void {}"): Example("func foo() {}"), @@ -65,7 +65,7 @@ struct RedundantVoidReturnRule: Rule { Example("func foo()↓ -> () {}"): Example("func foo() {}"), Example("protocol Foo {\n func foo()↓ -> ()\n}"): Example("protocol Foo {\n func foo()\n}"), Example("protocol Foo {\n #if true\n func foo()↓ -> Void\n #endif\n}"): - Example("protocol Foo {\n #if true\n func foo()\n #endif\n}") + Example("protocol Foo {\n #if true\n func foo()\n #endif\n}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift index 58ea304639..7b033ecb4d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRule.swift @@ -44,7 +44,7 @@ private extension ReturnValueFromVoidFunctionRule { \.leadingTrivia, .newline + (returnStmt.leadingTrivia.indentation(isOnNewline: false) ?? [])) .with(\.trailingTrivia, returnStmt.trailingTrivia) - ))) + ))), ] return super.visit(CodeBlockItemListSyntax(newStmtList)) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift index bcbbbcf4df..5dd45d712f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ReturnValueFromVoidFunctionRuleExamples.swift @@ -146,7 +146,7 @@ internal struct ReturnValueFromVoidFunctionRuleExamples { } } } - """#, excludeFromDocumentation: true) + """#, excludeFromDocumentation: true), ] static let triggeringExamples = [ @@ -289,7 +289,7 @@ internal struct ReturnValueFromVoidFunctionRuleExamples { } ↓return foo() } - """) + """), ] static let corrections = [ @@ -320,6 +320,6 @@ internal struct ReturnValueFromVoidFunctionRuleExamples { return } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift index 220d73be0a..5daf74cbba 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift @@ -24,7 +24,7 @@ struct ShorthandOptionalBindingRule: OptInRule { if let i, var i = a, j > 0 {} - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -48,7 +48,7 @@ struct ShorthandOptionalBindingRule: OptInRule { """), Example(""" while ↓var i = i { i = nil } - """) + """), ], corrections: [ Example(""" @@ -75,7 +75,7 @@ struct ShorthandOptionalBindingRule: OptInRule { while j > 0, ↓var i = i { i = nil } """): Example(""" while j > 0, var i { i = nil } - """) + """), ], deprecatedAliases: ["if_let_shadowing"] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOperatorRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOperatorRule.swift index 910189b6c2..419085b2b8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOperatorRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOperatorRule.swift @@ -43,7 +43,7 @@ struct StaticOperatorRule: OptInRule { } } } - """) + """), ], triggeringExamples: [ Example(""" @@ -73,7 +73,7 @@ struct StaticOperatorRule: OptInRule { return false } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift index 558e01676c..c054fc1c66 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift @@ -43,7 +43,7 @@ struct StaticOverFinalClassRule: Rule { class func f() {} } } - """) + """), ], triggeringExamples: [ Example(""" @@ -72,7 +72,7 @@ struct StaticOverFinalClassRule: Rule { ↓class func f() {} } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift index ca57cd6822..918999604b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StrictFilePrivateRule.swift @@ -55,7 +55,7 @@ struct StrictFilePrivateRule: OptInRule { protocol P { func f() } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] + ["actor", "class", "enum", "extension", "struct"].map { type in Example(""" \(type) T: P { @@ -100,7 +100,7 @@ struct StrictFilePrivateRule: OptInRule { """), Example(""" ↓fileprivate func f() {} - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] + ["actor", "class", "enum", "extension", "struct"].map { type in Example(""" \(type) T: P { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift index 2da01b60ca..6b1a57c35a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift @@ -28,7 +28,7 @@ internal enum SyntacticSugarRuleExamples { Example("let x = case Optional.none = obj"), Example("let a = Swift.Optional.none"), - Example("func f() -> [Array.Index] { [Array.Index]() }", excludeFromDocumentation: true) + Example("func f() -> [Array.Index] { [Array.Index]() }", excludeFromDocumentation: true), ] static let triggering = [ @@ -62,7 +62,7 @@ internal enum SyntacticSugarRuleExamples { Example(""" let dict: [String: Any] = [:] _ = dict["key"] as? ↓Optional ?? Optional.none - """) + """), ] static let corrections = [ @@ -81,6 +81,6 @@ internal enum SyntacticSugarRuleExamples { Example("let x:↓Dictionary<↓Dictionary<↓Dictionary, Int>, String>"): Example("let x:[[[Int: Int]: Int]: String]"), Example("let x:↓Array<↓Dictionary>"): Example("let x:[[Int: Int]]"), - Example("let x:↓Optional<↓Dictionary>"): Example("let x:[Int: Int]?") + Example("let x:↓Optional<↓Dictionary>"): Example("let x:[Int: Int]?"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift index 12b9fe4945..91816cb712 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift @@ -16,17 +16,17 @@ struct ToggleBoolRule: OptInRule { Example("func foo() { abc.toggle() }"), Example("view.clipsToBounds = !clipsToBounds"), Example("disconnected = !connected"), - Example("result = !result.toggle()") + Example("result = !result.toggle()"), ], triggeringExamples: [ Example("↓isHidden = !isHidden"), Example("↓view.clipsToBounds = !view.clipsToBounds"), - Example("func foo() { ↓abc = !abc }") + Example("func foo() { ↓abc = !abc }"), ], corrections: [ Example("↓isHidden = !isHidden"): Example("isHidden.toggle()"), Example("↓view.clipsToBounds = !view.clipsToBounds"): Example("view.clipsToBounds.toggle()"), - Example("func foo() { ↓abc = !abc }"): Example("func foo() { abc.toggle() }") + Example("func foo() { ↓abc = !abc }"): Example("func foo() { abc.toggle() }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TrailingSemicolonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TrailingSemicolonRule.swift index 6e6b397ca6..72a50c3cef 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TrailingSemicolonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TrailingSemicolonRule.swift @@ -11,17 +11,17 @@ struct TrailingSemicolonRule: Rule { kind: .idiomatic, nonTriggeringExamples: [ Example("let a = 0"), - Example("let a = 0; let b = 0") + Example("let a = 0; let b = 0"), ], triggeringExamples: [ Example("let a = 0↓;\n"), Example("let a = 0↓;\nlet b = 1"), - Example("let a = 0↓; // a comment\n") + Example("let a = 0↓; // a comment\n"), ], corrections: [ Example("let a = 0↓;\n"): Example("let a = 0\n"), Example("let a = 0↓;\nlet b = 1"): Example("let a = 0\nlet b = 1"), - Example("let foo = 12↓; // comment\n"): Example("let foo = 12 // comment\n") + Example("let foo = 12↓; // comment\n"): Example("let foo = 12 // comment\n"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TypeNameRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TypeNameRuleExamples.swift index 6a8b9a25a1..fcd8ae214f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TypeNameRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/TypeNameRuleExamples.swift @@ -25,7 +25,7 @@ internal struct TypeNameRuleExamples { case x, y, z } } - """) + """), ] static let triggeringExamples: [Example] = [ @@ -57,6 +57,6 @@ internal struct TypeNameRuleExamples { associatedtype ↓\(repeatElement("A", count: 41).joined()) } """), - Example("protocol ↓X {}") + Example("protocol ↓X {}"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableConditionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableConditionRule.swift index 694924d14c..2a6c8954b7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableConditionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableConditionRule.swift @@ -38,7 +38,7 @@ struct UnavailableConditionRule: Rule { } else if i < 2, #available(macOS 11.0, *) { print("something else") } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -66,7 +66,7 @@ struct UnavailableConditionRule: Rule { } else if i < 2 { loadMainWindow() } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift index ae81a1a4f5..2e41d94d3c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift @@ -36,7 +36,7 @@ struct UnavailableFunctionRule: OptInRule { // Crash the app to re-start the onboarding flow. fatalError("Onboarding re-start crash.") } - """) + """), ], triggeringExamples: [ Example(""" @@ -67,7 +67,7 @@ struct UnavailableFunctionRule: OptInRule { // Crash the app to re-start the onboarding flow. fatalError("Onboarding re-start crash.") } - """) + """), ] ) } @@ -131,7 +131,7 @@ private extension CodeBlockSyntax? { let terminatingFunctions: Set = [ "abort", "fatalError", - "preconditionFailure" + "preconditionFailure", ] return statements.contains { item in diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift index 1c9bb4a657..657d07d54b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift @@ -39,13 +39,13 @@ struct UnneededBreakInSwitchRule: Rule { } } } - """) + """), ], triggeringExamples: [ embedInSwitch("something()\n ↓break"), embedInSwitch("something()\n ↓break // comment"), embedInSwitch("something()\n ↓break", case: "default"), - embedInSwitch("something()\n ↓break", case: "case .foo, .foo2 where condition") + embedInSwitch("something()\n ↓break", case: "case .foo, .foo2 where condition"), ], corrections: [ embedInSwitch("something()\n ↓break") @@ -83,7 +83,7 @@ struct UnneededBreakInSwitchRule: Rule { embedInSwitch("something()\n ↓break", case: "default") : embedInSwitch("something()", case: "default"), embedInSwitch("something()\n ↓break", case: "case .foo, .foo2 where condition") - : embedInSwitch("something()", case: "case .foo, .foo2 where condition") + : embedInSwitch("something()", case: "case .foo, .foo2 where condition"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift index 507ade2774..66c19ebee9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift @@ -243,7 +243,7 @@ enum UnneededSynthesizedInitializerRuleExamples { init() {} } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] static let triggering = [ @@ -388,7 +388,7 @@ enum UnneededSynthesizedInitializerRuleExamples { self.i = i } } - """) + """), ] static let corrections = [ @@ -539,6 +539,6 @@ enum UnneededSynthesizedInitializerRuleExamples { let prop: Int } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UntypedErrorInCatchRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UntypedErrorInCatchRule.swift index 386366dc3e..fb793a1406 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UntypedErrorInCatchRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UntypedErrorInCatchRule.swift @@ -41,7 +41,7 @@ struct UntypedErrorInCatchRule: OptInRule { } catch { print(error) } - """) + """), ], triggeringExamples: [ Example(""" @@ -78,12 +78,12 @@ struct UntypedErrorInCatchRule: OptInRule { do { try foo() } ↓catch (let error) {} - """) + """), ], corrections: [ Example("do {\n try foo() \n} ↓catch let error {}"): Example("do {\n try foo() \n} catch {}"), Example("do {\n try foo() \n} ↓catch(let error) {}"): Example("do {\n try foo() \n} catch {}"), - Example("do {\n try foo() \n} ↓catch (let error) {}"): Example("do {\n try foo() \n} catch {}") + Example("do {\n try foo() \n} ↓catch (let error) {}"): Example("do {\n try foo() \n} catch {}"), ]) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift index 8e8c614296..f125473ce4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift @@ -36,7 +36,7 @@ struct UnusedEnumeratedRule: Rule { let (i, e) = $0 print(i) } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example("for (↓_, foo) in bar.enumerated() { }"), @@ -84,7 +84,7 @@ struct UnusedEnumeratedRule: Rule { list.↓enumerated().forEach { let (i, _) = $0 } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift index b569de22c7..51b7e2890c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift @@ -59,7 +59,7 @@ struct VoidFunctionInTernaryConditionRule: Rule { Example(""" subscript(index: Int) -> Int { index == 0 ? defaultValue() : compute(index) - """) + """), ], triggeringExamples: [ Example("success ↓? askQuestion() : exit()"), @@ -103,7 +103,7 @@ struct VoidFunctionInTernaryConditionRule: Rule { index == 0 ↓? something() : somethingElse(index) return index } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTFailMessageRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTFailMessageRule.swift index 1c3c2fd866..13309b5b44 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTFailMessageRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTFailMessageRule.swift @@ -19,7 +19,7 @@ struct XCTFailMessageRule: Rule { func testFoo() { XCTFail(bar) } - """) + """), ], triggeringExamples: [ Example(""" @@ -31,7 +31,7 @@ struct XCTFailMessageRule: Rule { func testFoo() { ↓XCTFail("") } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRuleExamples.swift index accabe8f77..cade2be89b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRuleExamples.swift @@ -63,7 +63,7 @@ internal struct XCTSpecificMatcherRuleExamples { // Skip if one operand might be a type or a tuple Example("XCTAssert(foo.self == bar)"), Example("XCTAssertTrue(type(of: foo) != Int.self)"), - Example("XCTAssertTrue(a == (1, 3, 5)") + Example("XCTAssertTrue(a == (1, 3, 5)"), ] static let triggeringExamples = [ @@ -136,6 +136,6 @@ internal struct XCTSpecificMatcherRuleExamples { Example("↓XCTAssert(nil == foo"), Example("↓XCTAssertTrue( foo != nil)"), Example("↓XCTAssertFalse(nil != foo"), - Example("↓XCTAssert(foo == nil, \"toto\")") + Example("↓XCTAssert(foo == nil, \"toto\")"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift index 18dfda9d8e..a5432e5b80 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift @@ -133,7 +133,7 @@ private extension SourceKittenDictionary { SwiftUIModifier( name: "accessibility", arguments: [.init(name: "label", values: [])] - ) + ), ], in: file ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRuleExamples.swift index 8ba3214e16..ede1e90e84 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRuleExamples.swift @@ -148,7 +148,7 @@ internal struct AccessibilityLabelForImageRuleExamples { .accessibilityLabel(Text("Label for my image")) } } - """) + """), ] static let triggeringExamples = [ @@ -264,6 +264,6 @@ internal struct AccessibilityLabelForImageRuleExamples { ↓Image(systemName: "circle.plus") } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift index 62ab87460f..7fa33b38df 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift @@ -111,7 +111,7 @@ private extension SourceKittenDictionary { arguments: [ .init(name: "", values: ["TapGesture()", "TapGesture(count: 1)"], matchType: .prefix) ] - ) + ), ], in: file ) @@ -129,7 +129,7 @@ private extension SourceKittenDictionary { SwiftUIModifier( name: "accessibility", arguments: [.init(name: "addTraits", values: [trait], matchType: .substring)] - ) + ), ], in: file ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRuleExamples.swift index ea987cf1ed..570411695d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRuleExamples.swift @@ -168,7 +168,7 @@ internal struct AccessibilityTraitForButtonRuleExamples { }) } } - """) + """), ] static let triggeringExamples = [ @@ -265,6 +265,6 @@ internal struct AccessibilityTraitForButtonRuleExamples { }) } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift index 325f68b121..3d8ded4ae5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift @@ -21,12 +21,12 @@ struct AnyObjectProtocolRule: SwiftSyntaxCorrectableRule, OptInRule { Example("protocol SomeProtocol {}"), Example("protocol SomeClassOnlyProtocol: AnyObject {}"), Example("protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), - Example("@objc protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}") + Example("@objc protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), ], triggeringExamples: [ Example("protocol SomeClassOnlyProtocol: ↓class {}"), Example("protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"), - Example("@objc protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}") + Example("@objc protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"), ], corrections: [ Example("protocol SomeClassOnlyProtocol: ↓class {}"): @@ -34,7 +34,7 @@ struct AnyObjectProtocolRule: SwiftSyntaxCorrectableRule, OptInRule { Example("protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"): Example("protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), Example("@objc protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"): - Example("@objc protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}") + Example("@objc protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift index fc8bf2def1..2b0e0ef2d3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift @@ -19,7 +19,7 @@ struct ArrayInitRule: OptInRule { Example("foo.map { $0! /* force unwrap */ }"), Example("foo.something { RouteMapper.map($0) }"), Example("foo.map { !$0 }"), - Example("foo.map { /* a comment */ !$0 }") + Example("foo.map { /* a comment */ !$0 }"), ], triggeringExamples: [ Example("foo.↓map({ $0 })"), @@ -46,7 +46,7 @@ struct ArrayInitRule: OptInRule { } """), Example("foo.↓map { $0 /* a comment */ }"), - Example("foo.↓map { /* a comment */ $0 }") + Example("foo.↓map { /* a comment */ $0 }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/BalancedXCTestLifecycleRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/BalancedXCTestLifecycleRule.swift index e1dbbebd0a..9c29b21dd0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/BalancedXCTestLifecycleRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/BalancedXCTestLifecycleRule.swift @@ -56,7 +56,7 @@ struct BalancedXCTestLifecycleRule: OptInRule { class func setUp() {} class func tearDown() {} } - """#) + """#), ], triggeringExamples: [ Example(#""" @@ -101,7 +101,7 @@ struct BalancedXCTestLifecycleRule: OptInRule { final class ↓BarTests: XCTestCase { override func tearDownWithError() throws {} } - """#) + """#), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift index b0508d2049..87d37e5d65 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift @@ -22,7 +22,7 @@ struct BlanketDisableCommandRule: Rule, SourceKitFreeRule { """), Example("// swiftlint:disable:this unused_import"), Example("// swiftlint:disable:next unused_import"), - Example("// swiftlint:disable:previous unused_import") + Example("// swiftlint:disable:previous unused_import"), ], triggeringExamples: [ Example("// swiftlint:disable ↓unused_import"), @@ -37,7 +37,7 @@ struct BlanketDisableCommandRule: Rule, SourceKitFreeRule { """), Example(""" // swiftlint:enable ↓unused_import - """) + """), ].skipWrappingInCommentTests().skipDisableCommandTests() ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift index f86ad77a04..2ae3409899 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift @@ -72,7 +72,7 @@ struct CaptureVariableRule: AnalyzerRule, CollectingRule { closure() j = 1 closure() - """) + """), ], triggeringExamples: [ Example(""" @@ -147,7 +147,7 @@ struct CaptureVariableRule: AnalyzerRule, CollectingRule { func test(_ completionHandler: @escaping (Int) -> Void) { } } - """) + """), ], requiresFileOnDisk: true ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ClassDelegateProtocolRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ClassDelegateProtocolRule.swift index 07fde3470a..ce556449b9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ClassDelegateProtocolRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ClassDelegateProtocolRule.swift @@ -21,12 +21,12 @@ struct ClassDelegateProtocolRule: Rule { Example("protocol FooDelegate: NSObjectProtocol {}"), Example("protocol FooDelegate where Self: BarDelegate {}"), Example("protocol FooDelegate where Self: AnyObject {}"), - Example("protocol FooDelegate where Self: NSObjectProtocol {}") + Example("protocol FooDelegate where Self: NSObjectProtocol {}"), ], triggeringExamples: [ Example("↓protocol FooDelegate {}"), Example("↓protocol FooDelegate: Bar {}"), - Example("↓protocol FooDelegate where Self: StringProtocol {}") + Example("↓protocol FooDelegate where Self: StringProtocol {}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift index 464f15f134..0acdce2a9b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift @@ -58,7 +58,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { """), Example(""" /*#-editable-code Swift Platground editable area*/default/*#-end-editable-code*/ - """) + """), ], triggeringExamples: [ Example(""" @@ -89,7 +89,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { """), Example(""" //:↓Swift Playground prose section - """) + """), ], corrections: [ Example("//↓Something"): Example("// Something"), @@ -113,7 +113,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { print("Something") } // We should improve above function - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift index e3a41a0b4c..d97ceaf1e5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift @@ -12,13 +12,13 @@ struct CompilerProtocolInitRule: Rule { kind: .lint, nonTriggeringExamples: [ Example("let set: Set = [1, 2]"), - Example("let set = Set(array)") + Example("let set = Set(array)"), ], triggeringExamples: [ Example("let set = ↓Set(arrayLiteral: 1, 2)"), Example("let set = ↓Set (arrayLiteral: 1, 2)"), Example("let set = ↓Set.init(arrayLiteral: 1, 2)"), - Example("let set = ↓Set.init(arrayLiteral : 1, 2)") + Example("let set = ↓Set.init(arrayLiteral : 1, 2)"), ] ) } @@ -85,10 +85,12 @@ private struct ExpressibleByCompiler { initCallNames = Set(types.flatMap { [$0, "\($0).init"] }) } - static let allProtocols = [byArrayLiteral, byNilLiteral, byBooleanLiteral, - byFloatLiteral, byIntegerLiteral, byUnicodeScalarLiteral, - byExtendedGraphemeClusterLiteral, byStringLiteral, - byStringInterpolation, byDictionaryLiteral] + static let allProtocols = [ + byArrayLiteral, byNilLiteral, byBooleanLiteral, + byFloatLiteral, byIntegerLiteral, byUnicodeScalarLiteral, + byExtendedGraphemeClusterLiteral, byStringLiteral, + byStringInterpolation, byDictionaryLiteral, + ] static let possibleNumberOfArguments: Set = { allProtocols.reduce(into: Set()) { partialResult, entry in @@ -121,7 +123,7 @@ private struct ExpressibleByCompiler { "NSSet", "SBElementArray", "Set", - "IndexSet" + "IndexSet", ] return Self(protocolName: "ExpressibleByArrayLiteral", types: types, arguments: [["arrayLiteral"]]) }() diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift index 33be403ff1..e31ad3ed9c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift @@ -46,7 +46,7 @@ private extension DeploymentTargetRule { "tvOS": configuration.tvOSDeploymentTarget, "tvOSApplicationExtension": configuration.tvOSAppExtensionDeploymentTarget, "watchOS": configuration.watchOSDeploymentTarget, - "watchOSApplicationExtension": configuration.watchOSAppExtensionDeploymentTarget + "watchOSApplicationExtension": configuration.watchOSAppExtensionDeploymentTarget, ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRuleExamples.swift index a22c0c8c3d..3d85368f6f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRuleExamples.swift @@ -10,7 +10,7 @@ internal enum DeploymentTargetRuleExamples { Example("if #available(iOS 10, *) {}"), Example("guard #available(iOS 12.0, *) else { return }"), Example("#if #unavailable(iOS 15.0) {}"), - Example("#guard #unavailable(iOS 15.0) {} else { return }") + Example("#guard #unavailable(iOS 15.0) {} else { return }"), ] static let triggeringExamples: [Example] = [ @@ -32,6 +32,6 @@ internal enum DeploymentTargetRuleExamples { Example("guard ↓#available(iOS 6.0, *) else { return }"), Example("if ↓#unavailable(iOS 7.0) {}"), Example("if ↓#unavailable(iOS 6.9) {}"), - Example("guard ↓#unavailable(iOS 7.0) {} else { return }") + Example("guard ↓#unavailable(iOS 7.0) {} else { return }"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift index 3e3cd6dcf4..2b7d0a6d82 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift @@ -54,7 +54,7 @@ struct DiscardedNotificationCenterObserverRule: OptInRule { """), Example(""" f { return nc.addObserver(forName: $0, object: object, queue: queue, using: block) } - """) + """), ], triggeringExamples: [ Example("↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil) { }"), @@ -88,7 +88,7 @@ struct DiscardedNotificationCenterObserverRule: OptInRule { ↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { }) } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscouragedDirectInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscouragedDirectInitRule.swift index 2bbe11bc18..4ae0db9ac8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscouragedDirectInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscouragedDirectInitRule.swift @@ -18,7 +18,7 @@ struct DiscouragedDirectInitRule: Rule { Example("let foo = Bundle.init(identifier: \"bar\")"), Example("let foo = NSError(domain: \"bar\", code: 0)"), Example("let foo = NSError.init(domain: \"bar\", code: 0)"), - Example("func testNSError()") + Example("func testNSError()"), ], triggeringExamples: [ Example("↓UIDevice()"), @@ -32,7 +32,7 @@ struct DiscouragedDirectInitRule: Rule { Example("↓NSError.init()"), Example("let foo = ↓UIDevice.init()"), Example("let foo = ↓Bundle.init()"), - Example("let foo = bar(bundle: ↓Bundle.init(), device: ↓UIDevice.init(), error: ↓NSError.init())") + Example("let foo = bar(bundle: ↓Bundle.init(), device: ↓UIDevice.init(), error: ↓NSError.init())"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift index e24e7009a6..8c3f10974a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift @@ -72,7 +72,7 @@ struct DuplicateConditionsRule: Rule { if true { if true { foo() } } - """) + """), ], triggeringExamples: [ Example(""" @@ -152,7 +152,7 @@ struct DuplicateConditionsRule: Rule { if ↓x < 5 {} else if ↓x < 5 {} else if ↓x < 5 {} - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift index 04c942c50f..0e26dec2bc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift @@ -43,7 +43,7 @@ struct DuplicateEnumCasesRule: Rule { case file(URL) #endif } - """) + """), ], triggeringExamples: [ Example(""" @@ -52,7 +52,7 @@ struct DuplicateEnumCasesRule: Rule { case addURL(url: URL) case ↓add(data: Data) } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift index 5c2c1ac2be..3307ac36cf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift @@ -39,7 +39,7 @@ struct DuplicatedKeyInDictionaryLiteralRule: Rule { #line: "1", #line: "2" ] - """) + """), ], triggeringExamples: [ Example(""" @@ -74,7 +74,7 @@ struct DuplicatedKeyInDictionaryLiteralRule: Rule { .four: "4", .five: "5" ] - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DynamicInlineRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DynamicInlineRule.swift index e12f6b5027..232cb208cb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DynamicInlineRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DynamicInlineRule.swift @@ -12,14 +12,14 @@ struct DynamicInlineRule: Rule { nonTriggeringExamples: [ Example("class C {\ndynamic func f() {}}"), Example("class C {\n@inline(__always) func f() {}}"), - Example("class C {\n@inline(never) dynamic func f() {}}") + Example("class C {\n@inline(never) dynamic func f() {}}"), ], triggeringExamples: [ Example("class C {\n@inline(__always) dynamic ↓func f() {}\n}"), Example("class C {\n@inline(__always) public dynamic ↓func f() {}\n}"), Example("class C {\n@inline(__always) dynamic internal ↓func f() {}\n}"), Example("class C {\n@inline(__always)\ndynamic ↓func f() {}\n}"), - Example("class C {\n@inline(__always)\ndynamic\n↓func f() {}\n}") + Example("class C {\n@inline(__always)\ndynamic\n↓func f() {}\n}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/EmptyXCTestMethodRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/EmptyXCTestMethodRuleExamples.swift index beafdfb36c..ee5fcdaaec 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/EmptyXCTestMethodRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/EmptyXCTestMethodRuleExamples.swift @@ -98,7 +98,7 @@ internal struct EmptyXCTestMethodRuleExamples { enum E { override func foo(a: Int) {} } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] static let triggeringExamples = [ @@ -187,6 +187,6 @@ internal struct EmptyXCTestMethodRuleExamples { class BarTests: XCTestCase { ↓func testFoo() {} } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift index 3e395a3bf6..e0f6776343 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift @@ -33,14 +33,14 @@ struct ExpiringTodoRule: OptInRule { Example("/* FIXME: */"), Example("/* TODO: */"), Example("/** FIXME: */"), - Example("/** TODO: */") + Example("/** TODO: */"), ], triggeringExamples: [ Example("// TODO: [↓10/14/2019]"), Example("// FIXME: [↓10/14/2019]"), Example("// FIXME: [↓1/14/2019]"), Example("// FIXME: [↓10/14/2019]"), - Example("// TODO: [↓9999/14/10]") + Example("// TODO: [↓9999/14/10]"), ].skipWrappingInCommentTests() ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/IBInspectableInExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/IBInspectableInExtensionRule.swift index 46a1d85db9..686edfdf07 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/IBInspectableInExtensionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/IBInspectableInExtensionRule.swift @@ -14,14 +14,14 @@ struct IBInspectableInExtensionRule: OptInRule { class Foo { @IBInspectable private var x: Int } - """) + """), ], triggeringExamples: [ Example(""" extension Foo { ↓@IBInspectable private var x: Int } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/IdenticalOperandsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/IdenticalOperandsRule.swift index dac4e997da..4849b0570c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/IdenticalOperandsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/IdenticalOperandsRule.swift @@ -32,7 +32,7 @@ struct IdenticalOperandsRule: OptInRule { """), Example("num \(operation) num!.byteSwapped"), Example("1 + 1 \(operation) 1 + 2"), - Example("f( i : 2) \(operation) f (i: 3 )") + Example("f( i : 2) \(operation) f (i: 3 )"), ] } + [ Example("func evaluate(_ mode: CommandMode) -> Result>>"), @@ -42,7 +42,7 @@ struct IdenticalOperandsRule: OptInRule { Example("type(of: model).cachePrefix == cachePrefix"), Example("histogram[156].0 == 0x003B8D96 && histogram[156].1 == 1"), Example(#"[Wrapper(type: .three), Wrapper(type: .one)].sorted { "\($0.type)" > "\($1.type)"}"#), - Example(#"array.sorted { "\($0)" < "\($1)" }"#) + Example(#"array.sorted { "\($0)" < "\($1)" }"#), ], triggeringExamples: operators.flatMap { operation in [ @@ -56,7 +56,7 @@ struct IdenticalOperandsRule: OptInRule { Example("XCTAssertTrue(↓s3 \(operation) s3)"), Example("if let tab = tabManager.selectedTab, ↓tab.webView \(operation) tab.webView"), Example("↓1 + 1 \(operation) 1 + 1"), - Example(" ↓f( i : 2) \(operation) f (i: \n 2 )") + Example(" ↓f( i : 2) \(operation) f (i: \n 2 )"), ] } + [ Example(""" @@ -66,7 +66,7 @@ struct IdenticalOperandsRule: OptInRule { Example(""" return lhs.foo == rhs.foo && ↓lhs.bar == lhs.bar - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift index d49b72fd75..abecbf32c6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift @@ -42,7 +42,7 @@ struct InertDeferRule: SwiftSyntaxRule, OptInRule { #endif print(1) } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -79,7 +79,7 @@ struct InertDeferRule: SwiftSyntaxRule, OptInRule { ↓defer { print(5) } #endif } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/InvalidSwiftLintCommandRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/InvalidSwiftLintCommandRule.swift index 71fed8fc04..52d8146bb0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/InvalidSwiftLintCommandRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/InvalidSwiftLintCommandRule.swift @@ -12,7 +12,7 @@ struct InvalidSwiftLintCommandRule: Rule, SourceKitFreeRule { Example("// swiftlint:disable:next unused_import"), Example("// swiftlint:disable:previous unused_import"), Example("// swiftlint:disable:this unused_import"), - Example("//swiftlint:disable:this unused_import") + Example("//swiftlint:disable:this unused_import"), ], triggeringExamples: [ Example("// ↓swiftlint:"), @@ -29,7 +29,7 @@ struct InvalidSwiftLintCommandRule: Rule, SourceKitFreeRule { Example("// ↓swiftlint:enable:"), Example("// ↓swiftlint:enable: "), Example("// ↓swiftlint:disable: unused_import"), - Example("// s↓swiftlint:disable unused_import") + Example("// s↓swiftlint:disable unused_import"), ].skipWrappingInCommentTests() ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift index 927a32c869..dc551ea499 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift @@ -28,7 +28,7 @@ struct LocalDocCommentRule: SwiftSyntaxRule, OptInRule { /// Look here for more info: /// https://github.com. var myGreatProperty: String! - """) + """), ], triggeringExamples: [ Example(""" @@ -36,7 +36,7 @@ struct LocalDocCommentRule: SwiftSyntaxRule, OptInRule { ↓/// Docstring inside a function declaration print("foo") } - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/LowerACLThanParentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/LowerACLThanParentRule.swift index 7e38328ba1..624ebf0369 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/LowerACLThanParentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/LowerACLThanParentRule.swift @@ -25,7 +25,7 @@ struct LowerACLThanParentRule: OptInRule { Example("public extension Foo { struct Bar { public func baz() {} }}"), Example("public extension Foo { struct Bar { internal func baz() {} }}"), Example("internal extension Foo { struct Bar { internal func baz() {} }}"), - Example("extension Foo { struct Bar { internal func baz() {} }}") + Example("extension Foo { struct Bar { internal func baz() {} }}"), ], triggeringExamples: [ Example("struct Foo { ↓public func bar() {} }"), @@ -47,7 +47,7 @@ struct LowerACLThanParentRule: OptInRule { Example("private extension Foo { struct Bar { ↓internal func baz() {} }}"), Example("fileprivate extension Foo { struct Bar { ↓internal func baz() {} }}"), Example("public extension Foo { struct Bar { struct Baz { ↓public func qux() {} }}}"), - Example("final class Foo { ↓public func bar() {} }") + Example("final class Foo { ↓public func bar() {} }"), ], corrections: [ Example("struct Foo { ↓public func bar() {} }"): @@ -77,7 +77,7 @@ struct LowerACLThanParentRule: OptInRule { struct Foo { func bar() {} } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift index 1a5b48e98f..e7b92a8d17 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRule.swift @@ -70,13 +70,13 @@ private extension TokenSyntax { "^// MARK:$", // comment start with `Mark ...` is ignored - "^\(twoOrThreeSlashes) +[Mm]ark[^:]" + "^\(twoOrThreeSlashes) +[Mm]ark[^:]", ].map(nonCapturingGroup).joined(separator: "|") private static let badPattern = capturingGroup([ "MARK[^\\s:]", "[Mm]ark", - "MARK" + "MARK", ].map(basePattern).joined(separator: "|")) + capturingGroup(hyphenOrEmpty) private static let anySpace = " *" diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift index 5ae104dc12..3aa174113e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MarkRuleExamples.swift @@ -28,7 +28,7 @@ internal struct MarkRuleExamples { /// //marketingOptIn struct T {} """, excludeFromDocumentation: true), - issue1749Example + issue1749Example, ] static let triggeringExamples = [ @@ -62,7 +62,7 @@ internal struct MarkRuleExamples { ↓//MARK: bad } """), - issue1029Example + issue1029Example, ] static let corrections = [ @@ -85,7 +85,7 @@ internal struct MarkRuleExamples { Example("↓/// MARK:"): Example("// MARK:"), Example("↓/// MARK comment"): Example("// MARK: comment"), issue1029Example: issue1029Correction, - issue1749Example: issue1749Correction + issue1749Example: issue1749Correction, ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift index 9b388c3b8f..49e36967c4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift @@ -90,7 +90,7 @@ struct MissingDocsRule: OptInRule { public class A { public init() {} } - """, configuration: ["excludes_trivial_init": true]) + """, configuration: ["excludes_trivial_init": true]), ], triggeringExamples: [ // public, undocumented @@ -116,7 +116,7 @@ struct MissingDocsRule: OptInRule { public class A { public init(argument: String) {} } - """, configuration: ["excludes_trivial_init": true]) + """, configuration: ["excludes_trivial_init": true]), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringKeyRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringKeyRule.swift index 0af4f6fb10..77fb9b7ed1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringKeyRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringKeyRule.swift @@ -22,13 +22,13 @@ struct NSLocalizedStringKeyRule: OptInRule { let format = NSLocalizedString("%@, %@.", comment: "Accessibility label for a post in the post list." + " The parameters are the title, and date respectively." + " For example, \"Let it Go, 1 hour ago.\"") - """) + """), ], triggeringExamples: [ Example("NSLocalizedString(↓method(), comment: \"\")"), Example("NSLocalizedString(↓\"key_\\(param)\", comment: \"\")"), Example("NSLocalizedString(\"key\", comment: ↓\"comment with \\(param)\")"), - Example("NSLocalizedString(↓\"key_\\(param)\", comment: ↓method())") + Example("NSLocalizedString(↓\"key_\\(param)\", comment: ↓method())"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringRequireBundleRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringRequireBundleRule.swift index bbb8d0f22a..22a515971a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringRequireBundleRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NSLocalizedStringRequireBundleRule.swift @@ -25,7 +25,7 @@ struct NSLocalizedStringRequireBundleRule: OptInRule { """), Example(""" arbitraryFunctionCall("something") - """) + """), ], triggeringExamples: [ Example(""" @@ -37,7 +37,7 @@ struct NSLocalizedStringRequireBundleRule: OptInRule { Example(""" ↓NSLocalizedString("someKey", tableName: "xyz", value: "test", comment: "test") - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NSNumberInitAsFunctionReferenceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NSNumberInitAsFunctionReferenceRule.swift index 780c311350..bc600d0601 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NSNumberInitAsFunctionReferenceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NSNumberInitAsFunctionReferenceRule.swift @@ -16,11 +16,11 @@ struct NSNumberInitAsFunctionReferenceRule: Rule { Example("let value = NSNumber.init(value: 0.0)"), Example("[0, 0.2].map { NSNumber(value: $0) }"), Example("[0, 0.2].map(NSDecimalNumber.init(value:))"), - Example("[0, 0.2].map { NSDecimalNumber(value: $0) }") + Example("[0, 0.2].map { NSDecimalNumber(value: $0) }"), ], triggeringExamples: [ Example("[0, 0.2].map(↓NSNumber.init)"), - Example("[0, 0.2].map(↓NSDecimalNumber.init)") + Example("[0, 0.2].map(↓NSDecimalNumber.init)"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NSObjectPreferIsEqualRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NSObjectPreferIsEqualRuleExamples.swift index 8213de49a2..acce2b7b15 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NSObjectPreferIsEqualRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NSObjectPreferIsEqualRuleExamples.swift @@ -82,7 +82,7 @@ internal struct NSObjectPreferIsEqualRuleExamples { } } } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] static let triggeringExamples: [Example] = [ @@ -157,6 +157,6 @@ internal struct NSObjectPreferIsEqualRuleExamples { } } } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift index 24cd22d7a1..2e83b87bde 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift @@ -10,11 +10,11 @@ struct NonOptionalStringDataConversionRule: Rule { kind: .lint, nonTriggeringExamples: [ Example("Data(\"foo\".utf8)"), - Example("String(decoding: data, as: UTF8.self)") + Example("String(decoding: data, as: UTF8.self)"), ], triggeringExamples: [ Example("\"foo\".data(using: .utf8)"), - Example("String(data: data, encoding: .utf8)") + Example("String(data: data, encoding: .utf8)"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRuleExamples.swift index bd1b60ab0e..7aa9c683aa 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRuleExamples.swift @@ -13,7 +13,7 @@ internal struct NotificationCenterDetachmentRuleExamples { NotificationCenter.default.removeObserver(otherObject) } } - """) + """), ] static let triggeringExamples = [ @@ -23,6 +23,6 @@ internal struct NotificationCenterDetachmentRuleExamples { ↓NotificationCenter.default.removeObserver(self) } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/OrphanedDocCommentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/OrphanedDocCommentRule.swift index acd440a5ae..428b79721e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/OrphanedDocCommentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/OrphanedDocCommentRule.swift @@ -29,7 +29,7 @@ struct OrphanedDocCommentRule: Rule { /// Look here for more info: /// https://github.com. var myGreatProperty: String! - """) + """), ], triggeringExamples: [ Example(""" @@ -64,7 +64,7 @@ struct OrphanedDocCommentRule: Rule { // Not a doc string var myGreatProperty: String! } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/OverriddenSuperCallRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/OverriddenSuperCallRule.swift index dd1bd23003..84f8c0d3a2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/OverriddenSuperCallRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/OverriddenSuperCallRule.swift @@ -46,7 +46,7 @@ struct OverriddenSuperCallRule: OptInRule { } } } - """) + """), ], triggeringExamples: [ Example(""" @@ -71,7 +71,7 @@ struct OverriddenSuperCallRule: OptInRule { override func didReceiveMemoryWarning() {↓ } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift index fe02f72cf7..99d47cddff 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift @@ -25,11 +25,11 @@ struct OverrideInExtensionRule: OptInRule, SwiftSyntaxRule { extension Foo.Bar { override var description: String { return "" } } - """) + """), ], triggeringExamples: [ Example("extension Person {\n override ↓var age: Int { return 42 }\n}"), - Example("extension Person {\n override ↓func celebrateBirthday() {}\n}") + Example("extension Person {\n override ↓func celebrateBirthday() {}\n}"), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift index e53bd22288..fbda7181e3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift @@ -27,7 +27,7 @@ struct PeriodSpacingRule: SourceKitFreeRule, OptInRule, SubstitutionCorrectableR - Sentence 2 new line characters after. **/ - """) + """), ], triggeringExamples: [ Example("/* Only god knows why. ↓ This symbol does nothing. */", testWrappingInComment: false), @@ -35,7 +35,7 @@ struct PeriodSpacingRule: SourceKitFreeRule, OptInRule, SubstitutionCorrectableR Example("// Single. Double. ↓ End.", testWrappingInComment: false), Example("// Single. Double. ↓ Triple. ↓ End.", testWrappingInComment: false), Example("// Triple. ↓ Quad. ↓ End.", testWrappingInComment: false), - Example("/// - code: Identifier of the error. ↓ Integer.", testWrappingInComment: false) + Example("/// - code: Identifier of the error. ↓ Integer.", testWrappingInComment: false), ], corrections: [ Example("/* Why. ↓ Symbol does nothing. */"): Example("/* Why. Symbol does nothing. */"), @@ -43,7 +43,7 @@ struct PeriodSpacingRule: SourceKitFreeRule, OptInRule, SubstitutionCorrectableR Example("// Single. Double. ↓ End."): Example("// Single. Double. End."), Example("// Single. Double. ↓ Triple. ↓ End."): Example("// Single. Double. Triple. End."), Example("// Triple. ↓ Quad. ↓ End."): Example("// Triple. Quad. End."), - Example("/// - code: Identifier. ↓ Integer."): Example("/// - code: Identifier. Integer.") + Example("/// - code: Identifier. ↓ Integer."): Example("/// - code: Identifier. Integer."), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateActionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateActionRule.swift index bc180be017..6e2a40a1f1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateActionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateActionRule.swift @@ -15,7 +15,7 @@ struct PrivateActionRule: OptInRule { Example("class Foo {\n\t@IBAction fileprivate func barButtonTapped(_ sender: UIButton) {}\n}"), Example("struct Foo {\n\t@IBAction fileprivate func barButtonTapped(_ sender: UIButton) {}\n}"), Example("private extension Foo {\n\t@IBAction func barButtonTapped(_ sender: UIButton) {}\n}"), - Example("fileprivate extension Foo {\n\t@IBAction func barButtonTapped(_ sender: UIButton) {}\n}") + Example("fileprivate extension Foo {\n\t@IBAction func barButtonTapped(_ sender: UIButton) {}\n}"), ], triggeringExamples: [ Example("class Foo {\n\t@IBAction ↓func barButtonTapped(_ sender: UIButton) {}\n}"), @@ -28,7 +28,7 @@ struct PrivateActionRule: OptInRule { Example("extension Foo {\n\t@IBAction public ↓func barButtonTapped(_ sender: UIButton) {}\n}"), Example("extension Foo {\n\t@IBAction internal ↓func barButtonTapped(_ sender: UIButton) {}\n}"), Example("public extension Foo {\n\t@IBAction ↓func barButtonTapped(_ sender: UIButton) {}\n}"), - Example("internal extension Foo {\n\t@IBAction ↓func barButtonTapped(_ sender: UIButton) {}\n}") + Example("internal extension Foo {\n\t@IBAction ↓func barButtonTapped(_ sender: UIButton) {}\n}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateOutletRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateOutletRule.swift index 8c1ba43808..cadc2474d2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateOutletRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateOutletRule.swift @@ -36,7 +36,7 @@ struct PrivateOutletRule: OptInRule { Example( "class Foo { @IBOutlet fileprivate(set) weak var label: UILabel? }", configuration: ["allow_private_set": true] - ) + ), ], triggeringExamples: [ Example("class Foo { @IBOutlet ↓var label: UILabel? }"), @@ -73,7 +73,7 @@ struct PrivateOutletRule: OptInRule { ellipsisButtonDidTouch?(self) } } - """, configuration: ["allow_private_set": false], excludeFromDocumentation: true) + """, configuration: ["allow_private_set": false], excludeFromDocumentation: true), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSubjectRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSubjectRuleExamples.swift index fc119d4d8c..0c2f06a1f4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSubjectRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSubjectRuleExamples.swift @@ -118,7 +118,7 @@ internal struct PrivateSubjectRuleExamples { let goodSubject = PassthroughSubject(true) } """ - ) + ), ] static let triggeringExamples: [Example] = [ @@ -272,6 +272,6 @@ internal struct PrivateSubjectRuleExamples { CurrentValueSubject(true) } """# - ) + ), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift index 2f8321a704..3c88ee263f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRuleExamples.swift @@ -101,7 +101,7 @@ internal struct PrivateSwiftUIStatePropertyRuleExamples { actor ContentView: View { @State private var isPlaying: Bool = false } - """) + """), ] static let triggeringExamples: [Example] = [ @@ -184,7 +184,7 @@ internal struct PrivateSwiftUIStatePropertyRuleExamples { Example(""" struct ContentView: View { @State ↓fileprivate(set) public var isPlaying = false - """) + """), ] static let corrections: [Example: Example] = [ @@ -265,6 +265,6 @@ internal struct PrivateSwiftUIStatePropertyRuleExamples { /// This will track if the content is currently playing private var isPlaying: Bool = false } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateUnitTestRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateUnitTestRule.swift index 32264f5f90..44d0db3b74 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateUnitTestRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateUnitTestRule.swift @@ -62,7 +62,7 @@ struct PrivateUnitTestRule: Rule { private func atest() {} private static func test3() {} } - """) + """), ], triggeringExamples: [ Example(""" @@ -96,7 +96,7 @@ struct PrivateUnitTestRule: Rule { public func test3() {} private ↓func test4() {} } - """) + """), ], corrections: [ Example(""" @@ -122,7 +122,7 @@ struct PrivateUnitTestRule: Rule { @objc private func test3() {} internal func test4() {} } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift index a03d759861..c3ca38b0e8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift @@ -11,11 +11,11 @@ struct ProhibitedInterfaceBuilderRule: OptInRule { kind: .lint, nonTriggeringExamples: [ wrapExample("var label: UILabel!"), - wrapExample("@objc func buttonTapped(_ sender: UIButton) {}") + wrapExample("@objc func buttonTapped(_ sender: UIButton) {}"), ], triggeringExamples: [ wrapExample("@IBOutlet ↓var label: UILabel!"), - wrapExample("@IBAction ↓func buttonTapped(_ sender: UIButton) {}") + wrapExample("@IBAction ↓func buttonTapped(_ sender: UIButton) {}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedSuperRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedSuperRule.swift index f6ed403340..f19d2ba4fe 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedSuperRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedSuperRule.swift @@ -32,7 +32,7 @@ struct ProhibitedSuperRule: OptInRule { } } } - """) + """), ], triggeringExamples: [ Example(""" @@ -67,7 +67,7 @@ struct ProhibitedSuperRule: OptInRule { } } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRuleExamples.swift index 824f9a6442..16ebe4dbdd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRuleExamples.swift @@ -172,7 +172,7 @@ internal struct QuickDiscouragedCallRuleExamples { xitBehavesLike("foo") } } - """) + """), ] static let triggeringExamples: [Example] = [ @@ -323,6 +323,6 @@ internal struct QuickDiscouragedCallRuleExamples { } } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRuleExamples.swift index 9a16aa1f3a..3b0e1077bc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRuleExamples.swift @@ -13,7 +13,7 @@ internal struct QuickDiscouragedFocusedTestRuleExamples { } } } - """) + """), ] static let triggeringExamples = [ @@ -80,6 +80,6 @@ internal struct QuickDiscouragedFocusedTestRuleExamples { ↓fitBehavesLike("foo") } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRuleExamples.swift index b6490f4715..eb8018cd95 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRuleExamples.swift @@ -13,7 +13,7 @@ internal struct QuickDiscouragedPendingTestRuleExamples { } } } - """) + """), ] static let triggeringExamples = [ @@ -87,6 +87,6 @@ internal struct QuickDiscouragedPendingTestRuleExamples { ↓xitBehavesLike("foo") } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/RawValueForCamelCasedCodableEnumRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/RawValueForCamelCasedCodableEnumRule.swift index 39e7662ee2..7144b5a374 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/RawValueForCamelCasedCodableEnumRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/RawValueForCamelCasedCodableEnumRule.swift @@ -58,7 +58,7 @@ struct RawValueForCamelCasedCodableEnumRule: OptInRule { case notAcceptable case maybeAcceptable = -1 } - """) + """), ], triggeringExamples: [ Example(""" @@ -88,7 +88,7 @@ struct RawValueForCamelCasedCodableEnumRule: OptInRule { case ↓notAcceptable case maybeAcceptable = "maybe_acceptable" } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift index 529b9fd57e..06d827dad6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift @@ -31,7 +31,7 @@ struct RequiredDeinitRule: OptInRule { deinit { print("Deinit Inner") } } } - """) + """), ], triggeringExamples: [ Example("↓class Apple { }"), @@ -63,7 +63,7 @@ struct RequiredDeinitRule: OptInRule { deinit { } } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift index 09ce28d043..741ef7e1a4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift @@ -104,7 +104,7 @@ struct RequiredEnumCaseRule: OptInRule { case error case notConnected(error: Error) } - """, configuration: exampleConfiguration) + """, configuration: exampleConfiguration), ], triggeringExamples: [ Example(""" @@ -128,7 +128,7 @@ struct RequiredEnumCaseRule: OptInRule { case success case error } - """, configuration: exampleConfiguration) + """, configuration: exampleConfiguration), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift index b350f85955..cc39c1962b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift @@ -67,7 +67,7 @@ struct SelfInPropertyInitializationRule: Rule { func calculateA() -> String { "A" } func calculateB() -> String { "B" } } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -87,7 +87,7 @@ struct SelfInPropertyInitializationRule: Rule { return button }() } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift index 516aff6895..36daed5e35 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift @@ -11,12 +11,12 @@ struct StrongIBOutletRule: OptInRule { kind: .lint, nonTriggeringExamples: [ wrapExample("@IBOutlet var label: UILabel?"), - wrapExample("weak var label: UILabel?") + wrapExample("weak var label: UILabel?"), ], triggeringExamples: [ wrapExample("@IBOutlet ↓weak var label: UILabel?"), wrapExample("@IBOutlet ↓unowned var label: UILabel!"), - wrapExample("@IBOutlet ↓weak var textField: UITextField?") + wrapExample("@IBOutlet ↓weak var textField: UITextField?"), ], corrections: [ wrapExample("@IBOutlet ↓weak var label: UILabel?"): @@ -24,7 +24,7 @@ struct StrongIBOutletRule: OptInRule { wrapExample("@IBOutlet ↓unowned var label: UILabel!"): wrapExample("@IBOutlet var label: UILabel!"), wrapExample("@IBOutlet ↓weak var textField: UITextField?"): - wrapExample("@IBOutlet var textField: UITextField?") + wrapExample("@IBOutlet var textField: UITextField?"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRuleExamples.swift index 12d2bc0d15..736c9e6031 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRuleExamples.swift @@ -74,7 +74,7 @@ internal struct TestCaseAccessibilityRuleExamples { func testFoo() {} } - """) + """), ] static let triggeringExamples = [ @@ -105,7 +105,7 @@ internal struct TestCaseAccessibilityRuleExamples { final class BarTests: XCTestCase { ↓class Nested {} } - """) + """), ] static let corrections = [ @@ -142,6 +142,6 @@ internal struct TestCaseAccessibilityRuleExamples { private func helperFunction() {} } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TodoRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TodoRule.swift index 524e4bb072..4ef5f9b115 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TodoRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TodoRule.swift @@ -12,7 +12,7 @@ struct TodoRule: Rule { kind: .lint, nonTriggeringExamples: [ Example("// notaTODO:"), - Example("// notaFIXME:") + Example("// notaFIXME:"), ], triggeringExamples: [ Example("// ↓TODO:"), @@ -22,7 +22,7 @@ struct TodoRule: Rule { Example("/* ↓FIXME: */"), Example("/* ↓TODO: */"), Example("/** ↓FIXME: */"), - Example("/** ↓TODO: */") + Example("/** ↓TODO: */"), ].skipWrappingInCommentTests() ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift index 2d5d878ce4..7e977c51c5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift @@ -24,7 +24,7 @@ struct TypesafeArrayInitRule: AnalyzerRule { } let ints = IntArray() let intsCopy = ints.map { $0 } - """) + """), ], triggeringExamples: [ Example(""" @@ -45,7 +45,7 @@ struct TypesafeArrayInitRule: AnalyzerRule { func next() -> Int? { nil } } let array = Generator().↓map { i in i } - """) + """), ], requiresFileOnDisk: true ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift index 5e2cd82b4b..bc9c7f6894 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift @@ -105,7 +105,7 @@ struct UnhandledThrowingTaskRule: OptInRule { try someThrowingFunc() } } - """) + """), ], triggeringExamples: [ Example(""" @@ -181,7 +181,7 @@ struct UnhandledThrowingTaskRule: OptInRule { try await someThrowingFunction() } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift index 2014039e0d..1109108422 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift @@ -113,7 +113,7 @@ struct UnneededOverrideRuleExamples { super.bar(value: value) } } - """) + """), ] static let triggeringExamples = [ @@ -167,7 +167,7 @@ struct UnneededOverrideRuleExamples { super.bar(animated: animated, completion: completion) } } - """) + """), ] static let corrections = [ @@ -221,6 +221,6 @@ struct UnneededOverrideRuleExamples { super.init(i: i) } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift index ab1bbf7e0a..062bb87935 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift @@ -24,12 +24,12 @@ struct UnownedVariableCaptureRule: OptInRule { self.value = value } } - """) + """), ], triggeringExamples: [ Example("foo { [↓unowned self] in _ }"), Example("foo { [↓unowned bar] in _ }"), - Example("foo { [bar, ↓unowned self] in _ }") + Example("foo { [bar, ↓unowned self] in _ }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift index d913a685c8..d8ce4a85be 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift @@ -94,7 +94,7 @@ struct UnusedCaptureListRule: SwiftSyntaxRule, OptInRule { } someInstanceFunction() } - """) + """), ], triggeringExamples: [ Example(""" @@ -140,7 +140,7 @@ struct UnusedCaptureListRule: SwiftSyntaxRule, OptInRule { } someInstanceFunction() } - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRuleExamples.swift index 4ef8f81fbb..cd76a55d37 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRuleExamples.swift @@ -62,7 +62,7 @@ enum UnusedClosureParameterRuleExamples { """), Example(#"_ = ["a"].filter { `class` in `class`.hasPrefix("a") }"#), Example("let closure: (Int) -> Void = { `foo` in _ = foo }"), - Example("let closure: (Int) -> Void = { foo in _ = `foo` }") + Example("let closure: (Int) -> Void = { foo in _ = `foo` }"), ] static let triggering = [ @@ -97,7 +97,7 @@ enum UnusedClosureParameterRuleExamples { Example(""" let class1 = "a" _ = ["a"].filter { ↓`class` in `class1`.hasPrefix("a") } - """) + """), ] static let corrections = [ @@ -166,6 +166,6 @@ enum UnusedClosureParameterRuleExamples { let failure: Failure = { _, error in observer.sendFailed(error) } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift index 76284d83df..1e36d5f07c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedControlFlowLabelRule.swift @@ -28,7 +28,7 @@ struct UnusedControlFlowLabelRule: Rule { break loop } } while true - """) + """), ], triggeringExamples: [ Example("↓loop: while true { break }"), @@ -48,7 +48,7 @@ struct UnusedControlFlowLabelRule: Rule { break } } while true - """) + """), ], corrections: [ Example("↓loop: while true { break }"): Example("while true { break }"), @@ -80,7 +80,7 @@ struct UnusedControlFlowLabelRule: Rule { break } } while true - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index 02ce724740..8d483a72ec 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -274,7 +274,7 @@ private extension SourceKittenDictionary { "tableView(_:commit:forRowAt:)", "tableView(_:editingStyleForRowAt:)", "tableView(_:willDisplayHeaderView:forSection:)", - "tableView(_:willSelectRowAt:)" + "tableView(_:willSelectRowAt:)", ] return functionsToSkipForSR11985.contains(name) @@ -297,7 +297,7 @@ private extension SourceKittenDictionary { "buildFinalResult(_:)", // https://github.com/apple/swift-evolution/blob/main/proposals/0348-buildpartialblock.md "buildPartialBlock(first:)", - "buildPartialBlock(accumulated:next:)" + "buildPartialBlock(accumulated:next:)", ] return resultBuilderStaticMethods.contains(name) @@ -330,7 +330,7 @@ private let declarationKindsToSkip: Set = [ .functionConstructor, .functionDestructor, .functionSubscript, - .genericTypeParam + .genericTypeParam, ] private let declarationAttributesToSkip: Set = [ @@ -338,5 +338,5 @@ private let declarationAttributesToSkip: Set = [ .main, .nsApplicationMain, .override, - .uiApplicationMain + .uiApplicationMain, ] diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift index 3118ed3ba3..393aee95f6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRuleExamples.swift @@ -136,7 +136,7 @@ struct UnusedDeclarationRuleExamples { acceptComponentBuilder { "hello" } - """) + """), ] + platformSpecificNonTriggeringExamples static let triggeringExamples = [ @@ -215,7 +215,7 @@ struct UnusedDeclarationRuleExamples { Example(""" class ↓C {} extension C {} - """) + """), ] + ["actor", "enum", "class", "struct"].map { Example(""" protocol Foo {} @@ -277,7 +277,7 @@ struct UnusedDeclarationRuleExamples { didSet { print("didSet") } } } - """) + """), ] private static let platformSpecificTriggeringExamples = [ @@ -319,7 +319,7 @@ struct UnusedDeclarationRuleExamples { final class ↓Bar { var ↓foo = Foo() } - """) + """), ] #else private static let platformSpecificNonTriggeringExamples = [Example]() diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift index 31d5be392b..5a51d7f0e3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift @@ -259,7 +259,7 @@ private extension SwiftLintFile { guard let kind else { return false } return [ "source.lang.swift.ref.function.operator", - "source.lang.swift.ref.function.method.static" + "source.lang.swift.ref.function.method.static", ].contains { kind.hasPrefix($0) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift index c8ac95135c..5a74494073 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift @@ -24,7 +24,7 @@ struct UnusedImportRuleExamples { import Foundation let 👨‍👩‍👧‍👦 = #selector(NSArray.contains(_:)) 👨‍👩‍👧‍👦 == 👨‍👩‍👧‍👦 - """) + """), ] static let triggeringExamples = [ @@ -62,7 +62,7 @@ struct UnusedImportRuleExamples { ↓import Swift ↓import SwiftShims func foo(error: Swift.Error) {} - """) + """), ] static let corrections = [ @@ -159,9 +159,9 @@ struct UnusedImportRuleExamples { "allowed_transitive_imports": [ [ "module": "Foundation", - "allowed_transitive_imports": ["CoreFoundation"] - ] as [String: any Sendable] - ] + "allowed_transitive_imports": ["CoreFoundation"], + ] as [String: any Sendable], + ], ] as [String: any Sendable], testMultiByteOffsets: false, testOnLinux: false): Example(""" import CoreFoundation @@ -187,9 +187,9 @@ struct UnusedImportRuleExamples { "allowed_transitive_imports": [ [ "module": "Foundation", - "allowed_transitive_imports": ["CoreFoundation"] - ] as [String: any Sendable] - ] + "allowed_transitive_imports": ["CoreFoundation"], + ] as [String: any Sendable], + ], ] as [String: any Sendable]): Example(""" import Foundation @@ -229,6 +229,6 @@ struct UnusedImportRuleExamples { """): Example(""" func foo(error: Swift.Error) {} - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedSetterValueRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedSetterValueRule.swift index 6624acca97..a3073f47b5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedSetterValueRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedSetterValueRule.swift @@ -61,7 +61,7 @@ struct UnusedSetterValueRule: Rule { } set {} } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -124,7 +124,7 @@ struct UnusedSetterValueRule: Rule { Persister.shared.aValue = aValue } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift index 47ff7bf31f..922d4034af 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ValidIBInspectableRule.swift @@ -68,7 +68,7 @@ struct ValidIBInspectableRule: Rule { } } } - """) + """), ], triggeringExamples: [ Example(""" @@ -105,7 +105,7 @@ struct ValidIBInspectableRule: Rule { class Foo { @IBInspectable private ↓var x: Optional } - """) + """), ] ) @@ -122,7 +122,7 @@ struct ValidIBInspectableRule: Rule { "UIColor", "NSColor", "UIImage", - "NSImage" + "NSImage", ] let types = [ @@ -135,7 +135,7 @@ struct ValidIBInspectableRule: Rule { "CGSize", "NSSize", "CGRect", - "NSRect" + "NSRect", ] let intTypes: [String] = ["", "8", "16", "32", "64"].flatMap { size in diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/WeakDelegateRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/WeakDelegateRule.swift index b55e70d007..42bf2f3540 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/WeakDelegateRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/WeakDelegateRule.swift @@ -50,7 +50,7 @@ struct WeakDelegateRule: OptInRule { } } """, excludeFromDocumentation: true), - Example("private var appDelegate: String?", excludeFromDocumentation: true) + Example("private var appDelegate: String?", excludeFromDocumentation: true), ], triggeringExamples: [ Example("class Foo {\n ↓var delegate: SomeProtocol?\n}"), @@ -62,7 +62,7 @@ struct WeakDelegateRule: OptInRule { print("Updated delegate") } } - """) + """), ] ) } @@ -123,7 +123,7 @@ private extension VariableDeclSyntax { let ignoredAttributes: Set = [ "UIApplicationDelegateAdaptor", "NSApplicationDelegateAdaptor", - "WKExtensionDelegateAdaptor" + "WKExtensionDelegateAdaptor", ] return attributes.contains { attr in diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/YodaConditionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/YodaConditionRule.swift index 55f692da79..afff97830c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/YodaConditionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/YodaConditionRule.swift @@ -21,7 +21,7 @@ struct YodaConditionRule: OptInRule { Example("if foo == nil {}"), Example("if flags & 1 == 1 {}"), Example("if true {}", excludeFromDocumentation: true), - Example("if true == false || b, 2 != 3, {}", excludeFromDocumentation: true) + Example("if true == false || b, 2 != 3, {}", excludeFromDocumentation: true), ], triggeringExamples: [ Example("if ↓42 == foo {}"), @@ -32,7 +32,7 @@ struct YodaConditionRule: OptInRule { Example("while ↓1 < foo { }"), Example("if ↓nil == foo {}"), Example("while ↓1 > i + 5 {}"), - Example("if ↓200 <= i && i <= 299 || ↓600 <= i {}") + Example("if ↓200 <= i && i <= 299 || ↓600 <= i {}"), ]) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift index 899c013568..af7f9b1ce7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift @@ -13,7 +13,7 @@ internal struct ClosureBodyLengthRuleExamples { labeledArgumentClosure(codeLinesCount: 29), multiLabeledArgumentClosures(codeLinesCount: 29), labeledAndTrailingClosures(codeLinesCount: 29), - lazyInitialization(codeLinesCount: 28) + lazyInitialization(codeLinesCount: 28), ] static let triggeringExamples: [Example] = [ @@ -23,7 +23,7 @@ internal struct ClosureBodyLengthRuleExamples { labeledArgumentClosure("↓", codeLinesCount: 31), multiLabeledArgumentClosures("↓", codeLinesCount: 31), labeledAndTrailingClosures("↓", codeLinesCount: 31), - lazyInitialization("↓", codeLinesCount: 29) + lazyInitialization("↓", codeLinesCount: 29), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift index 9b0aaac4d0..73295f80d8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift @@ -42,7 +42,7 @@ struct CyclomaticComplexityRule: Rule { if true {}; if true {}; if true {}; if true {}; if true {} } } - """) + """), ], triggeringExamples: [ Example(""" @@ -67,7 +67,7 @@ struct CyclomaticComplexityRule: Rule { } } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/EnumCaseAssociatedValuesLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/EnumCaseAssociatedValuesLengthRule.swift index 0cc37a4980..5804d2a377 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/EnumCaseAssociatedValuesLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/EnumCaseAssociatedValuesLengthRule.swift @@ -20,7 +20,7 @@ struct EnumCaseAssociatedValuesLengthRule: OptInRule { enum Barcode { case upc(Int, Int, Int, Int) } - """) + """), ], triggeringExamples: [ Example(""" @@ -33,7 +33,7 @@ struct EnumCaseAssociatedValuesLengthRule: OptInRule { enum Barcode { case ↓upc(Int, Int, Int, Int, Int, Int) } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/FileLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/FileLengthRule.swift index 4604c467d4..2d62a54965 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/FileLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/FileLengthRule.swift @@ -14,7 +14,7 @@ struct FileLengthRule: Rule { triggeringExamples: [ Example(repeatElement("print(\"swiftlint\")\n", count: 401).joined()), Example((repeatElement("print(\"swiftlint\")\n", count: 400) + ["//\n"]).joined()), - Example(repeatElement("print(\"swiftlint\")\n\n", count: 201).joined()) + Example(repeatElement("print(\"swiftlint\")\n\n", count: 201).joined()), ].skipWrappingInCommentTests() ) @@ -39,10 +39,14 @@ struct FileLengthRule: Rule { let reason = "File should contain \(configuration.severityConfiguration.warning) lines or less" + (configuration.ignoreCommentOnlyLines ? " excluding comments and whitespaces" : "") + ": currently contains \(lineCount)" - return [StyleViolation(ruleDescription: Self.description, - severity: parameter.severity, - location: Location(file: file.path, line: file.lines.count), - reason: reason)] + return [ + StyleViolation( + ruleDescription: Self.description, + severity: parameter.severity, + location: Location(file: file.path, line: file.lines.count), + reason: reason + ), + ] } return [] diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/FunctionParameterCountRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/FunctionParameterCountRule.swift index 6990fe89fb..27895f1c0c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/FunctionParameterCountRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/FunctionParameterCountRule.swift @@ -22,7 +22,7 @@ struct FunctionParameterCountRule: Rule { func f(a: [Int], b: Int, c: Int, d: Int, f: Int) -> [Int] { let s = a.flatMap { $0 as? [String: Int] } ?? []}} """), - Example("override func f(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {}") + Example("override func f(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {}"), ], triggeringExamples: [ Example("↓func f(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {}"), @@ -32,7 +32,7 @@ struct FunctionParameterCountRule: Rule { struct Foo { init(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {} ↓func bar(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {}} - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/LargeTupleRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/LargeTupleRuleExamples.swift index e801fb531d..ec604610ee 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/LargeTupleRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/LargeTupleRuleExamples.swift @@ -27,7 +27,7 @@ struct LargeTupleRuleExamples { Example("func foo(bar: (Int, String, Float) async -> Void)"), Example("func foo(bar: (Int, String, Float) async throws -> Void)"), Example("func getDictionaryAndInt() async -> (Dictionary, Int)?"), - Example("func getGenericTypeAndInt() async -> (Type, Int)?") + Example("func getGenericTypeAndInt() async -> (Type, Int)?"), ] static let triggeringExamples: [Example] = [ @@ -51,6 +51,6 @@ struct LargeTupleRuleExamples { Example("func foo() async throws -> ↓(Int, Int, Int)"), Example("func foo() async throws -> ↓(Int, Int, Int) {}"), Example("func foo() async throws -> ↓(Int, ↓(String, String, String), Int) {}"), - Example("func getDictionaryAndInt() async -> (Dictionary, Int)?") + Example("func getDictionaryAndInt() async -> (Dictionary, Int)?"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift index d016b35915..f044995d31 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift @@ -16,12 +16,12 @@ struct LineLengthRule: Rule { nonTriggeringExamples: [ Example(String(repeating: "/", count: 120) + ""), Example(String(repeating: "#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)", count: 120) + ""), - Example(String(repeating: "#imageLiteral(resourceName: \"image.jpg\")", count: 120) + "") + Example(String(repeating: "#imageLiteral(resourceName: \"image.jpg\")", count: 120) + ""), ], triggeringExamples: [ Example(String(repeating: "/", count: 121) + ""), Example(String(repeating: "#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)", count: 121) + ""), - Example(String(repeating: "#imageLiteral(resourceName: \"image.jpg\")", count: 121) + "") + Example(String(repeating: "#imageLiteral(resourceName: \"image.jpg\")", count: 121) + ""), ].skipWrappingInCommentTests().skipWrappingInStringTests() ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift index 71622e264a..d2934ed470 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift @@ -48,7 +48,7 @@ internal struct NestingRuleExamples { extension Example_0 { \(type) Example_1 {} } - """) + """), ] } @@ -99,7 +99,7 @@ internal struct NestingRuleExamples { } } } - """) + """), ] private static let nonTriggeringProtocolExamples = @@ -131,7 +131,7 @@ internal struct NestingRuleExamples { extension Example_0 { protocol Example_1 {} } - """) + """), ] } @@ -180,7 +180,7 @@ internal struct NestingRuleExamples { } } }) - """) + """), ] } @@ -225,7 +225,7 @@ internal struct NestingRuleExamples { } } } - """) + """), ] } } @@ -284,7 +284,7 @@ extension NestingRuleExamples { ↓\(type) Example_2 {} } } - """) + """), ] } @@ -343,7 +343,7 @@ extension NestingRuleExamples { } } } - """) + """), ] private static let triggeringClosureAndStatementExamples = @@ -401,7 +401,7 @@ extension NestingRuleExamples { } } }) - """) + """), ] } @@ -442,7 +442,7 @@ extension NestingRuleExamples { ↓protocol Example_2 {} } } - """) + """), ] } @@ -496,7 +496,7 @@ extension NestingRuleExamples { } } } - """) + """), ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift index 18486f8f29..0e5689c110 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift @@ -23,7 +23,7 @@ struct TypeBodyLengthRule: SwiftSyntaxRule { wrapExample(type, "let abc = 0\n", 249), wrapExample(type, "\n", 251), wrapExample(type, "// this is a comment\n", 251), - wrapExample(type, "let abc = 0\n", 249, "\n/* this is\na multiline comment\n*/") + wrapExample(type, "let abc = 0\n", 249, "\n/* this is\na multiline comment\n*/"), ] }), triggeringExamples: ["class", "struct", "enum", "actor"].map({ type in diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift index ba1ddb4ca9..4018c4b1c6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift @@ -13,18 +13,18 @@ struct ContainsOverFilterCountRule: OptInRule { return [ Example("let result = myList.filter(where: { $0 % 2 == 0 }).count \(operation) 1"), Example("let result = myList.filter { $0 % 2 == 0 }.count \(operation) 1"), - Example("let result = myList.filter(where: { $0 % 2 == 0 }).count \(operation) 01") + Example("let result = myList.filter(where: { $0 % 2 == 0 }).count \(operation) 01"), ] } + [ Example("let result = myList.contains(where: { $0 % 2 == 0 })"), Example("let result = !myList.contains(where: { $0 % 2 == 0 })"), - Example("let result = myList.contains(10)") + Example("let result = myList.contains(10)"), ], triggeringExamples: [">", "==", "!="].flatMap { operation in return [ Example("let result = ↓myList.filter(where: { $0 % 2 == 0 }).count \(operation) 0"), Example("let result = ↓myList.filter { $0 % 2 == 0 }.count \(operation) 0"), - Example("let result = ↓myList.filter(where: someFunction).count \(operation) 0") + Example("let result = ↓myList.filter(where: someFunction).count \(operation) 0"), ] } ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift index 2d08935c26..166459389f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift @@ -12,18 +12,18 @@ struct ContainsOverFilterIsEmptyRule: OptInRule { nonTriggeringExamples: [">", "==", "!="].flatMap { operation in return [ Example("let result = myList.filter(where: { $0 % 2 == 0 }).count \(operation) 1"), - Example("let result = myList.filter { $0 % 2 == 0 }.count \(operation) 1") + Example("let result = myList.filter { $0 % 2 == 0 }.count \(operation) 1"), ] } + [ Example("let result = myList.contains(where: { $0 % 2 == 0 })"), Example("let result = !myList.contains(where: { $0 % 2 == 0 })"), - Example("let result = myList.contains(10)") + Example("let result = myList.contains(10)"), ], triggeringExamples: [ Example("let result = ↓myList.filter(where: { $0 % 2 == 0 }).isEmpty"), Example("let result = !↓myList.filter(where: { $0 % 2 == 0 }).isEmpty"), Example("let result = ↓myList.filter { $0 % 2 == 0 }.isEmpty"), - Example("let result = ↓myList.filter(where: someFunction).isEmpty") + Example("let result = ↓myList.filter(where: someFunction).isEmpty"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift index 42469c5c9f..b77eb1b9e3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift @@ -12,7 +12,7 @@ struct ContainsOverFirstNotNilRule: OptInRule { nonTriggeringExamples: ["first", "firstIndex"].flatMap { method in return [ Example("let \(method) = myList.\(method)(where: { $0 % 2 == 0 })"), - Example("let \(method) = myList.\(method) { $0 % 2 == 0 }") + Example("let \(method) = myList.\(method) { $0 % 2 == 0 }"), ] }, triggeringExamples: ["first", "firstIndex"].flatMap { method in @@ -23,7 +23,7 @@ struct ContainsOverFirstNotNilRule: OptInRule { Example("↓myList.map { $0 + 1 }.\(method)(where: { $0 % 2 == 0 }) \(comparison) nil"), Example("↓myList.\(method)(where: someFunction) \(comparison) nil"), Example("↓myList.map { $0 + 1 }.\(method) { $0 % 2 == 0 } \(comparison) nil"), - Example("(↓myList.\(method) { $0 % 2 == 0 }) \(comparison) nil") + Example("(↓myList.\(method) { $0 % 2 == 0 }) \(comparison) nil"), ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift index 71088d6e2d..05b62733a9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift @@ -13,7 +13,7 @@ struct ContainsOverRangeNilComparisonRule: OptInRule { Example("let range = myString.range(of: \"Test\")"), Example("myString.contains(\"Test\")"), Example("!myString.contains(\"Test\")"), - Example("resourceString.range(of: rule.regex, options: .regularExpression) != nil") + Example("resourceString.range(of: rule.regex, options: .regularExpression) != nil"), ], triggeringExamples: ["!=", "=="].flatMap { comparison in return [ diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCollectionLiteralRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCollectionLiteralRule.swift index 1b739a34dc..2d74682cd3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCollectionLiteralRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCollectionLiteralRule.swift @@ -13,7 +13,7 @@ struct EmptyCollectionLiteralRule: OptInRule { Example("myArray = []"), Example("myArray.isEmpty"), Example("!myArray.isEmpty"), - Example("myDict = [:]") + Example("myDict = [:]"), ], triggeringExamples: [ Example("myArray↓ == []"), @@ -23,7 +23,7 @@ struct EmptyCollectionLiteralRule: OptInRule { Example("myDict↓ != [:]"), Example("myDict↓ == [: ]"), Example("myDict↓ == [ :]"), - Example("myDict↓ == [ : ]") + Example("myDict↓ == [ : ]"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift index 477c1a40d8..c1ffce14f7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyCountRule.swift @@ -19,7 +19,7 @@ struct EmptyCountRule: OptInRule { Example("[Int]().count == 0b01"), Example("[Int]().count == 0o07"), Example("discount == 0"), - Example("order.discount == 0") + Example("order.discount == 0"), ], triggeringExamples: [ Example("[Int]().↓count == 0"), @@ -31,7 +31,7 @@ struct EmptyCountRule: OptInRule { Example("[Int]().↓count == 0x00_00"), Example("[Int]().↓count == 0b00"), Example("[Int]().↓count == 0o00"), - Example("↓count == 0") + Example("↓count == 0"), ], corrections: [ Example("[].↓count == 0"): @@ -61,7 +61,7 @@ struct EmptyCountRule: OptInRule { Example("↓count == 0 && [Int]().↓count == 0o00"): 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("[Int]().count != 3 && ![Int]().isEmpty || isEmpty && [Int]().count > 2"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyStringRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyStringRule.swift index faba6f737b..ad199a36a4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyStringRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/EmptyStringRule.swift @@ -12,14 +12,14 @@ struct EmptyStringRule: OptInRule { nonTriggeringExamples: [ Example("myString.isEmpty"), Example("!myString.isEmpty"), - Example("\"\"\"\nfoo==\n\"\"\"") + Example("\"\"\"\nfoo==\n\"\"\""), ], triggeringExamples: [ Example(#"myString↓ == """#), Example(#"myString↓ != """#), Example(#"myString↓=="""#), Example(##"myString↓ == #""#"##), - Example(###"myString↓ == ##""##"###) + Example(###"myString↓ == ##""##"###), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift index f71f8bd8c2..066b9daaea 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift @@ -15,18 +15,18 @@ struct FinalTestCaseRule: OptInRule { Example("open class Test: XCTestCase {}"), Example("public final class Test: QuickSpec {}"), Example("class Test: MyTestCase {}"), - Example("struct Test: MyTestCase {}", configuration: ["test_parent_classes": "MyTestCase"]) + Example("struct Test: MyTestCase {}", configuration: ["test_parent_classes": "MyTestCase"]), ], triggeringExamples: [ Example("class ↓Test: XCTestCase {}"), Example("public class ↓Test: QuickSpec {}"), - Example("class ↓Test: MyTestCase {}", configuration: ["test_parent_classes": "MyTestCase"]) + Example("class ↓Test: MyTestCase {}", configuration: ["test_parent_classes": "MyTestCase"]), ], corrections: [ Example("class ↓Test: XCTestCase {}"): Example("final class Test: XCTestCase {}"), Example("internal class ↓Test: XCTestCase {}"): - Example("internal final class Test: XCTestCase {}") + Example("internal final class Test: XCTestCase {}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/FirstWhereRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/FirstWhereRule.swift index 474e3d8181..4576af9f98 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/FirstWhereRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/FirstWhereRule.swift @@ -16,7 +16,7 @@ struct FirstWhereRule: OptInRule { Example("(myList.filter { $0 == 1 }.suffix(2)).first"), Example(#"collection.filter("stringCol = '3'").first"#), Example(#"realm?.objects(User.self).filter(NSPredicate(format: "email ==[c] %@", email)).first"#), - Example(#"if let pause = timeTracker.pauses.filter("beginDate < %@", beginDate).first { print(pause) }"#) + Example(#"if let pause = timeTracker.pauses.filter("beginDate < %@", beginDate).first { print(pause) }"#), ], triggeringExamples: [ Example("↓myList.filter { $0 % 2 == 0 }.first"), @@ -27,7 +27,7 @@ struct FirstWhereRule: OptInRule { Example("↓myList.filter({ $0 % 2 == 0 })\n.first"), Example("(↓myList.filter { $0 == 1 }).first"), Example(#"↓myListOfDict.filter { dict in dict["1"] }.first"#), - Example(#"↓myListOfDict.filter { $0["someString"] }.first"#) + Example(#"↓myListOfDict.filter { $0["someString"] }.first"#), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/FlatMapOverMapReduceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/FlatMapOverMapReduceRule.swift index b3e6bfb96b..650990e7cb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/FlatMapOverMapReduceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/FlatMapOverMapReduceRule.swift @@ -11,7 +11,7 @@ struct FlatMapOverMapReduceRule: OptInRule { kind: .performance, nonTriggeringExamples: [ Example("let foo = bar.map { $0.count }.reduce(0, +)"), - Example("let foo = bar.flatMap { $0.array }") + Example("let foo = bar.flatMap { $0.array }"), ], triggeringExamples: [ Example("let foo = ↓bar.map { $0.array }.reduce([], +)") diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/LastWhereRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/LastWhereRule.swift index 7c0c7c0b03..577bc5d34e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/LastWhereRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/LastWhereRule.swift @@ -14,7 +14,7 @@ struct LastWhereRule: OptInRule { Example("myList.last(where: { $0 % 2 == 0 })"), Example("match(pattern: pattern).filter { $0.last == .identifier }"), Example("(myList.filter { $0 == 1 }.suffix(2)).last"), - Example(#"collection.filter("stringCol = '3'").last"#) + Example(#"collection.filter("stringCol = '3'").last"#), ], triggeringExamples: [ Example("↓myList.filter { $0 % 2 == 0 }.last"), @@ -23,7 +23,7 @@ struct LastWhereRule: OptInRule { Example("↓myList.map { $0 + 1 }.filter({ $0 % 2 == 0 }).last?.something()"), Example("↓myList.filter(someFunction).last"), Example("↓myList.filter({ $0 % 2 == 0 })\n.last"), - Example("(↓myList.filter { $0 == 1 }).last") + Example("(↓myList.filter { $0 == 1 }).last"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceBooleanRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceBooleanRule.swift index 4df46b59c2..9298eeb441 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceBooleanRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceBooleanRule.swift @@ -12,7 +12,7 @@ struct ReduceBooleanRule: Rule { 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 }") + Example("nums.reduce(initial: true) { $0.0 && $0.1 == 3 }"), ], triggeringExamples: [ Example("let allNines = nums.↓reduce(true) { $0.0 && $0.1 == 9 }"), @@ -23,7 +23,7 @@ struct ReduceBooleanRule: Rule { 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) }") + Example("nums.reduce(into: true) { (r: inout Bool, s) in r = r && (s == 3) }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceIntoRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceIntoRule.swift index 14c450b895..d683a2d29e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceIntoRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ReduceIntoRule.swift @@ -48,7 +48,7 @@ struct ReduceIntoRule: OptInRule { result.handleValue(value) return result } - """) + """), ], triggeringExamples: [ Example(""" @@ -103,7 +103,7 @@ struct ReduceIntoRule: OptInRule { } } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/SortedFirstLastRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/SortedFirstLastRule.swift index 31e57e23aa..ebe76cb73a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/SortedFirstLastRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/SortedFirstLastRule.swift @@ -26,7 +26,7 @@ struct SortedFirstLastRule: OptInRule { Example("myList.sorted().first(where: someFunction)"), Example("myList.sorted().last(where: someFunction)"), Example("myList.sorted().first { $0 == key }"), - Example("myList.sorted().last { $0 == key }") + Example("myList.sorted().last { $0 == key }"), ], triggeringExamples: [ Example("↓myList.sorted().first"), @@ -41,7 +41,7 @@ struct SortedFirstLastRule: OptInRule { Example("↓myList.map { $0 + 1 }.sorted().last"), Example("↓myList.sorted(by: someFunction).last"), Example("↓myList.map { $0 + 1 }.sorted { $0.description < $1.description }.last"), - Example("↓myList.map { $0 + 1 }.sorted { $0.first < $1.first }.last") + Example("↓myList.map { $0 + 1 }.sorted { $0.first < $1.first }.last"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift index b7bc5e1d31..66e4284f9c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift @@ -12,7 +12,7 @@ struct BlanketDisableCommandConfiguration: SeverityBasedRuleConfiguration { "file_length", "file_name", "file_name_no_space", - "single_test_class" + "single_test_class", ] @ConfigurationElement(key: "always_blanket_disable") private(set) var alwaysBlanketDisableRuleIdentifiers: Set = [] diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift index 8490c18a99..9fef4a4c8e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift @@ -125,7 +125,7 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { watchOSDeploymentTarget, watchOSAppExtensionDeploymentTarget, tvOSDeploymentTarget, - tvOSAppExtensionDeploymentTarget + tvOSAppExtensionDeploymentTarget, ].map { ($0.platform.configurationKey, $0) }) } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift index 22641758c6..776a7000cc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift @@ -14,6 +14,6 @@ struct DiscouragedDirectInitConfiguration: SeverityBasedRuleConfiguration { private(set) var discouragedInits: Set = [ "Bundle", "NSError", - "UIDevice" + "UIDevice", ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift index f9d6c34323..5a88b26009 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift @@ -21,6 +21,6 @@ struct FileTypesOrderConfiguration: SeverityBasedRuleConfiguration { [.mainType], [.extension], [.previewProvider], - [.libraryContentProvider] + [.libraryContentProvider], ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift index 03d2e472bb..281f9079a6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift @@ -8,7 +8,7 @@ struct InclusiveLanguageConfiguration: SeverityBasedRuleConfiguration { "whitelist", "blacklist", "master", - "slave" + "slave", ] private static let defaultAllowedTerms: Set = [ diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift index 4f506391e7..f9404436fa 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift @@ -5,7 +5,7 @@ struct MissingDocsConfiguration: RuleConfiguration { private(set) var parameters = [ RuleParameter(severity: .warning, value: .open), - RuleParameter(severity: .warning, value: .public) + RuleParameter(severity: .warning, value: .public), ] @ConfigurationElement(key: "excludes_extensions") diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift index 70338e61ed..f805557e67 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift @@ -19,7 +19,7 @@ struct ModifierOrderConfiguration: SeverityBasedRuleConfiguration { .required, .convenience, .typeMethods, - .owned + .owned, ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift index ca2a9aeb32..9affca857b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift @@ -33,7 +33,7 @@ struct OverriddenSuperCallConfiguration: SeverityBasedRuleConfiguration { "viewWillAppear(_:)", "viewWillDisappear(_:)", // XCTestCase - "invokeTest()" + "invokeTest()", ] @ConfigurationElement(key: "severity") diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift index 914e3a5dfc..d12c4a91ec 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift @@ -19,7 +19,7 @@ struct ProhibitedSuperConfiguration: SeverityBasedRuleConfiguration { // NSView "updateLayer()", // UIViewController - "loadView()" + "loadView()", ] var resolvedMethodNames: [String] { diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift index 811622d0f7..9a229c6016 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift @@ -40,6 +40,6 @@ struct TypeContentsOrderConfiguration: SeverityBasedRuleConfiguration { [.ibAction], [.otherMethod], [.subscript], - [.deinitializer] + [.deinitializer], ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/AttributesRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/AttributesRuleExamples.swift index e537cebca3..470b75c146 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/AttributesRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/AttributesRuleExamples.swift @@ -95,7 +95,7 @@ internal struct AttributesRuleExamples { @Environment(\.colorScheme) var second: ColorScheme @Persisted(primaryKey: true) var id: Int } - """#, configuration: ["attributes_with_arguments_always_on_line_above": false], excludeFromDocumentation: true) + """#, configuration: ["attributes_with_arguments_always_on_line_above": false], excludeFromDocumentation: true), ] static let triggeringExamples = [ @@ -139,6 +139,6 @@ internal struct AttributesRuleExamples { ) var entities: FetchedResults } - """#, excludeFromDocumentation: true) + """#, excludeFromDocumentation: true), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ClosingBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ClosingBraceRule.swift index 2e876912ec..0d60cd9e91 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ClosingBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ClosingBraceRule.swift @@ -11,11 +11,11 @@ struct ClosingBraceRule: Rule { kind: .style, nonTriggeringExamples: [ Example("[].map({ })"), - Example("[].map(\n { }\n)") + Example("[].map(\n { }\n)"), ], triggeringExamples: [ Example("[].map({ ↓} )"), - Example("[].map({ ↓}\t)") + Example("[].map({ ↓}\t)"), ], corrections: [ Example("[].map({ ↓} )"): Example("[].map({ })") diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRuleExamples.swift index bf1db05f7a..45c83d6d34 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRuleExamples.swift @@ -33,7 +33,7 @@ internal struct ClosureEndIndentationRuleExamples { " anotherClosure: { y in\n" + " print(y)\n" + " })"), - Example("(-variable).foo()") + Example("(-variable).foo()"), ] static let triggeringExamples = [ @@ -52,7 +52,7 @@ internal struct ClosureEndIndentationRuleExamples { "↓},\n" + " anotherClosure: { y in\n" + " print(y)\n" + - "↓})") + "↓})"), ] static let corrections = [ @@ -168,6 +168,6 @@ internal struct ClosureEndIndentationRuleExamples { " print(x)\n" + " }, anotherClosure: { y in\n" + " print(y)\n" + - " })") + " })"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift index 71ad4d59eb..fb9ba872f4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift @@ -29,7 +29,7 @@ struct ClosureParameterPositionRule: Rule { let mediaView: UIView = { [weak self] index in return UIView() }(index) - """) + """), ], triggeringExamples: [ Example(""" @@ -91,7 +91,7 @@ struct ClosureParameterPositionRule: Rule { [weak ↓self] in self?.bar() } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureSpacingRule.swift index 26322c54f7..55da2a8d0f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureSpacingRule.swift @@ -21,7 +21,7 @@ struct ClosureSpacingRule: OptInRule { Example(""" let test1 = func1(arg: { /* do nothing */ }) let test2 = func1 { /* do nothing */ } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example("[].filter↓{ $0.contains(location) }"), @@ -31,7 +31,7 @@ struct ClosureSpacingRule: OptInRule { Example("filter ↓{ sorted ↓{ $0 < $1}}"), Example(""" var tapped: (UITapGestureRecognizer) -> Void = ↓{ _ in /* no-op */ } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], corrections: [ Example("[].filter(↓{$0.contains(location) })"): @@ -41,7 +41,7 @@ struct ClosureSpacingRule: OptInRule { Example("filter ↓{sorted ↓{ $0 < $1}}"): Example("filter { sorted { $0 < $1 } }"), Example("(↓{each in return result.contains(where: ↓{e in return 0})}).count"): - Example("({ each in return result.contains(where: { e in return 0 }) }).count") + Example("({ each in return result.contains(where: { e in return 0 }) }).count"), ] ) } @@ -189,7 +189,7 @@ private extension TokenSyntax { .postfixQuestionMark, .rightParen, .rightSquare, - .semicolon + .semicolon, ] if case .newlines = trailingTrivia.first { return true diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift index 3d34029eb2..1cd10347aa 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift @@ -117,7 +117,7 @@ extension CollectionAlignmentRule { "b" ↓:2, "c" : 3 ] - """) + """), ] } @@ -150,7 +150,7 @@ extension CollectionAlignmentRule { Example(""" NSAttributedString(string: "…", attributes: [.font: UIFont.systemFont(ofSize: 12, weight: .regular), .foregroundColor: UIColor(white: 0, alpha: 0.2)]) - """) + """), ] } @@ -179,7 +179,7 @@ extension CollectionAlignmentRule { "lunch": "sandwich", ↓"dinner": "burger" ] - """) + """), ] } @@ -212,7 +212,7 @@ extension CollectionAlignmentRule { Example(""" NSAttributedString(string: "…", attributes: [.font: UIFont.systemFont(ofSize: 12, weight: .regular), .foregroundColor: UIColor(white: 0, alpha: 0.2)]) - """) + """), ] } @@ -231,7 +231,7 @@ extension CollectionAlignmentRule { ↓4, 6 ] - """) + """), ] } @@ -263,7 +263,7 @@ extension CollectionAlignmentRule { let abc = [ "foo": "bar", "fizz": "buzz" ] - """) + """), ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ColonRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ColonRuleExamples.swift index 73da73825e..a963c54181 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ColonRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ColonRuleExamples.swift @@ -74,7 +74,7 @@ internal struct ColonRuleExamples { case 0x2029 /* PARAGRAPH SEPARATOR */: return true default: return false } - """) + """), ] static let triggeringExamples = [ @@ -135,7 +135,7 @@ internal struct ColonRuleExamples { case .bar↓ : return baz } """), - Example("private var action↓:(() -> Void)?") + Example("private var action↓:(() -> Void)?"), ] static let corrections = [ @@ -219,6 +219,6 @@ internal struct ColonRuleExamples { case .bar: return baz } """), - Example("private var action↓:(() -> Void)?"): Example("private var action: (() -> Void)?") + Example("private var action↓:(() -> Void)?"): Example("private var action: (() -> Void)?"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift index a304035d78..36ce7df4f3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift @@ -22,7 +22,7 @@ struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, protocol G { associatedtype Model: Codable, Equatable } - """) + """), ], triggeringExamples: [ Example("struct A: Codable↓ & Equatable {}"), @@ -36,7 +36,7 @@ struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, protocol G { associatedtype Model: Codable↓ & Equatable } - """) + """), ], corrections: [ Example("struct A: Codable↓ & Equatable {}"): Example("struct A: Codable, Equatable {}"), @@ -54,7 +54,7 @@ struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, protocol G { associatedtype Model: Codable, Equatable } - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift index edb3054648..e71c5eb08f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift @@ -26,7 +26,7 @@ struct CommaRule: CorrectableRule, SourceKitFreeRule { /// appends after an existing message (" (use beNil() to match nils)") case appends(ExpectationMessage, /* Appended Message */ String) } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example("func abc(a: String↓ ,b: String) { }"), @@ -48,7 +48,7 @@ struct CommaRule: CorrectableRule, SourceKitFreeRule { another: parameter, doIt: true, alignment: .center) """), - Example(#"Logger.logError("Hat is too large"↓, info: [])"#) + Example(#"Logger.logError("Hat is too large"↓, info: [])"#), ], corrections: [ Example("func abc(a: String↓,b: String) {}"): Example("func abc(a: String, b: String) {}"), @@ -84,7 +84,7 @@ struct CommaRule: CorrectableRule, SourceKitFreeRule { alignment: .center) """), Example(#"Logger.logError("Hat is too large"↓, info: [])"#): - Example(#"Logger.logError("Hat is too large", info: [])"#) + Example(#"Logger.logError("Hat is too large", info: [])"#), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift index e0f7bf5e16..703125bcc1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift @@ -163,7 +163,7 @@ struct ComputedAccessorsOrderRuleExamples { protocol Foo { subscript(i: Int) -> Int { set get } } - """) + """), ] } @@ -230,7 +230,7 @@ struct ComputedAccessorsOrderRuleExamples { } } } - """) + """), ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ConditionalReturnsOnNewlineRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ConditionalReturnsOnNewlineRule.swift index f1dc20bcc5..7c95293376 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ConditionalReturnsOnNewlineRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ConditionalReturnsOnNewlineRule.swift @@ -19,7 +19,7 @@ struct ConditionalReturnsOnNewlineRule: OptInRule { Example(""" guard something else { return } - """) + """), ], triggeringExamples: [ Example("↓guard true else { return }"), @@ -29,7 +29,7 @@ struct ConditionalReturnsOnNewlineRule: OptInRule { Example("↓if true { return \"YES\" } else { return \"NO\" }"), Example(""" ↓guard condition else { XCTFail(); return } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift index 8ee4ab081b..8afd46d354 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift @@ -28,7 +28,7 @@ struct ControlStatementRule: Rule { Example("if max(a, b) < c {}"), Example("switch (lhs, rhs) {}"), Example("if (f() { g() {} }) {}"), - Example("if (a + f() {} == 1) {}") + Example("if (a + f() {} == 1) {}"), ], triggeringExamples: [ Example("↓if (condition) {}"), @@ -43,7 +43,7 @@ struct ControlStatementRule: Rule { Example("do { ; } ↓while (condition) {}"), Example("↓switch (foo) {}"), Example("do {} ↓catch(let error as NSError) {}"), - Example("↓if (max(a, b) < c) {}") + Example("↓if (max(a, b) < c) {}"), ], corrections: [ Example("↓if (condition) {}"): Example("if condition {}"), @@ -67,7 +67,7 @@ struct ControlStatementRule: Rule { """): Example(""" if a, b == 1 {} - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift index 4221be8564..952e844083 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift @@ -40,7 +40,7 @@ struct DirectReturnRule: OptInRule { return i }(1) } - """) + """), ], triggeringExamples: [ Example(""" @@ -82,7 +82,7 @@ struct DirectReturnRule: OptInRule { return b } } - """) + """), ], corrections: [ Example(""" @@ -175,7 +175,7 @@ struct DirectReturnRule: OptInRule { func f() -> Bool { return true as Bool } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift index 70ab89d64d..d52bd8a7d9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift @@ -59,7 +59,7 @@ struct EmptyEnumArgumentsRule: Rule { guard case .settings(.notifications(_, nil)) = nav else { return false } return true } - """) + """), ], triggeringExamples: [ wrapInSwitch("case .bar↓(_)"), @@ -85,7 +85,7 @@ struct EmptyEnumArgumentsRule: Rule { guard case .settings(.notifications↓(_, _)) = nav else { return false } return true } - """) + """), ], corrections: [ wrapInSwitch("case .bar↓(_)"): wrapInSwitch("case .bar"), @@ -108,7 +108,7 @@ struct EmptyEnumArgumentsRule: Rule { guard case .settings(.notifications) = nav else { return false } return true } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParametersRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParametersRule.swift index 984705e158..806a7d13df 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParametersRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParametersRule.swift @@ -15,20 +15,20 @@ struct EmptyParametersRule: Rule { Example("func foo(completion: () throws -> Void)"), Example("let foo: (ConfigurationTests) -> Void throws -> Void)"), Example("let foo: (ConfigurationTests) -> Void throws -> Void)"), - Example("let foo: (ConfigurationTests) ->Void throws -> Void)") + Example("let foo: (ConfigurationTests) ->Void throws -> Void)"), ], triggeringExamples: [ Example("let abc: ↓(Void) -> Void = {}"), Example("func foo(completion: ↓(Void) -> Void)"), Example("func foo(completion: ↓(Void) throws -> Void)"), - Example("let foo: ↓(Void) -> () throws -> Void)") + Example("let foo: ↓(Void) -> () throws -> Void)"), ], corrections: [ Example("let abc: ↓(Void) -> Void = {}"): Example("let abc: () -> Void = {}"), Example("func foo(completion: ↓(Void) -> Void)"): Example("func foo(completion: () -> Void)"), Example("func foo(completion: ↓(Void) throws -> Void)"): Example("func foo(completion: () throws -> Void)"), - Example("let foo: ↓(Void) -> () throws -> Void)"): Example("let foo: () -> () throws -> Void)") + Example("let foo: ↓(Void) -> () throws -> Void)"): Example("let foo: () -> () throws -> Void)"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift index c9edafb09a..78a7668484 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyParenthesesWithTrailingClosureRule.swift @@ -22,14 +22,14 @@ struct EmptyParenthesesWithTrailingClosureRule: Rule { }, completion: { _ in () }) - """) + """), ], triggeringExamples: [ Example("[1, 2].map↓() { $0 + 1 }"), Example("[1, 2].map↓( ) { $0 + 1 }"), Example("[1, 2].map↓() { number in\n number + 1 \n}"), Example("[1, 2].map↓( ) { number in\n number + 1 \n}"), - Example("func foo() -> [Int] {\n return [1, 2].map↓() { $0 + 1 }\n}") + Example("func foo() -> [Int] {\n return [1, 2].map↓() { $0 + 1 }\n}"), ], corrections: [ Example("[1, 2].map↓() { $0 + 1 }"): Example("[1, 2].map { $0 + 1 }"), @@ -41,7 +41,7 @@ struct EmptyParenthesesWithTrailingClosureRule: Rule { Example("func foo() -> [Int] {\n return [1, 2].map↓() { $0 + 1 }\n}"): Example("func foo() -> [Int] {\n return [1, 2].map { $0 + 1 }\n}"), Example("class C {\n#if true\nfunc f() {\n[1, 2].map↓() { $0 + 1 }\n}\n#endif\n}"): - Example("class C {\n#if true\nfunc f() {\n[1, 2].map { $0 + 1 }\n}\n#endif\n}") + Example("class C {\n#if true\nfunc f() {\n[1, 2].map { $0 + 1 }\n}\n#endif\n}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift index 89df900515..7593d67430 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift @@ -80,7 +80,7 @@ struct ExplicitSelfRule: CorrectableRule, AnalyzerRule { private let kindsToFind: Set = [ "source.lang.swift.ref.function.method.instance", - "source.lang.swift.ref.var.instance" + "source.lang.swift.ref.var.instance", ] private extension SwiftLintFile { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRuleExamples.swift index 39626a427b..8dad43365f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRuleExamples.swift @@ -34,7 +34,7 @@ struct ExplicitSelfRuleExamples { func f1() { A(p1: 10).$p1 } - """) + """), ] static let triggeringExamples = [ @@ -80,7 +80,7 @@ struct ExplicitSelfRuleExamples { func f1() { A(p1: 10).$p1 } - """) + """), ] static let corrections = [ @@ -168,6 +168,6 @@ struct ExplicitSelfRuleExamples { func f1() { A(p1: 10).$p1 } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift index a92b6cae38..bfb6f41fd8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift @@ -14,7 +14,7 @@ struct FileHeaderRule: OptInRule { nonTriggeringExamples: [ Example("let foo = \"Copyright\""), Example("let foo = 2 // Copyright"), - Example("let foo = 2\n // Copyright") + Example("let foo = 2\n // Copyright"), ], triggeringExamples: [ Example("// ↓Copyright"), @@ -27,7 +27,7 @@ struct FileHeaderRule: OptInRule { // Created by Marcelo Fabri on 27/11/16. // ↓Copyright © 2016 Realm. All rights reserved. // - """) + """), ].skipWrappingInCommentTests() ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRuleExamples.swift index 65ddc8ecb1..2d9c3d3691 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRuleExamples.swift @@ -108,7 +108,7 @@ internal struct FileTypesOrderRuleExamples { return 1 } } - """ + """, ] static let nonTriggeringExamples = [ @@ -138,7 +138,7 @@ internal struct FileTypesOrderRuleExamples { LibraryItem(ContentView()) } } - """) + """), ] static let triggeringExamples = [ @@ -222,6 +222,6 @@ internal struct FileTypesOrderRuleExamples { Text("Hello, World!") } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/IdentifierNameRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/IdentifierNameRuleExamples.swift index 3a1779bb56..0e6cba45f9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/IdentifierNameRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/IdentifierNameRuleExamples.swift @@ -29,7 +29,7 @@ internal struct IdentifierNameRuleExamples { static var Bar = 0 } """), - Example("func √ (arg: Double) -> Double { arg }", configuration: ["additional_operators": "√"]) + Example("func √ (arg: Double) -> Double { arg }", configuration: ["additional_operators": "√"]), ] static let triggeringExamples = [ @@ -95,6 +95,6 @@ internal struct IdentifierNameRuleExamples { } } """), - Example("func ↓√ (arg: Double) -> Double { arg }") + Example("func ↓√ (arg: Double) -> Double { arg }"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitGetterRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitGetterRuleExamples.swift index c2683aa487..433ee125e3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitGetterRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitGetterRuleExamples.swift @@ -202,7 +202,7 @@ struct ImplicitGetterRuleExamples { } } } - """) + """), ] static let triggeringExamples: [Example] = [ @@ -261,6 +261,6 @@ struct ImplicitGetterRuleExamples { } } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift index eaf6b8cd71..64c4466ba4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift @@ -8,7 +8,7 @@ struct ImplicitReturnRuleExamples { [1, 2].first(where: { true }) - """) + """), ] static let triggeringExamples = [ @@ -27,7 +27,7 @@ struct ImplicitReturnRuleExamples { [1, 2].first(where: { ↓return true }) - """) + """), ] static let corrections = [ @@ -60,7 +60,7 @@ struct ImplicitReturnRuleExamples { [1, 2].first(where: { true }) - """) + """), ] } @@ -102,7 +102,7 @@ struct ImplicitReturnRuleExamples { return g() func g() -> Int { 4 } } - """) + """), ] static let triggeringExamples = [ @@ -118,7 +118,7 @@ struct ImplicitReturnRuleExamples { """), Example(""" func f() { ↓return } - """) + """), ] static let corrections = [ @@ -156,7 +156,7 @@ struct ImplicitReturnRuleExamples { \("") // Another comment } - """) + """), ] } @@ -178,7 +178,7 @@ struct ImplicitReturnRuleExamples { 0 } } - """) + """), ] static let triggeringExamples = [ @@ -198,7 +198,7 @@ struct ImplicitReturnRuleExamples { ↓return 0 } } - """) + """), ] static let corrections = [ @@ -219,7 +219,7 @@ struct ImplicitReturnRuleExamples { } } } - """) + """), ] } @@ -244,7 +244,7 @@ struct ImplicitReturnRuleExamples { return nil } } - """) + """), ] static let triggeringExamples = [ @@ -261,7 +261,7 @@ struct ImplicitReturnRuleExamples { ↓return nil } } - """) + """), ] static let corrections = [ @@ -290,7 +290,7 @@ struct ImplicitReturnRuleExamples { nil } } - """) + """), ] } @@ -303,7 +303,7 @@ struct ImplicitReturnRuleExamples { return res } } - """) + """), ] static let triggeringExamples = [ @@ -313,7 +313,7 @@ struct ImplicitReturnRuleExamples { ↓return i } } - """) + """), ] static let corrections = [ @@ -329,7 +329,7 @@ struct ImplicitReturnRuleExamples { i } } - """) + """), ] } @@ -353,7 +353,7 @@ struct ImplicitReturnRuleExamples { FunctionExamples.corrections, GetterExamples.corrections, InitializerExamples.corrections, - SubscriptExamples.corrections + SubscriptExamples.corrections, ] .reduce(into: [:]) { result, element in result.merge(element) { _, _ in diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRuleExamples.swift index 9ebc7f0221..39b9eb3b9b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRuleExamples.swift @@ -15,7 +15,7 @@ internal struct InclusiveLanguageRuleExamples { case mastercard } """), - Example("func chargeMasterCard(_ card: Card) {}") + Example("func chargeMasterCard(_ card: Card) {}"), ] static let triggeringExamples: [Example] = [ @@ -37,7 +37,7 @@ internal struct InclusiveLanguageRuleExamples { final class FooBar { func register<↓Master, ↓Slave>(one: Master, two: Slave) {} } - """) + """), ] // MARK: - Non-default config @@ -54,8 +54,8 @@ internal struct InclusiveLanguageRuleExamples { private func doThisThing() {} """, configuration: [ "override_terms": ["abc123"], - "additional_terms": ["xyz789"] - ]) + "additional_terms": ["xyz789"], + ]), ] static let triggeringExamplesWithConfig: [Example] = [ @@ -75,6 +75,6 @@ internal struct InclusiveLanguageRuleExamples { private var ↓fooBar = "abc" """, configuration: [ "additional_terms": ["FoObAr"] - ]) + ]), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/IndentationWidthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/IndentationWidthRule.swift index d79e11b85b..888c9eb01c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/IndentationWidthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/IndentationWidthRule.swift @@ -29,13 +29,13 @@ struct IndentationWidthRule: OptInRule { Example("firstLine\n secondLine"), Example("firstLine\n\tsecondLine\n\t\tthirdLine\n\n\t\tfourthLine"), Example("firstLine\n\tsecondLine\n\t\tthirdLine\n\t//test\n\t\tfourthLine"), - Example("firstLine\n secondLine\n thirdLine\nfourthLine") + Example("firstLine\n secondLine\n thirdLine\nfourthLine"), ], triggeringExamples: [ Example("↓ firstLine", testMultiByteOffsets: false, testDisableCommand: false), Example("firstLine\n secondLine"), Example("firstLine\n\tsecondLine\n\n↓\t\t\tfourthLine"), - Example("firstLine\n secondLine\n thirdLine\n↓ fourthLine") + Example("firstLine\n secondLine\n thirdLine\n↓ fourthLine"), ].skipWrappingInCommentTests() ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/LeadingWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/LeadingWhitespaceRule.swift index 59ccd8b946..329fad6178 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/LeadingWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/LeadingWhitespaceRule.swift @@ -14,7 +14,7 @@ struct LeadingWhitespaceRule: CorrectableRule, SourceKitFreeRule { ], triggeringExamples: [ Example("\n//"), - Example(" //") + Example(" //"), ].skipMultiByteOffsetTests().skipDisableCommandTests(), corrections: [ Example("\n //", testMultiByteOffsets: false): Example("//") @@ -27,9 +27,13 @@ struct LeadingWhitespaceRule: CorrectableRule, SourceKitFreeRule { return [] } - return [StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: file.path, line: 1))] + return [ + StyleViolation( + ruleDescription: Self.description, + severity: configuration.severity, + location: Location(file: file.path, line: 1) + ), + ] } func correct(file: SwiftLintFile) -> [Correction] { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift index 43f3f36408..1e575d8ff5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift @@ -120,7 +120,7 @@ struct LetVarWhitespaceRule: OptInRule { var format = false @Flag(help: "help") var useAlternativeExcluding = false - """#, excludeFromDocumentation: true) + """#, excludeFromDocumentation: true), ].map(Self.wrapIntoClass) + [ Example(""" a = 2 @@ -155,7 +155,7 @@ struct LetVarWhitespaceRule: OptInRule { return 1 #endif } - """) + """), ], triggeringExamples: [ Example(""" @@ -189,7 +189,7 @@ struct LetVarWhitespaceRule: OptInRule { let a = 0 ↓func f() {} #endif - """) + """), ].map(Self.wrapIntoClass) + [ Example(""" let a = 2 @@ -203,7 +203,7 @@ struct LetVarWhitespaceRule: OptInRule { func f() {} ↓let a = 1 #endif - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift index 245a2cb5ea..4aad4e58fe 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift @@ -48,7 +48,7 @@ struct LiteralExpressionEndIndentationRule: Rule, OptInRule { key: 0, key2: 20 ] - """) + """), ], triggeringExamples: [ Example(""" @@ -67,7 +67,7 @@ struct LiteralExpressionEndIndentationRule: Rule, OptInRule { let x = [ key: value ↓] - """) + """), ], corrections: [ Example(""" @@ -117,7 +117,7 @@ struct LiteralExpressionEndIndentationRule: Rule, OptInRule { 3, 4 ] - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift index 409e5f3760..227a0a36d5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift @@ -32,7 +32,7 @@ struct ModifierOrderRule: ASTRule, OptInRule, CorrectableRule { severity: configuration.severityConfiguration.severity, location: Location(file: file, byteOffset: offset), reason: reason - ) + ), ] } return [] @@ -85,7 +85,7 @@ struct ModifierOrderRule: ASTRule, OptInRule, CorrectableRule { file: file, byteOffset: offset ) - ) + ), ] } return corrections diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRuleExamples.swift index 2e382185f9..fc6ee5d416 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRuleExamples.swift @@ -110,7 +110,7 @@ internal struct ModifierOrderRuleExamples { class Foo { internal lazy var bar: String = "foo" } - """) + """), ] static let triggeringExamples = [ @@ -223,6 +223,6 @@ internal struct ModifierOrderRuleExamples { class Foo { lazy internal var bar: String = "foo" } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsBracketsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsBracketsRule.swift index 3575ab8e3a..35cd7feee8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsBracketsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsBracketsRule.swift @@ -99,7 +99,7 @@ struct MultilineArgumentsBracketsRule: OptInRule { SomeType( a: 1 ) {} onError: {} - """) + """), ], triggeringExamples: [ Example(""" @@ -153,7 +153,7 @@ struct MultilineArgumentsBracketsRule: OptInRule { title: "MacBook", subtitle: "M1", action: { [weak self] in print("action tapped") }↓)) - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRuleExamples.swift index d1501d08b9..da7c1a3f0e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRuleExamples.swift @@ -68,7 +68,7 @@ internal struct MultilineArgumentsRuleExamples { } completion: { _ in print("b") } - """) + """), ] static let triggeringExamples = [ @@ -89,6 +89,6 @@ internal struct MultilineArgumentsRuleExamples { 0, ↓param1: 1, param2: true, ↓param3: [3] ) - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift index a12b0e8fd1..e8bd868bda 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift @@ -60,7 +60,7 @@ struct MultilineFunctionChainsRule: ASTRule, OptInRule { Example(""" self.happeningNewsletterOn = self.updateCurrentUser .map { $0.newsletters.happening }.skipNil().skipRepeats() - """) + """), ], triggeringExamples: [ Example(""" @@ -88,7 +88,7 @@ struct MultilineFunctionChainsRule: ASTRule, OptInRule { a.b { // ““ }↓.e() - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift index 9be4eab865..ac4e58a920 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift @@ -46,7 +46,7 @@ struct MultilineLiteralBracketsRule: OptInRule { 5, 6, 7, 8, 9 ] - """) + """), ], triggeringExamples: [ Example(""" @@ -107,7 +107,7 @@ struct MultilineLiteralBracketsRule: OptInRule { $0.isValid }.sum()↓] } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift index ee19dca382..db56b81f50 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift @@ -53,7 +53,7 @@ struct MultilineParametersBracketsRule: OptInRule { func foo(a: [Int] = [ 1 ]) - """) + """), ], triggeringExamples: [ Example(""" @@ -86,7 +86,7 @@ struct MultilineParametersBracketsRule: OptInRule { func foo(↓param1: T, param2: String, param3: String ) -> T - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift index ca3ab5b784..e87e35359b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift @@ -196,7 +196,7 @@ internal struct MultilineParametersRuleExamples { param3: [String] ) { } } - """, configuration: ["allows_single_line": false]) + """, configuration: ["allows_single_line": false]), ] static let triggeringExamples: [Example] = [ @@ -335,6 +335,6 @@ internal struct MultilineParametersRuleExamples { Example("func ↓foo(param1: Int, param2: Bool) { }", configuration: ["allows_single_line": false]), Example("func ↓foo(param1: Int, param2: Bool, param3: [String]) { }", - configuration: ["allows_single_line": false]) + configuration: ["allows_single_line": false]), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift index 76d294bc7b..288c3fce40 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultipleClosuresWithTrailingClosureRule.swift @@ -20,7 +20,7 @@ struct MultipleClosuresWithTrailingClosureRule: Rule { } """), Example("foo.method { print(0) } arg2: { print(1) }"), - Example("foo.methodWithParenArgs((0, 1), arg2: (0, 1, 2)) { $0 } arg4: { $0 }") + Example("foo.methodWithParenArgs((0, 1), arg2: (0, 1, 2)) { $0 } arg4: { $0 }"), ], triggeringExamples: [ Example("foo.something(param1: { $0 }) ↓{ $0 + 1 }"), @@ -32,7 +32,7 @@ struct MultipleClosuresWithTrailingClosureRule: Rule { } """), Example("foo.multipleTrailing(arg1: { $0 }) { $0 } arg3: { $0 }"), - Example("foo.methodWithParenArgs(param1: { $0 }, param2: (0, 1), (0, 1)) { $0 }") + Example("foo.methodWithParenArgs(param1: { $0 }, param2: (0, 1), (0, 1)) { $0 }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/NoSpaceInMethodCallRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/NoSpaceInMethodCallRule.swift index 493d44257d..9c185a2aa4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/NoSpaceInMethodCallRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/NoSpaceInMethodCallRule.swift @@ -23,7 +23,7 @@ struct NoSpaceInMethodCallRule: Rule { } label: { Text("Button") } - """) + """), ], triggeringExamples: [ Example("foo↓ ()"), @@ -32,7 +32,7 @@ struct NoSpaceInMethodCallRule: Rule { Example("object.foo↓ (value: 1)"), Example("object.foo↓ () {}"), Example("object.foo↓ ()"), - Example("object.foo↓ (value: 1) { x in print(x) }") + Example("object.foo↓ (value: 1) { x in print(x) }"), ], corrections: [ Example("foo↓ ()"): Example("foo()"), @@ -40,7 +40,7 @@ struct NoSpaceInMethodCallRule: Rule { Example("object.foo↓ (1)"): Example("object.foo(1)"), Example("object.foo↓ (value: 1)"): Example("object.foo(value: 1)"), Example("object.foo↓ () {}"): Example("object.foo() {}"), - Example("object.foo↓ ()"): Example("object.foo()") + Example("object.foo↓ ()"): Example("object.foo()"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift index bec336d152..0bdfa09821 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift @@ -50,7 +50,7 @@ struct NonOverridableClassDeclarationRule: SwiftSyntaxCorrectableRule, OptInRule class func f() {} } } - """) + """), ], triggeringExamples: [ Example(""" @@ -72,7 +72,7 @@ struct NonOverridableClassDeclarationRule: SwiftSyntaxCorrectableRule, OptInRule private ↓class var b: Bool { true } private ↓class func f() {} } - """) + """), ], corrections: [ Example(""" @@ -92,7 +92,7 @@ struct NonOverridableClassDeclarationRule: SwiftSyntaxCorrectableRule, OptInRule final class C { static var b: Bool { true } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift index d17fbe0614..472c1c491f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift @@ -22,7 +22,7 @@ internal struct NumberSeparatorRuleExamples { """, excludeFromDocumentation: true), Example(""" let color = #colorLiteral(red: 0.354_398_250_6, green: 0.318_749_547, blue: 0.636_701_524_3, alpha: 1) - """, configuration: ["minimum_fraction_length": 3], excludeFromDocumentation: true) + """, configuration: ["minimum_fraction_length": 3], excludeFromDocumentation: true), ] } }() @@ -43,7 +43,7 @@ internal struct NumberSeparatorRuleExamples { Example("let foo = \(sign)1.0001", configuration: ["minimum_fraction_length": 3]), Example("let foo = \(sign)1_000_000.000000_1", configuration: ["minimum_fraction_length": 3]), Example("let foo = \(sign)1000000.000000_1"), - Example("let foo = \(sign)6.2832e-6", configuration: ["minimum_fraction_length": 3]) + Example("let foo = \(sign)6.2832e-6", configuration: ["minimum_fraction_length": 3]), ] } } @@ -54,7 +54,10 @@ internal struct NumberSeparatorRuleExamples { [ Example("let foo: Double = \(sign)100000)"), Example("let foo: Double = \(sign)10.000000_1)", configuration: ["minimum_fraction_length": 3]), - Example("let foo: Double = \(sign)123456 / ↓447.214214)", configuration: ["minimum_fraction_length": 3]) + Example( + "let foo: Double = \(sign)123456 / ↓447.214214)", + configuration: ["minimum_fraction_length": 3] + ), ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index a855aac2cb..37d05fb1b2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -57,7 +57,7 @@ struct OpeningBraceRuleExamples { if c /* comment */ { return } - """) + """), ] static let triggeringExamples = [ @@ -216,7 +216,7 @@ struct OpeningBraceRuleExamples { Example(""" if c ↓{} else /* comment */ ↓{} - """) + """), ] static let corrections = [ @@ -545,6 +545,6 @@ struct OpeningBraceRuleExamples { if c /* comment */ { return } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorFunctionWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorFunctionWhitespaceRule.swift index 9d6df406a6..e2d548888a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorFunctionWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorFunctionWhitespaceRule.swift @@ -12,7 +12,7 @@ struct OperatorFunctionWhitespaceRule: Rule { nonTriggeringExamples: [ Example("func <| (lhs: Int, rhs: Int) -> Int {}"), Example("func <|<
(lhs: A, rhs: A) -> A {}"), - Example("func abc(lhs: Int, rhs: Int) -> Int {}") + Example("func abc(lhs: Int, rhs: Int) -> Int {}"), ], triggeringExamples: [ Example("↓func <|(lhs: Int, rhs: Int) -> Int {}"), // no spaces after @@ -20,7 +20,7 @@ struct OperatorFunctionWhitespaceRule: Rule { Example("↓func <| (lhs: Int, rhs: Int) -> Int {}"), // 2 spaces after Example("↓func <|< (lhs: A, rhs: A) -> A {}"), // 2 spaces after Example("↓func <| (lhs: Int, rhs: Int) -> Int {}"), // 2 spaces before - Example("↓func <|< (lhs: A, rhs: A) -> A {}") // 2 spaces before + Example("↓func <|< (lhs: A, rhs: A) -> A {}"), // 2 spaces before ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift index 432748d683..8296c2f86a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift @@ -90,7 +90,7 @@ internal enum OperatorUsageWhitespaceRuleExamples { """, configuration: ["allowed_no_space_operators": ["<--<"]], excludeFromDocumentation: true - ) + ), ] static let triggeringExamples = [ @@ -137,7 +137,7 @@ internal enum OperatorUsageWhitespaceRuleExamples { """), Example("tabbedViewController.title↓ = nil"), Example("let foo = bar ? 0↓:1"), - Example("let foo = bar↓ ? 0 : 1") + Example("let foo = bar↓ ? 0 : 1"), ] static let corrections = [ @@ -158,6 +158,6 @@ internal enum OperatorUsageWhitespaceRuleExamples { Example("let foo↓ = \"1\""): Example("let foo = \"1\""), Example("let foo↓ = \"1\""): Example("let foo = \"1\""), Example("let foo = bar ? 0↓:1"): Example("let foo = bar ? 0 : 1"), - Example("let foo = bar↓ ? 0 : 1"): Example("let foo = bar ? 0 : 1") + Example("let foo = bar↓ ? 0 : 1"): Example("let foo = bar ? 0 : 1"), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OptionalEnumCaseMatchingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OptionalEnumCaseMatchingRule.swift index 937c495a6a..5d475ef56f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OptionalEnumCaseMatchingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OptionalEnumCaseMatchingRule.swift @@ -46,7 +46,7 @@ struct OptionalEnumCaseMatchingRule: OptInRule { case .none: break } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -83,7 +83,7 @@ struct OptionalEnumCaseMatchingRule: OptInRule { case (_, .bar↓?): break default: break } - """) + """), ], corrections: [ Example(""" @@ -150,7 +150,7 @@ struct OptionalEnumCaseMatchingRule: OptInRule { case (_, .bar): break default: break } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRuleExamples.swift index bb4602393c..e16c6f346b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRuleExamples.swift @@ -100,7 +100,7 @@ enum PreferSelfInStaticReferencesRuleExamples { let s2 = S1() } } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] static let triggeringExamples = [ @@ -222,7 +222,7 @@ enum PreferSelfInStaticReferencesRuleExamples { child = (input as! T).child } } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ] static let corrections = [ @@ -264,6 +264,6 @@ enum PreferSelfInStaticReferencesRuleExamples { static func f(_ l: Int = Self.i) -> Int { l*Self.j } func g() { Self.i + Self.f() + k } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift index eb5be49558..7ebaa37f0a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift @@ -38,7 +38,7 @@ struct PreferSelfTypeOverTypeOfSelfRule: OptInRule { print(type(of: self)) } } - """) + """), ], triggeringExamples: [ Example(""" @@ -61,7 +61,7 @@ struct PreferSelfTypeOverTypeOfSelfRule: OptInRule { print(↓Swift.type(of: self).baz) } } - """) + """), ], corrections: [ Example(""" @@ -102,7 +102,7 @@ struct PreferSelfTypeOverTypeOfSelfRule: OptInRule { print(Self.baz) } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift index 7e4050a6f3..4dda360e68 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift @@ -60,7 +60,7 @@ struct PrefixedTopLevelConstantRule: OptInRule { print("\(number) is a small number") } } - """#) + """#), ], triggeringExamples: [ Example("private let ↓Foo = 20.0"), @@ -76,7 +76,7 @@ struct PrefixedTopLevelConstantRule: OptInRule { let ↓foo = { return a + b }() - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ProtocolPropertyAccessorsOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ProtocolPropertyAccessorsOrderRule.swift index dbcbb289de..22b161f535 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ProtocolPropertyAccessorsOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ProtocolPropertyAccessorsOrderRule.swift @@ -12,14 +12,14 @@ struct ProtocolPropertyAccessorsOrderRule: Rule { nonTriggeringExamples: [ Example("protocol Foo {\n var bar: String { get set }\n }"), Example("protocol Foo {\n var bar: String { get }\n }"), - Example("protocol Foo {\n var bar: String { set }\n }") + Example("protocol Foo {\n var bar: String { set }\n }"), ], triggeringExamples: [ Example("protocol Foo {\n var bar: String { ↓set get }\n }") ], corrections: [ Example("protocol Foo {\n var bar: String { ↓set get }\n }"): - Example("protocol Foo {\n var bar: String { get set }\n }") + Example("protocol Foo {\n var bar: String { get set }\n }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantDiscardableLetRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantDiscardableLetRule.swift index 149a67976a..76904825a0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantDiscardableLetRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantDiscardableLetRule.swift @@ -15,15 +15,15 @@ struct RedundantDiscardableLetRule: Rule { Example("guard let _ = foo() else { return }"), Example("let _: ExplicitType = foo()"), Example("while let _ = SplashStyle(rawValue: maxValue) { maxValue += 1 }"), - Example("async let _ = await foo()") + Example("async let _ = await foo()"), ], triggeringExamples: [ Example("↓let _ = foo()"), - Example("if _ = foo() { ↓let _ = bar() }") + Example("if _ = foo() { ↓let _ = bar() }"), ], corrections: [ Example("↓let _ = foo()"): Example("_ = foo()"), - Example("if _ = foo() { ↓let _ = bar() }"): Example("if _ = foo() { _ = bar() }") + Example("if _ = foo() { ↓let _ = bar() }"): Example("if _ = foo() { _ = bar() }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift index 21ab61ea6d..71b14b5384 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift @@ -79,7 +79,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """) + """), ] static let triggeringExamples = [ @@ -198,7 +198,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """) + """), ] static let corrections = [ @@ -224,6 +224,6 @@ struct RedundantSelfInClosureRuleExamples { } } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift index 31f55ce9bd..ac292aa644 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift @@ -23,7 +23,7 @@ struct ReturnArrowWhitespaceRule: SwiftSyntaxCorrectableRule { return 1 } """), - Example("typealias SuccessBlock = ((Data) -> Void)") + Example("typealias SuccessBlock = ((Data) -> Void)"), ], triggeringExamples: [ Example("func abc()↓->Int {}"), @@ -39,7 +39,7 @@ struct ReturnArrowWhitespaceRule: SwiftSyntaxCorrectableRule { Example("func abc()\n ↓-> Int {}"), Example("func abc()\n ↓-> Int {}"), Example("func abc()↓ ->\n Int {}"), - Example("func abc()↓ ->\nInt {}") + Example("func abc()↓ ->\nInt {}"), ], corrections: [ Example("func abc()↓->Int {}"): Example("func abc() -> Int {}"), @@ -49,7 +49,7 @@ struct ReturnArrowWhitespaceRule: SwiftSyntaxCorrectableRule { Example("func abc()\n ↓-> Int {}"): Example("func abc()\n -> Int {}"), Example("func abc()\n ↓-> Int {}"): Example("func abc()\n -> Int {}"), Example("func abc()↓ ->\n Int {}"): Example("func abc() ->\n Int {}"), - Example("func abc()↓ ->\nInt {}"): Example("func abc() ->\nInt {}") + Example("func abc()↓ ->\nInt {}"): Example("func abc() ->\nInt {}"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SelfBindingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SelfBindingRule.swift index 2c666742d8..25e2672917 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SelfBindingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SelfBindingRule.swift @@ -17,7 +17,7 @@ struct SelfBindingRule: OptInRule { Example("if let this = this { return }"), Example("guard let this = this else { return }"), Example("if let this = self { return }", configuration: ["bind_identifier": "this"]), - Example("guard let this = self else { return }", configuration: ["bind_identifier": "this"]) + Example("guard let this = self else { return }", configuration: ["bind_identifier": "this"]), ], triggeringExamples: [ Example("if let ↓`self` = self { return }"), @@ -27,7 +27,7 @@ struct SelfBindingRule: OptInRule { Example("if let ↓self = self { return }", configuration: ["bind_identifier": "this"]), Example("guard let ↓self = self else { return }", configuration: ["bind_identifier": "this"]), Example("if let ↓self { return }", configuration: ["bind_identifier": "this"]), - Example("guard let ↓self else { return }", configuration: ["bind_identifier": "this"]) + Example("guard let ↓self else { return }", configuration: ["bind_identifier": "this"]), ], corrections: [ Example("if let ↓`self` = self { return }"): @@ -43,7 +43,7 @@ struct SelfBindingRule: OptInRule { Example("if let ↓self { return }", configuration: ["bind_identifier": "this"]): Example("if let this = self { return }", configuration: ["bind_identifier": "this"]), Example("guard let ↓self else { return }", configuration: ["bind_identifier": "this"]): - Example("guard let this = self else { return }", configuration: ["bind_identifier": "this"]) + Example("guard let this = self else { return }", configuration: ["bind_identifier": "this"]), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift index 1bb1df43ac..144de8f757 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift @@ -32,7 +32,7 @@ struct ShorthandArgumentRule: OptInRule { f { $0 + g { $0 } - """, configuration: ["allow_until_line_after_opening_brace": 1]) + """, configuration: ["allow_until_line_after_opening_brace": 1]), ], triggeringExamples: [ Example(""" @@ -64,7 +64,7 @@ struct ShorthandArgumentRule: OptInRule { + $1 + ↓$2.c } - """, configuration: ["always_disallow_member_access": true, "allow_until_line_after_opening_brace": 3]) + """, configuration: ["always_disallow_member_access": true, "allow_until_line_after_opening_brace": 3]), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandOperatorRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandOperatorRule.swift index ead260cfb9..7912bf25a5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandOperatorRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandOperatorRule.swift @@ -25,7 +25,7 @@ struct ShorthandOperatorRule: Rule { """), Example("var helloWorld = \"world!\"\n helloWorld = \"Hello, \" + helloWorld"), Example("angle = someCheck ? angle : -angle"), - Example("seconds = seconds * 60 + value") + Example("seconds = seconds * 60 + value"), ], triggeringExamples: [ Example("↓foo = foo * 1"), @@ -34,7 +34,7 @@ struct ShorthandOperatorRule: Rule { Example("↓foo.aProperty = foo.aProperty - 1"), Example("↓self.aProperty = self.aProperty * 1"), Example("↓n = n + i / outputLength"), - Example("↓n = n - i / outputLength") + Example("↓n = n - i / outputLength"), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift index 906b91e92c..1e29c0dc8d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift @@ -11,7 +11,7 @@ struct SingleTestClassRule: SourceKitFreeRule, OptInRule { nonTriggeringExamples: [ Example("class FooTests { }"), Example("class FooTests: QuickSpec { }"), - Example("class FooTests: XCTestCase { }") + Example("class FooTests: XCTestCase { }"), ], triggeringExamples: [ Example(""" @@ -45,7 +45,7 @@ struct SingleTestClassRule: SourceKitFreeRule, OptInRule { final ↓class FooTests: QuickSpec { } ↓class BarTests: XCTestCase { } class TotoTests { } - """) + """), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SortedEnumCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SortedEnumCasesRule.swift index a78b926c46..31c8b3b087 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SortedEnumCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SortedEnumCasesRule.swift @@ -60,7 +60,7 @@ struct SortedEnumCasesRule: OptInRule { case a case c, f, d } - """) + """), ], triggeringExamples: [ Example(""" @@ -104,7 +104,7 @@ struct SortedEnumCasesRule: OptInRule { case a(foo: Foo) case ↓c, ↓b(String) } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRuleExamples.swift index d7940bc44c..d245b15af8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRuleExamples.swift @@ -58,7 +58,7 @@ internal struct SortedImportsRuleExamples { Example(""" @_exported @testable import BBB import AAA - """, configuration: groupByAttributesConfiguration, excludeFromDocumentation: true) + """, configuration: groupByAttributesConfiguration, excludeFromDocumentation: true), ] static let triggeringExamples = [ @@ -114,7 +114,7 @@ internal struct SortedImportsRuleExamples { Example(""" import AAA @_exported @testable import ↓BBB - """, configuration: groupByAttributesConfiguration, excludeFromDocumentation: true) + """, configuration: groupByAttributesConfiguration, excludeFromDocumentation: true), ] static let corrections = [ @@ -228,6 +228,6 @@ internal struct SortedImportsRuleExamples { Example(""" @_exported @testable import BBB import AAA - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift index 960e81365a..8db9e908b2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift @@ -15,18 +15,18 @@ struct StatementPositionRule: CorrectableRule { Example("} catch {"), Example("\"}else{\""), Example("struct A { let catchphrase: Int }\nlet a = A(\n catchphrase: 0\n)"), - Example("struct A { let `catch`: Int }\nlet a = A(\n `catch`: 0\n)") + Example("struct A { let `catch`: Int }\nlet a = A(\n `catch`: 0\n)"), ], triggeringExamples: [ Example("↓}else if {"), Example("↓} else {"), Example("↓}\ncatch {"), - Example("↓}\n\t catch {") + Example("↓}\n\t catch {"), ], corrections: [ Example("↓}\n else {"): Example("} else {"), Example("↓}\n else if {"): Example("} else if {"), - Example("↓}\n catch {"): Example("} catch {") + Example("↓}\n catch {"): Example("} catch {"), ] ) @@ -44,19 +44,19 @@ struct StatementPositionRule: CorrectableRule { Example("\n\n }\n catch {"), Example("\"}\nelse{\""), Example("struct A { let catchphrase: Int }\nlet a = A(\n catchphrase: 0\n)"), - Example("struct A { let `catch`: Int }\nlet a = A(\n `catch`: 0\n)") + Example("struct A { let `catch`: Int }\nlet a = A(\n `catch`: 0\n)"), ], triggeringExamples: [ Example("↓ }else if {"), Example("↓}\n else {"), Example("↓ }\ncatch {"), - Example("↓}\n\t catch {") + Example("↓}\n\t catch {"), ], corrections: [ Example(" }else if {"): Example(" }\n else if {"), Example("}\n else {"): Example("}\nelse {"), Example(" }\ncatch {"): Example(" }\n catch {"), - Example("}\n\t catch {"): Example("}\ncatch {") + Example("}\n\t catch {"): Example("}\ncatch {"), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift index cd257ae235..21d8fbe4ab 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift @@ -68,7 +68,7 @@ struct SuperfluousElseRule: OptInRule { break } } - """) + """), ], triggeringExamples: [ Example(""" @@ -119,7 +119,7 @@ struct SuperfluousElseRule: OptInRule { throw error } } - """) + """), ], corrections: [ Example(""" @@ -240,7 +240,7 @@ struct SuperfluousElseRule: OptInRule { throw error } } - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift index 1e509776a3..eec2198dca 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift @@ -34,7 +34,7 @@ struct SwitchCaseAlignmentRule: Rule { } } } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: Examples(indentedCases: false).triggeringExamples ) @@ -140,7 +140,7 @@ extension SwitchCaseAlignmentRule { \(violationMarker)case 1: 1 \(violationMarker)default: 2 } - """) + """), ] } @@ -193,7 +193,7 @@ extension SwitchCaseAlignmentRule { \(violationMarker)default: 2 } } - """) + """), ] } @@ -224,7 +224,7 @@ extension SwitchCaseAlignmentRule { \(indentation)case 1: 1 \(indentation)\(indentedCasesOption ? "" : violationMarker)default: 2 } - """) + """), ] } @@ -236,7 +236,7 @@ extension SwitchCaseAlignmentRule { Example( "let a = switch i { case .x: 1 default: 0 }", configuration: ["ignore_one_liners": true] - ) + ), ] private var invalidOneLiners: [Example] { @@ -265,7 +265,7 @@ extension SwitchCaseAlignmentRule { Example(""" let a = switch i { \(violationMarker)case .x: 1 \(violationMarker)default: 0 } - """, configuration: ["ignore_one_liners": true]) + """, configuration: ["ignore_one_liners": true]), ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift index 3d8254cc1e..b75d08d40a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift @@ -46,7 +46,7 @@ struct SwitchCaseOnNewlineRule: OptInRule { let loadedToken = try tokenManager.decodeToken(from: response) return loadedToken } catch { throw error } - """) + """), ], triggeringExamples: [ wrapInSwitch("↓case 1: return true"), @@ -57,7 +57,7 @@ struct SwitchCaseOnNewlineRule: OptInRule { wrapInSwitch("↓case let .myCase(value) where value > 10: return false"), wrapInSwitch("↓case #selector(aFunction(_:)): return false"), wrapInSwitch("↓case let .myCase(value)\n where value > 10: return false"), - wrapInSwitch("↓case .first,\n .second: return false") + wrapInSwitch("↓case .first,\n .second: return false"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift index a91c8165aa..b124dae2ce 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift @@ -35,7 +35,7 @@ struct TrailingClosureRule: OptInRule { for i in h({ [1,2,3] }) { print(i) } - """) + """), ], triggeringExamples: [ Example("foo.map(↓{ $0 + 1 })"), @@ -47,7 +47,7 @@ struct TrailingClosureRule: OptInRule { for n in list { n.forEach(↓{ print($0) }) } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], corrections: [ Example("foo.map(↓{ $0 + 1 })"): @@ -100,7 +100,7 @@ struct TrailingClosureRule: OptInRule { f(a: 2, /* comment1 */ c /* comment2 */ : /* comment3 */ { 3 } /* comment4 */) """): Example(""" f(a: 2) /* comment1 */ /* comment2 */ /* comment3 */ { 3 } /* comment4 */ - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingCommaRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingCommaRule.swift index 6b99d41410..0383ff8051 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingCommaRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingCommaRule.swift @@ -14,7 +14,7 @@ struct TrailingCommaRule: Rule { Example("let example = [ 1,\n2↓,\n // 3,\n]"), Example("let foo = [\"אבג\", \"αβγ\", \"🇺🇸\"↓,]"), Example("class C {\n #if true\n func f() {\n let foo = [1, 2, 3↓,]\n }\n #endif\n}"), - Example("foo([1: \"\\(error)\"↓,])") + Example("foo([1: \"\\(error)\"↓,])"), ] private static let corrections: [Example: Example] = { @@ -42,7 +42,7 @@ struct TrailingCommaRule: Rule { Example("let foo = [Void]()"), Example("let example = [ 1,\n 2\n // 3,\n]"), Example("foo([1: \"\\(error)\"])"), - Example("let foo = [Int]()") + Example("let foo = [Int]()"), ], triggeringExamples: Self.triggeringExamples, corrections: Self.corrections diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift index 174a02282a..d1b399021a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift @@ -31,12 +31,12 @@ struct TrailingNewlineRule: CorrectableRule, SourceKitFreeRule { ], triggeringExamples: [ Example("let a = 0"), - Example("let a = 0\n\n") + Example("let a = 0\n\n"), ].skipWrappingInCommentTests().skipWrappingInStringTests(), corrections: [ Example("let a = 0"): Example("let a = 0\n"), Example("let b = 0\n\n"): Example("let b = 0\n"), - Example("let c = 0\n\n\n\n"): Example("let c = 0\n") + Example("let c = 0\n\n\n\n"): Example("let c = 0\n"), ] ) @@ -44,9 +44,13 @@ struct TrailingNewlineRule: CorrectableRule, SourceKitFreeRule { if file.contents.trailingNewlineCount() == 1 { return [] } - return [StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: file.path, line: max(file.lines.count, 1)))] + return [ + StyleViolation( + ruleDescription: Self.description, + severity: configuration.severity, + location: Location(file: file.path, line: max(file.lines.count, 1)) + ), + ] } func correct(file: SwiftLintFile) -> [Correction] { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingWhitespaceRule.swift index 8e52a821b4..653d87fb48 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingWhitespaceRule.swift @@ -11,14 +11,14 @@ struct TrailingWhitespaceRule: CorrectableRule { kind: .style, nonTriggeringExamples: [ Example("let name: String\n"), Example("//\n"), Example("// \n"), - Example("let name: String //\n"), Example("let name: String // \n") + Example("let name: String //\n"), Example("let name: String // \n"), ], triggeringExamples: [ Example("let name: String \n"), Example("/* */ let name: String \n") ], corrections: [ Example("let name: String \n"): Example("let name: String\n"), - Example("/* */ let name: String \n"): Example("/* */ let name: String\n") + Example("/* */ let name: String \n"): Example("/* */ let name: String\n"), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift index 62cf3fe0e3..2bb9198769 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift @@ -118,7 +118,7 @@ struct TypeContentsOrderRule: OptInRule { "viewDidAppear(", "viewWillDisappear(", "viewDidDisappear(", - "willMove(" + "willMove(", ] if typeContentStructure.name!.starts(with: "init(") { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift index 1ea70c3362..836e38a9be 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift @@ -119,7 +119,7 @@ internal struct TypeContentsOrderRuleExamples { deinit { log.debug("deinit") } - """ + """, ] static let nonTriggeringExamples = [ @@ -127,7 +127,7 @@ internal struct TypeContentsOrderRuleExamples { class TestViewController: UIViewController { \(Self.defaultOrderParts.joined(separator: "\n\n")), } - """) + """), ] static let triggeringExamples = [ @@ -254,6 +254,6 @@ internal struct TypeContentsOrderRuleExamples { // MARK: Other Methods func goToNextVc() { /* TODO */ } } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift index bf690e1d67..91c362bee6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/UnneededParenthesesInClosureArgumentRule.swift @@ -23,7 +23,7 @@ struct UnneededParenthesesInClosureArgumentRule: OptInRule { registerFilter(name) { any, args throws -> Any? in doSomething(any, args) } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example("call(arg: { ↓(bar) in })"), @@ -59,7 +59,7 @@ struct UnneededParenthesesInClosureArgumentRule: OptInRule { registerFilter(name) { ↓(any, args) throws -> Any? in doSomething(any, args) } - """, excludeFromDocumentation: true) + """, excludeFromDocumentation: true), ], corrections: [ Example("call(arg: { ↓(bar) in })"): Example("call(arg: { bar in })"), @@ -69,7 +69,7 @@ struct UnneededParenthesesInClosureArgumentRule: OptInRule { Example("let foo = { bar -> Bool in return true }"), Example("method { ↓(foo, bar) in }"): Example("method { foo, bar in }"), Example("foo.map { ($0, $0) }.forEach { ↓(x, y) in }"): Example("foo.map { ($0, $0) }.forEach { x, y in }"), - Example("foo.bar { [weak self] ↓(x, y) in }"): Example("foo.bar { [weak self] x, y in }") + Example("foo.bar { [weak self] ↓(x, y) in }"): Example("foo.bar { [weak self] x, y in }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift index 39018eba01..a394a3d2f4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift @@ -16,7 +16,7 @@ struct UnusedOptionalBindingRule: Rule { Example("if foo() { let _ = bar() }"), Example("if foo() { _ = bar() }"), Example("if case .some(_) = self {}"), - Example("if let point = state.find({ _ in true }) {}") + Example("if let point = state.find({ _ in true }) {}"), ], triggeringExamples: [ Example("if let ↓_ = Foo.optionalValue {}"), @@ -26,7 +26,7 @@ struct UnusedOptionalBindingRule: Rule { Example("if let (first, _) = getOptionalTuple(), let ↓_ = Foo.optionalValue {}"), Example("if let (_, second) = getOptionalTuple(), let ↓_ = Foo.optionalValue {}"), Example("if let ↓(_, _, _) = getOptionalTuple(), let bar = Foo.optionalValue {}"), - Example("func foo() { if let ↓_ = bar {} }") + Example("func foo() { if let ↓_ = bar {} }"), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentOnCallRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentOnCallRule.swift index 6eb28fab13..a7b9bedc38 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentOnCallRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentOnCallRule.swift @@ -82,7 +82,7 @@ struct VerticalParameterAlignmentOnCallRule: OptInRule { } completion: { _ in // completion } - """) + """), ], triggeringExamples: [ Example(""" @@ -119,7 +119,7 @@ struct VerticalParameterAlignmentOnCallRule: OptInRule { Example(""" myFunc(foo: 0, bar: baz == 0, ↓baz: true) - """) + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentRuleExamples.swift index 743390ff3d..1bde7d086f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalParameterAlignmentRuleExamples.swift @@ -59,7 +59,7 @@ internal struct VerticalParameterAlignmentRuleExamples { init(foo: Int, bar: String) } - """) + """), ] static let triggeringExamples: [Example] = [ @@ -85,6 +85,6 @@ internal struct VerticalParameterAlignmentRuleExamples { init(data: Data, ↓@ViewBuilder content: @escaping (Data.Element.IdentifiedValue) -> Content) {} } - """) + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift index 55f28a2608..ba7cf549d1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift @@ -52,8 +52,8 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { " \n", "default: \n", " print(\"not one\") \n", - "} " - ].joined()) + "} ", + ].joined()), ] private static let violatingToValidExamples: [Example: Example] = [ @@ -124,7 +124,7 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { print("multiple ...") print("... lines") } - """) + """), ] private let pattern = "([^\\n{][ \\t]*\\n)([ \\t]*(?:case[^\\n]+|default):[ \\t]*\\n)" diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRuleExamples.swift index c5488efb37..e482f2a0af 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRuleExamples.swift @@ -28,7 +28,7 @@ internal struct VerticalWhitespaceClosingBracesRuleExamples { // do something // do something } - """, configuration: beforeTrivialLinesConfiguration, excludeFromDocumentation: true) + """, configuration: beforeTrivialLinesConfiguration, excludeFromDocumentation: true), ] static let violatingToValidExamples = [ @@ -142,6 +142,6 @@ internal struct VerticalWhitespaceClosingBracesRuleExamples { for i in 1...5 { mul *= i } return mul }]) - """, configuration: beforeTrivialLinesConfiguration) + """, configuration: beforeTrivialLinesConfiguration), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift index 1df1c9ddd4..339c7998eb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift @@ -22,7 +22,7 @@ struct VerticalWhitespaceOpeningBracesRule: Rule { } */ - """) + """), ] private static let violatingToValidExamples: [Example: Example] = [ @@ -134,7 +134,7 @@ struct VerticalWhitespaceOpeningBracesRule: Rule { self.dismiss(animated: false, completion: { }) } - """) + """), ] private let pattern = "([{(\\[][ \\t]*(?:[^\\n{]+ in[ \\t]*$)?)((?:\\n[ \\t]*)+)(\\n)" diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift index 70751ab2a9..ea9fcfa699 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift @@ -15,17 +15,17 @@ struct VerticalWhitespaceRule: CorrectableRule { Example("let abc = 0\n"), Example("let abc = 0\n\n"), Example("/* bcs \n\n\n\n*/"), - Example("// bca \n\n") + Example("// bca \n\n"), ], triggeringExamples: [ Example("let aaaa = 0\n\n\n"), Example("struct AAAA {}\n\n\n\n"), - Example("class BBBB {}\n\n\n") + Example("class BBBB {}\n\n\n"), ], corrections: [ Example("let b = 0\n\n\nclass AAA {}\n"): Example("let b = 0\n\nclass AAA {}\n"), Example("let c = 0\n\n\nlet num = 1\n"): Example("let c = 0\n\nlet num = 1\n"), - Example("// bca \n\n\n"): Example("// bca \n\n") + Example("// bca \n\n\n"): Example("// bca \n\n"), ] // End of line autocorrections are handled by Trailing Newline Rule. ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VoidReturnRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VoidReturnRule.swift index 71ae16ec54..8fcb01086d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VoidReturnRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VoidReturnRule.swift @@ -23,7 +23,7 @@ struct VoidReturnRule: Rule { Example("let foo: () -> () async -> Void"), Example("func foo() -> () async throws -> Void {}"), Example("func foo() async throws -> () async -> Void { return {} }"), - Example("func foo() -> () async -> Int { 1 }") + Example("func foo() -> () async -> Int { 1 }"), ], triggeringExamples: [ Example("let abc: () -> ↓() = {}"), @@ -34,7 +34,7 @@ struct VoidReturnRule: Rule { Example("func foo(completion: () -> ↓(Void))"), Example("let foo: (ConfigurationTests) -> () throws -> ↓()"), Example("func foo() async -> ↓()"), - Example("func foo() async throws -> ↓()") + Example("func foo() async throws -> ↓()"), ], corrections: [ Example("let abc: () -> ↓() = {}"): Example("let abc: () -> Void = {}"), @@ -45,7 +45,7 @@ struct VoidReturnRule: Rule { Example("func foo(completion: () -> ↓(Void))"): Example("func foo(completion: () -> Void)"), Example("let foo: (ConfigurationTests) -> () throws -> ↓()"): Example("let foo: (ConfigurationTests) -> () throws -> Void"), - Example("func foo() async throws -> ↓()"): Example("func foo() async throws -> Void") + Example("func foo() async throws -> ↓()"): Example("func foo() async throws -> Void"), ] ) } diff --git a/Source/SwiftLintCore/Extensions/Configuration+Cache.swift b/Source/SwiftLintCore/Extensions/Configuration+Cache.swift index 6a2f616578..56debce0ce 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Cache.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Cache.swift @@ -84,7 +84,7 @@ extension Configuration { let versionedDirectory = [ "SwiftLint", Version.current.value, - ExecutableInfo.buildID + ExecutableInfo.buildID, ].compactMap({ $0 }).joined(separator: "/") let folder = baseURL.appendingPathComponent(versionedDirectory) diff --git a/Source/SwiftLintCore/Extensions/Request+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Request+SwiftLint.swift index 5638f9dea4..34acd32dc4 100644 --- a/Source/SwiftLintCore/Extensions/Request+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Request+SwiftLint.swift @@ -19,7 +19,7 @@ public extension Request { "key.offset": Int64(offset.value), "key.compilerargs": arguments, "key.cancel_on_subsequent_request": 0, - "key.retrieve_symbol_graph": 0 + "key.retrieve_symbol_graph": 0, ]) } } diff --git a/Source/SwiftLintCore/Extensions/String+XML.swift b/Source/SwiftLintCore/Extensions/String+XML.swift index 280e1b00c6..bdb486c337 100644 --- a/Source/SwiftLintCore/Extensions/String+XML.swift +++ b/Source/SwiftLintCore/Extensions/String+XML.swift @@ -6,7 +6,7 @@ extension String { ("\"", """), ("'", "'"), (">", ">"), - ("<", "<") + ("<", "<"), ] var newString = self for (key, value) in htmlEscapes { diff --git a/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift b/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift index ace97f9a29..94a0a3c8b8 100644 --- a/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift @@ -6,7 +6,7 @@ public extension SwiftDeclarationAttributeKind { .objc, .objcName, .objcMembers, - .objcNonLazyRealization + .objcNonLazyRealization, ] } @@ -27,7 +27,7 @@ public extension SwiftDeclarationAttributeKind { public init?(rawAttribute: String) { let allModifierGroups: Set = [ .acl, .setterACL, .mutators, .override, .owned, .atPrefixed, .dynamic, .final, .typeMethods, - .required, .convenience, .lazy + .required, .convenience, .lazy, ] let modifierGroup = allModifierGroups.first { $0.swiftDeclarationAttributeKinds.contains(where: { $0.rawValue == rawAttribute }) @@ -48,7 +48,7 @@ public extension SwiftDeclarationAttributeKind { .fileprivate, .internal, .public, - .open + .open, ] case .setterACL: return [ @@ -56,12 +56,12 @@ public extension SwiftDeclarationAttributeKind { .setterFilePrivate, .setterInternal, .setterPublic, - .setterOpen + .setterOpen, ] case .mutators: return [ .mutating, - .nonmutating + .nonmutating, ] case .override: return [.override] @@ -89,7 +89,7 @@ public extension SwiftDeclarationAttributeKind { .ibdesignable, .ibinspectable, .nsManaged, - .nsCopying + .nsCopying, ] } } diff --git a/Source/SwiftLintCore/Extensions/SwiftDeclarationKind+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftDeclarationKind+SwiftLint.swift index 8bf1ae85ce..17cd5f2b51 100644 --- a/Source/SwiftLintCore/Extensions/SwiftDeclarationKind+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftDeclarationKind+SwiftLint.swift @@ -7,7 +7,7 @@ public extension SwiftDeclarationKind { .varInstance, .varLocal, .varParameter, - .varStatic + .varStatic, ] static let functionKinds: Set = [ @@ -24,7 +24,7 @@ public extension SwiftDeclarationKind { .functionMethodInstance, .functionMethodStatic, .functionOperator, - .functionSubscript + .functionSubscript, ] static let typeKinds: Set = [ @@ -32,7 +32,7 @@ public extension SwiftDeclarationKind { .struct, .typealias, .associatedtype, - .enum + .enum, ] static let extensionKinds: Set = [ @@ -40,6 +40,6 @@ public extension SwiftDeclarationKind { .extensionClass, .extensionEnum, .extensionProtocol, - .extensionStruct + .extensionStruct, ] } diff --git a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift index 677faf7c0b..bd3c613739 100644 --- a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift @@ -173,7 +173,7 @@ public extension EnumDeclSyntax { "Int", "Int8", "Int16", "Int32", "Int64", "UInt", "UInt8", "UInt16", "UInt32", "UInt64", "Double", "Float", "Float80", "Decimal", "NSNumber", - "NSDecimalNumber", "NSInteger", "String", "CGFloat" + "NSDecimalNumber", "NSInteger", "String", "CGFloat", ] return inheritedTypeCollection.contains { element in diff --git a/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift index 75261f2d28..9d35954e81 100644 --- a/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift @@ -10,14 +10,18 @@ public extension SyntaxKind { static let commentAndStringKinds: Set = commentKinds.union([.string]) - static let commentKinds: Set = [.comment, .commentMark, .commentURL, - .docComment, .docCommentField] + static let commentKinds: Set = [ + .comment, .commentMark, .commentURL, + .docComment, .docCommentField, + ] - static let allKinds: Set = [.argument, .attributeBuiltin, .attributeID, .buildconfigID, - .buildconfigKeyword, .comment, .commentMark, .commentURL, - .docComment, .docCommentField, .identifier, .keyword, .number, - .objectLiteral, .parameter, .placeholder, .string, - .stringInterpolationAnchor, .typeidentifier] + static let allKinds: Set = [ + .argument, .attributeBuiltin, .attributeID, .buildconfigID, + .buildconfigKeyword, .comment, .commentMark, .commentURL, + .docComment, .docCommentField, .identifier, .keyword, .number, + .objectLiteral, .parameter, .placeholder, .string, + .stringInterpolationAnchor, .typeidentifier, + ] /// Syntax kinds that don't have associated module info when getting their cursor info. static var kindsWithoutModuleInfo: Set { @@ -33,7 +37,7 @@ public extension SyntaxKind { .buildconfigID, .commentURL, .comment, - .docCommentField + .docCommentField, ] } } diff --git a/Source/SwiftLintCore/Models/Command.swift b/Source/SwiftLintCore/Models/Command.swift index d9efb2ac61..0a7675a2c4 100644 --- a/Source/SwiftLintCore/Models/Command.swift +++ b/Source/SwiftLintCore/Models/Command.swift @@ -151,17 +151,17 @@ public struct Command: Equatable { case .previous: return [ Self(action: action, ruleIdentifiers: ruleIdentifiers, line: line - 1), - Self(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line - 1, character: Int.max) + Self(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line - 1, character: Int.max), ] case .this: return [ Self(action: action, ruleIdentifiers: ruleIdentifiers, line: line), - Self(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line, character: Int.max) + Self(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line, character: Int.max), ] case .next: return [ Self(action: action, ruleIdentifiers: ruleIdentifiers, line: line + 1), - Self(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line + 1, character: Int.max) + Self(action: action.inverse(), ruleIdentifiers: ruleIdentifiers, line: line + 1, character: Int.max), ] case .invalid: return [] diff --git a/Source/SwiftLintCore/Models/ReportersList.swift b/Source/SwiftLintCore/Models/ReportersList.swift index 1c7d8c2ebe..e8773225e4 100644 --- a/Source/SwiftLintCore/Models/ReportersList.swift +++ b/Source/SwiftLintCore/Models/ReportersList.swift @@ -17,5 +17,5 @@ public let reportersList: [any Reporter.Type] = [ SARIFReporter.self, SonarQubeReporter.self, SummaryReporter.self, - XcodeReporter.self + XcodeReporter.self, ] diff --git a/Source/SwiftLintCore/Reporters/CSVReporter.swift b/Source/SwiftLintCore/Reporters/CSVReporter.swift index 3c0a7ff26e..ef95ddac62 100644 --- a/Source/SwiftLintCore/Reporters/CSVReporter.swift +++ b/Source/SwiftLintCore/Reporters/CSVReporter.swift @@ -16,7 +16,7 @@ struct CSVReporter: Reporter { "severity", "type", "reason", - "rule_id" + "rule_id", ].joined(separator: ",") let rows = [keys] + violations.map(csvRow(for:)) @@ -33,7 +33,7 @@ struct CSVReporter: Reporter { violation.severity.rawValue.capitalized, violation.ruleName.escapedForCSV(), violation.reason.escapedForCSV(), - violation.ruleIdentifier + violation.ruleIdentifier, ].joined(separator: ",") } } diff --git a/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift b/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift index 4c039e2b2b..46dd4d90ad 100644 --- a/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift +++ b/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift @@ -14,7 +14,7 @@ struct CheckstyleReporter: Reporter { .group(by: { ($0.location.file ?? "").escapedForXML() }) .sorted(by: { $0.key < $1.key }) .map(generateForViolationFile).joined(), - "\n" + "\n", ].joined() } @@ -24,7 +24,7 @@ struct CheckstyleReporter: Reporter { return [ "\n\t\n", violations.map(generateForSingleViolation).joined(), - "\t" + "\t", ].joined() } @@ -40,7 +40,7 @@ struct CheckstyleReporter: Reporter { "column=\"\(col)\" ", "severity=\"", severity, "\" ", "message=\"", reason, "\" ", - "source=\"\(source)\"/>\n" + "source=\"\(source)\"/>\n", ].joined() } } diff --git a/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift b/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift index 1c5e57658b..83e7fd23ed 100644 --- a/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift +++ b/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift @@ -29,11 +29,11 @@ struct CodeClimateReporter: Reporter { "path": violation.location.relativeFile ?? NSNull() as Any, "lines": [ "begin": violation.location.line ?? NSNull() as Any, - "end": violation.location.line ?? NSNull() as Any - ] + "end": violation.location.line ?? NSNull() as Any, + ], ], "severity": violation.severity == .error ? "major" : "minor", - "type": "issue" + "type": "issue", ] } @@ -46,7 +46,7 @@ struct CodeClimateReporter: Reporter { return [ "\(fingerprintLocation)", - "\(violation.ruleIdentifier)" + "\(violation.ruleIdentifier)", ].joined().sha256() } } diff --git a/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift b/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift index f4d388f710..9d61c07d7e 100644 --- a/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift +++ b/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift @@ -23,7 +23,7 @@ struct GitHubActionsLoggingReporter: Reporter { "line=\(violation.location.line ?? 1),", "col=\(violation.location.character ?? 1)::", violation.reason, - " (\(violation.ruleIdentifier))" + " (\(violation.ruleIdentifier))", ].joined() } } diff --git a/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift b/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift index 57381e3b94..a297ed3f75 100644 --- a/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift +++ b/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift @@ -31,7 +31,7 @@ struct GitLabJUnitReporter: Reporter { return [ "\n\t\n", "\t\t\(body)\n\t\t\n", - "\t" + "\t", ].joined() }).joined() + "\n\n" } diff --git a/Source/SwiftLintCore/Reporters/JSONReporter.swift b/Source/SwiftLintCore/Reporters/JSONReporter.swift index f5a866f151..1c65725477 100644 --- a/Source/SwiftLintCore/Reporters/JSONReporter.swift +++ b/Source/SwiftLintCore/Reporters/JSONReporter.swift @@ -23,7 +23,7 @@ struct JSONReporter: Reporter { "severity": violation.severity.rawValue.capitalized, "type": violation.ruleName, "rule_id": violation.ruleIdentifier, - "reason": violation.reason + "reason": violation.reason, ] } } diff --git a/Source/SwiftLintCore/Reporters/MarkdownReporter.swift b/Source/SwiftLintCore/Reporters/MarkdownReporter.swift index b121be845a..e4fed75337 100644 --- a/Source/SwiftLintCore/Reporters/MarkdownReporter.swift +++ b/Source/SwiftLintCore/Reporters/MarkdownReporter.swift @@ -14,7 +14,7 @@ struct MarkdownReporter: Reporter { "line", "severity", "reason", - "rule_id" + "rule_id", ].joined(separator: " | ") let rows = [keys, "--- | --- | --- | --- | ---"] + violations.map(markdownRow(for:)) @@ -29,7 +29,7 @@ struct MarkdownReporter: Reporter { violation.location.line?.description ?? "", severity(for: violation.severity), violation.ruleName.escapedForMarkdown() + ": " + violation.reason.escapedForMarkdown(), - violation.ruleIdentifier + violation.ruleIdentifier, ].joined(separator: " | ") } diff --git a/Source/SwiftLintCore/Reporters/RelativePathReporter.swift b/Source/SwiftLintCore/Reporters/RelativePathReporter.swift index ae22120e9c..e8ee8df298 100644 --- a/Source/SwiftLintCore/Reporters/RelativePathReporter.swift +++ b/Source/SwiftLintCore/Reporters/RelativePathReporter.swift @@ -25,7 +25,7 @@ struct RelativePathReporter: Reporter { "\(violation.severity.rawValue): ", "\(violation.ruleName) Violation: ", violation.reason, - " (\(violation.ruleIdentifier))" + " (\(violation.ruleIdentifier))", ].joined() } } diff --git a/Source/SwiftLintCore/Reporters/SARIFReporter.swift b/Source/SwiftLintCore/Reporters/SARIFReporter.swift index 4bcda874af..4349941c28 100644 --- a/Source/SwiftLintCore/Reporters/SARIFReporter.swift +++ b/Source/SwiftLintCore/Reporters/SARIFReporter.swift @@ -22,12 +22,12 @@ struct SARIFReporter: Reporter { "driver": [ "name": "SwiftLint", "semanticVersion": Version.current.value, - "informationUri": swiftlintVersion - ] + "informationUri": swiftlintVersion, + ], ], - "results": violations.map(dictionary(for:)) - ] - ] + "results": violations.map(dictionary(for:)), + ], + ], ] as [String: Any] return toJSON(SARIFJson) @@ -44,7 +44,7 @@ struct SARIFReporter: Reporter { ], "locations": [ dictionary(for: violation.location) - ] + ], ] } @@ -58,9 +58,9 @@ struct SARIFReporter: Reporter { ], "region": [ "startLine": line, - "startColumn": location.character ?? "1" - ] - ] + "startColumn": location.character ?? "1", + ], + ], ] } @@ -68,8 +68,8 @@ struct SARIFReporter: Reporter { "physicalLocation": [ "artifactLocation": [ "uri": location.file ?? "" - ] - ] + ], + ], ] } } diff --git a/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift b/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift index 81483ccf45..03dec72f5c 100644 --- a/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift +++ b/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift @@ -24,10 +24,10 @@ struct SonarQubeReporter: Reporter { "filePath": violation.location.relativeFile ?? "", "textRange": [ "startLine": violation.location.line ?? 1 - ] as Any + ] as Any, ] as Any, "type": "CODE_SMELL", - "severity": violation.severity == .error ? "MAJOR" : "MINOR" + "severity": violation.severity == .error ? "MAJOR" : "MINOR", ] } } diff --git a/Source/SwiftLintCore/Reporters/SummaryReporter.swift b/Source/SwiftLintCore/Reporters/SummaryReporter.swift index d8a0656114..fb939fcef3 100644 --- a/Source/SwiftLintCore/Reporters/SummaryReporter.swift +++ b/Source/SwiftLintCore/Reporters/SummaryReporter.swift @@ -32,7 +32,7 @@ private extension TextTable { TextTableColumn(header: numberOfWarningsHeader), TextTableColumn(header: numberOfErrorsHeader), TextTableColumn(header: numberOfViolationsHeader), - TextTableColumn(header: numberOfFilesHeader) + TextTableColumn(header: numberOfFilesHeader), ] self.init(columns: columns) @@ -75,7 +75,7 @@ private extension TextTable { numberOfWarnings.formattedString.leftPadded(forHeader: numberOfWarningsHeader), numberOfErrors.formattedString.leftPadded(forHeader: numberOfErrorsHeader), numberOfViolations.formattedString.leftPadded(forHeader: numberOfViolationsHeader), - numberOfFiles.formattedString.leftPadded(forHeader: numberOfFilesHeader) + numberOfFiles.formattedString.leftPadded(forHeader: numberOfFilesHeader), ]) } @@ -89,7 +89,7 @@ private extension TextTable { totalNumberOfWarnings.formattedString.leftPadded(forHeader: numberOfWarningsHeader), totalNumberOfErrors.formattedString.leftPadded(forHeader: numberOfErrorsHeader), totalNumberOfViolations.formattedString.leftPadded(forHeader: numberOfViolationsHeader), - totalNumberOfFiles.formattedString.leftPadded(forHeader: numberOfFilesHeader) + totalNumberOfFiles.formattedString.leftPadded(forHeader: numberOfFilesHeader), ]) } diff --git a/Source/SwiftLintCore/Reporters/XcodeReporter.swift b/Source/SwiftLintCore/Reporters/XcodeReporter.swift index cd478be29f..cff21a898a 100644 --- a/Source/SwiftLintCore/Reporters/XcodeReporter.swift +++ b/Source/SwiftLintCore/Reporters/XcodeReporter.swift @@ -22,7 +22,7 @@ struct XcodeReporter: Reporter { "\(violation.severity.rawValue): ", "\(violation.ruleName) Violation: ", violation.reason, - " (\(violation.ruleIdentifier))" + " (\(violation.ruleIdentifier))", ].joined() } } diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index c25c4dfb1b..b6e66089a0 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -35,7 +35,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, excluded.map(\.pattern).joined(separator: ","), SyntaxKind.allKinds.subtracting(excludedMatchKinds) .map({ $0.rawValue }).sorted(by: <).joined(separator: ","), - severity.rawValue + severity.rawValue, ] if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject) { return String(decoding: jsonData, as: UTF8.self) diff --git a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift index 8403bcb327..7ea3de8ed3 100644 --- a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift @@ -19,8 +19,10 @@ public struct SeverityLevelsConfiguration: RuleConfiguration, Inli /// The rule parameters that define the thresholds that should map to each severity. public var params: [RuleParameter] { if let error { - return [RuleParameter(severity: .error, value: error), - RuleParameter(severity: .warning, value: warning)] + return [ + RuleParameter(severity: .error, value: error), + RuleParameter(severity: .warning, value: warning), + ] } return [RuleParameter(severity: .warning, value: warning)] } diff --git a/Source/SwiftLintCore/Rules/CoreRules.swift b/Source/SwiftLintCore/Rules/CoreRules.swift index a1dc3895ee..fc959d2333 100644 --- a/Source/SwiftLintCore/Rules/CoreRules.swift +++ b/Source/SwiftLintCore/Rules/CoreRules.swift @@ -1,5 +1,5 @@ /// The rule list containing all available rules built into SwiftLintCore. public let coreRules: [any Rule.Type] = [ CustomRules.self, - SuperfluousDisableCommandRule.self + SuperfluousDisableCommandRule.self, ] diff --git a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift index f9c0c09e0d..f7dee1b17b 100644 --- a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift +++ b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift @@ -17,7 +17,7 @@ package struct SuperfluousDisableCommandRule: SourceKitFreeRule { // swiftlint:disable colon let abc:Void // swiftlint:enable colon - """) + """), ], triggeringExamples: [ Example("let abc: Void // swiftlint:disable:this colon"), @@ -25,7 +25,7 @@ package struct SuperfluousDisableCommandRule: SourceKitFreeRule { // swiftlint:disable colon let abc: Void // swiftlint:enable colon - """) + """), ] ) diff --git a/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift b/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift index 9a9780590c..1835e903f0 100644 --- a/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift +++ b/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift @@ -90,7 +90,7 @@ public extension Array where Element == any DeclSyntaxProtocol.Type { ProtocolDeclSyntax.self, StructDeclSyntax.self, SubscriptDeclSyntax.self, - VariableDeclSyntax.self + VariableDeclSyntax.self, ] /// All declarations except for the specified ones. diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index 036d4177bb..09b0263dcb 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -83,7 +83,7 @@ enum AutoApply: MemberMacro { Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } """ - }) + }), ] } } @@ -117,7 +117,7 @@ enum MakeAcceptableByConfigurationElement: ExtensionMacro { } } } - """) + """), ] } } diff --git a/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift b/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift index 90e85cd26d..fda8ad5534 100644 --- a/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift +++ b/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift @@ -8,7 +8,7 @@ struct SwiftLintCoreMacros: CompilerPlugin { let providingMacros: [any Macro.Type] = [ AutoApply.self, MakeAcceptableByConfigurationElement.self, - SwiftSyntaxRule.self + SwiftSyntaxRule.self, ] } diff --git a/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift b/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift index 340bfba2e1..aed202e684 100644 --- a/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift +++ b/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift @@ -34,7 +34,7 @@ enum SwiftSyntaxRule: ExtensionMacro { } } """ - ) + ), ].compactMap { $0 } } diff --git a/Source/swiftlint/Commands/Reporters.swift b/Source/swiftlint/Commands/Reporters.swift index 0eb9aa3b0b..345a93a0a7 100644 --- a/Source/swiftlint/Commands/Reporters.swift +++ b/Source/swiftlint/Commands/Reporters.swift @@ -19,13 +19,13 @@ private extension TextTable { init(reporters: [any Reporter.Type]) { let columns = [ TextTableColumn(header: "identifier"), - TextTableColumn(header: "description") + TextTableColumn(header: "description"), ] self.init(columns: columns) for reporter in reporters { addRow(values: [ reporter.identifier, - reporter.description + reporter.description, ]) } } diff --git a/Source/swiftlint/Commands/Rules.swift b/Source/swiftlint/Commands/Rules.swift index 52cff62992..ef56251f08 100644 --- a/Source/swiftlint/Commands/Rules.swift +++ b/Source/swiftlint/Commands/Rules.swift @@ -112,7 +112,7 @@ private extension TextTable { TextTableColumn(header: "kind"), TextTableColumn(header: "analyzer"), TextTableColumn(header: "uses sourcekit"), - TextTableColumn(header: "configuration") + TextTableColumn(header: "configuration"), ] self.init(columns: columns) func truncate(_ string: String) -> String { @@ -141,7 +141,7 @@ private extension TextTable { ruleType.description.kind.rawValue, (rule is any AnalyzerRule) ? "yes" : "no", (rule is any SourceKitFreeRule) ? "no" : "yes", - truncate((defaultConfig ? rule : configuredRule ?? rule).configurationDescription.oneLiner()) + truncate((defaultConfig ? rule : configuredRule ?? rule).configurationDescription.oneLiner()), ]) } } diff --git a/Source/swiftlint/Commands/SwiftLint.swift b/Source/swiftlint/Commands/SwiftLint.swift index 8229530b18..7368b9a9d8 100644 --- a/Source/swiftlint/Commands/SwiftLint.swift +++ b/Source/swiftlint/Commands/SwiftLint.swift @@ -27,7 +27,7 @@ struct SwiftLint: AsyncParsableCommand { Baseline.self, Reporters.self, Rules.self, - Version.self + Version.self, ], defaultSubcommand: Lint.self ) diff --git a/Source/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift b/Source/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift index c7e25c0686..e94ceeb209 100644 --- a/Source/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift +++ b/Source/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift @@ -20,7 +20,7 @@ extension ProcessInfo { "CI_WORKSPACE", "CI_XCODE_PROJECT", "CI_XCODE_SCHEME", - "CI_XCODEBUILD_ACTION" + "CI_XCODEBUILD_ACTION", ] return requiredKeys.isSubset(of: environment.keys) diff --git a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift index d0cf23c514..ffd8e13747 100644 --- a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift +++ b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift @@ -94,7 +94,7 @@ extension Array where Element == String { "-incremental", "-serialize-diagnostics", "-emit-dependencies", - "-use-frontend-parseable-output" + "-use-frontend-parseable-output", ].contains(arg) }.map { arg in if arg == "-O" { diff --git a/Tests/CLITests/RulesFilterTests.swift b/Tests/CLITests/RulesFilterTests.swift index fb2076601e..fa1cd87592 100644 --- a/Tests/CLITests/RulesFilterTests.swift +++ b/Tests/CLITests/RulesFilterTests.swift @@ -8,12 +8,12 @@ final class RulesFilterTests: XCTestCase { rules: [ RuleMock1.self, RuleMock2.self, - CorrectableRuleMock.self + CorrectableRuleMock.self, ] ) let enabledRules: [any Rule] = [ RuleMock1(), - CorrectableRuleMock() + CorrectableRuleMock(), ] let rulesFilter = RulesFilter( allRules: allRules, @@ -33,12 +33,12 @@ final class RulesFilterTests: XCTestCase { rules: [ RuleMock1.self, RuleMock2.self, - CorrectableRuleMock.self + CorrectableRuleMock.self, ] ) let enabledRules: [any Rule] = [ RuleMock1(), - CorrectableRuleMock() + CorrectableRuleMock(), ] let rulesFilter = RulesFilter( allRules: allRules, @@ -58,12 +58,12 @@ final class RulesFilterTests: XCTestCase { rules: [ RuleMock1.self, RuleMock2.self, - CorrectableRuleMock.self + CorrectableRuleMock.self, ] ) let enabledRules: [any Rule] = [ RuleMock1(), - CorrectableRuleMock() + CorrectableRuleMock(), ] let rulesFilter = RulesFilter( allRules: allRules, @@ -83,12 +83,12 @@ final class RulesFilterTests: XCTestCase { rules: [ RuleMock1.self, RuleMock2.self, - CorrectableRuleMock.self + CorrectableRuleMock.self, ] ) let enabledRules: [any Rule] = [ RuleMock1(), - CorrectableRuleMock() + CorrectableRuleMock(), ] let rulesFilter = RulesFilter( allRules: allRules, @@ -108,7 +108,7 @@ final class RulesFilterTests: XCTestCase { rules: [ RuleMock1.self, RuleMock2.self, - CorrectableRuleMock.self + CorrectableRuleMock.self, ] ) let enabledRules: [any Rule] = [ diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index ff49b170ca..47ec32879e 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -92,8 +92,10 @@ final class IntegrationTests: SwiftLintTestCase { try? FileManager.default.removeItem(at: seatbeltURL) } - let swiftlintInSandboxArgs = ["sandbox-exec", "-f", seatbeltURL.path, "sh", "-c", - "SWIFTLINT_SWIFT_VERSION=5 \(swiftlintURL.path) --no-cache"] + let swiftlintInSandboxArgs = [ + "sandbox-exec", "-f", seatbeltURL.path, "sh", "-c", + "SWIFTLINT_SWIFT_VERSION=5 \(swiftlintURL.path) --no-cache", + ] let swiftlintResult = execute(swiftlintInSandboxArgs, in: testSwiftURL.deletingLastPathComponent()) let statusWithoutCrash: Int32 = 0 let stdoutWithoutCrash = """ diff --git a/Tests/MacroTests/AutoApplyTests.swift b/Tests/MacroTests/AutoApplyTests.swift index 6e8a677f69..377fe34f48 100644 --- a/Tests/MacroTests/AutoApplyTests.swift +++ b/Tests/MacroTests/AutoApplyTests.swift @@ -171,7 +171,7 @@ final class AutoApplyTests: XCTestCase { message: SwiftLintCoreMacroError.severityBasedWithoutProperty.message, line: 2, column: 8 - ) + ), ], macros: macros) } diff --git a/Tests/MacroTests/SwiftSyntaxRuleTests.swift b/Tests/MacroTests/SwiftSyntaxRuleTests.swift index 624d3a5d71..d5a7dd28d7 100644 --- a/Tests/MacroTests/SwiftSyntaxRuleTests.swift +++ b/Tests/MacroTests/SwiftSyntaxRuleTests.swift @@ -94,7 +94,7 @@ final class SwiftSyntaxRuleTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: SwiftLintCoreMacroError.noBooleanLiteral.message, line: 1, column: 35), - DiagnosticSpec(message: SwiftLintCoreMacroError.noBooleanLiteral.message, line: 1, column: 63) + DiagnosticSpec(message: SwiftLintCoreMacroError.noBooleanLiteral.message, line: 1, column: 63), ], macros: macros ) diff --git a/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift b/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift index eabf603fc9..2a0f5444ee 100644 --- a/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/AttributesRuleTests.swift @@ -15,12 +15,12 @@ final class AttributesRuleTests: SwiftLintTestCase { """), Example(""" @objc(XYZFoo) class Foo: NSObject {} - """) + """), ] let triggeringExamples = [ Example("@objc\n ↓var x: String"), Example("@objc\n ↓func foo()"), - Example("@nonobjc ↓func foo()") + Example("@nonobjc ↓func foo()"), ] let alwaysOnSameLineDescription = AttributesRule.description @@ -36,12 +36,12 @@ final class AttributesRuleTests: SwiftLintTestCase { let nonTriggeringExamples = [ Example("@objc\n var x: String"), Example("@objc\n func foo()"), - Example("@nonobjc\n func foo()") + Example("@nonobjc\n func foo()"), ] let triggeringExamples = [ Example("@objc ↓var x: String"), Example("@objc ↓func foo()"), - Example("@nonobjc ↓func foo()") + Example("@nonobjc ↓func foo()"), ] let alwaysOnNewLineDescription = AttributesRule.description @@ -66,7 +66,7 @@ final class AttributesRuleTests: SwiftLintTestCase { @objc optional func tagDidSelect(_ title: String, sender: TagListView) @objc optional func tagDidDeselect(_ title: String, sender: TagListView) } - """) + """), ] let triggeringExamples = [ @@ -84,16 +84,21 @@ final class AttributesRuleTests: SwiftLintTestCase { optional ↓func tagDidSelect(_ title: String, sender: TagListView) @objc optional func tagDidDeselect(_ title: String, sender: TagListView) } - """) + """), ] let alwaysOnNewLineDescription = AttributesRule.description .with(triggeringExamples: triggeringExamples) .with(nonTriggeringExamples: nonTriggeringExamples) - verifyRule(alwaysOnNewLineDescription, - ruleConfiguration: ["always_on_same_line": ["@discardableResult", "@objc", - "@IBAction", "@IBDesignable"]]) + verifyRule( + alwaysOnNewLineDescription, + ruleConfiguration: [ + "always_on_same_line": [ + "@discardableResult", "@objc", "@IBAction", "@IBDesignable", + ], + ] + ) } func testAttributesWithArgumentsAlwaysOnLineAboveFalse() { @@ -104,7 +109,7 @@ final class AttributesRuleTests: SwiftLintTestCase { Example(""" @Environment(\\.presentationMode) private ↓var presentationMode - """) + """), ] let argumentsAlwaysOnLineDescription = AttributesRule.description diff --git a/Tests/SwiftLintFrameworkTests/BaselineTests.swift b/Tests/SwiftLintFrameworkTests/BaselineTests.swift index 5f45b66c03..732d9e6f79 100644 --- a/Tests/SwiftLintFrameworkTests/BaselineTests.swift +++ b/Tests/SwiftLintFrameworkTests/BaselineTests.swift @@ -44,7 +44,7 @@ final class BaselineTests: XCTestCase { ArrayInitRule.description, BlockBasedKVORule.description, ClosingBraceRule.description, - DirectReturnRule.description + DirectReturnRule.description, ] private static var currentDirectoryPath: String? @@ -116,14 +116,14 @@ final class BaselineTests: XCTestCase { BlockBasedKVORule.description, DirectReturnRule.description, ArrayInitRule.description, - ClosingBraceRule.description + ClosingBraceRule.description, ] let ruleDescriptions = [ ArrayInitRule.description, BlockBasedKVORule.description, ClosingBraceRule.description, - DirectReturnRule.description + DirectReturnRule.description, ] for ruleDescription in ruleDescriptions { diff --git a/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift b/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift index cb0210a1fe..9540c085c1 100644 --- a/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/BlanketDisableCommandRuleTests.swift @@ -14,7 +14,7 @@ final class BlanketDisableCommandRuleTests: SwiftLintTestCase { Example("// swiftlint:disable file_length\n// swiftlint:enable ↓file_length"), Example("// swiftlint:disable:previous ↓file_length"), Example("// swiftlint:disable:this ↓file_length"), - Example("// swiftlint:disable:next ↓file_length") + Example("// swiftlint:disable:next ↓file_length"), ] verifyRule(emptyDescription.with(triggeringExamples: triggeringExamples), ruleConfiguration: ["always_blanket_disable": ["file_length"]], @@ -31,7 +31,7 @@ final class BlanketDisableCommandRuleTests: SwiftLintTestCase { func testAllowedRules() { let nonTriggeringExamples = [ Example("// swiftlint:disable file_length"), - Example("// swiftlint:disable single_test_class") + Example("// swiftlint:disable single_test_class"), ] verifyRule(emptyDescription.with(nonTriggeringExamples: nonTriggeringExamples)) } diff --git a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift index 8ca48411f2..0a154dea0c 100644 --- a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift @@ -12,8 +12,12 @@ final class CollectingRuleTests: SwiftLintTestCase { } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Int]) -> [StyleViolation] { XCTAssertEqual(collectedInfo[file], 42) - return [StyleViolation(ruleDescription: Self.description, - location: Location(file: file, byteOffset: 0))] + return [ + StyleViolation( + ruleDescription: Self.description, + location: Location(file: file, byteOffset: 0) + ), + ] } } @@ -32,8 +36,12 @@ final class CollectingRuleTests: SwiftLintTestCase { XCTAssertTrue(values.contains("foo")) XCTAssertTrue(values.contains("bar")) XCTAssertTrue(values.contains("baz")) - return [StyleViolation(ruleDescription: Self.description, - location: Location(file: file, byteOffset: 0))] + return [ + StyleViolation( + ruleDescription: Self.description, + location: Location(file: file, byteOffset: 0) + ), + ] } } @@ -51,8 +59,12 @@ final class CollectingRuleTests: SwiftLintTestCase { func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: [String]], compilerArguments: [String]) -> [StyleViolation] { XCTAssertEqual(collectedInfo[file], compilerArguments) - return [StyleViolation(ruleDescription: Self.description, - location: Location(file: file, byteOffset: 0))] + return [ + StyleViolation( + ruleDescription: Self.description, + location: Location(file: file, byteOffset: 0) + ), + ] } } @@ -69,16 +81,24 @@ final class CollectingRuleTests: SwiftLintTestCase { func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String]) -> [StyleViolation] { if collectedInfo[file] == "baz" { - return [StyleViolation(ruleDescription: Self.description, - location: Location(file: file, byteOffset: 2))] + return [ + StyleViolation( + ruleDescription: Self.description, + location: Location(file: file, byteOffset: 2) + ), + ] } return [] } func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String]) -> [Correction] { if collectedInfo[file] == "baz" { - return [Correction(ruleDescription: Self.description, - location: Location(file: file, byteOffset: 2))] + return [ + Correction( + ruleDescription: Self.description, + location: Location(file: file, byteOffset: 2) + ), + ] } return [] } @@ -94,19 +114,21 @@ final class CollectingRuleTests: SwiftLintTestCase { func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String], compilerArguments: [String]) -> [StyleViolation] { if collectedInfo[file] == "baz" { - return [StyleViolation(ruleDescription: Spec.description, - location: Location(file: file, byteOffset: 2))] + return [ + StyleViolation( + ruleDescription: Spec.description, + location: Location(file: file, byteOffset: 2) + ), + ] } return [] } func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String], compilerArguments: [String]) -> [Correction] { - if collectedInfo[file] == "baz" { - return [Correction(ruleDescription: Spec.description, - location: Location(file: file, byteOffset: 2))] - } - return [] + collectedInfo[file] == "baz" + ? [Correction(ruleDescription: Spec.description, location: Location(file: file, byteOffset: 2))] + : [] } } diff --git a/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift b/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift index 03d40cd653..095214241e 100644 --- a/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ColonRuleTests.swift @@ -10,7 +10,7 @@ final class ColonRuleTests: SwiftLintTestCase { Example("let abc: ([Void], String, Int)\n"), Example("let abc: [([Void], String, Int)]\n"), Example("func abc(def: Void) {}\n"), - Example("let abc = [Void: Void]()\n") + Example("let abc = [Void: Void]()\n"), ] let triggeringExamples: [Example] = [ Example("let abc↓:Void\n"), @@ -34,7 +34,7 @@ final class ColonRuleTests: SwiftLintTestCase { Example("let abc = [Void↓ : Void]()\n"), Example("let abc = [Void↓ : Void]()\n"), Example("let abc = [1: [3↓ : 2], 3: 4]\n"), - Example("let abc = [1: [3↓ : 2], 3: 4]\n") + Example("let abc = [1: [3↓ : 2], 3: 4]\n"), ] let corrections: [Example: Example] = [ Example("let abc↓:Void\n"): Example("let abc: Void\n"), @@ -58,7 +58,7 @@ final class ColonRuleTests: SwiftLintTestCase { Example("let abc = [Void↓ : Void]()\n"): Example("let abc = [Void: Void]()\n"), Example("let abc = [Void↓ : Void]()\n"): Example("let abc = [Void: Void]()\n"), Example("let abc = [1: [3↓ : 2], 3: 4]\n"): Example("let abc = [1: [3: 2], 3: 4]\n"), - Example("let abc = [1: [3↓ : 2], 3: 4]\n"): Example("let abc = [1: [3: 2], 3: 4]\n") + Example("let abc = [1: [3↓ : 2], 3: 4]\n"): Example("let abc = [1: [3: 2], 3: 4]\n"), ] let description = ColonRule.description.with(triggeringExamples: triggeringExamples) .with(nonTriggeringExamples: nonTriggeringExamples) @@ -74,7 +74,7 @@ final class ColonRuleTests: SwiftLintTestCase { Example("let abc = [Void: Void]()\n"), Example("let abc = [Void : Void]()\n"), Example("let abc = [1: [3 : 2], 3: 4]\n"), - Example("let abc = [1: [3 : 2], 3: 4]\n") + Example("let abc = [1: [3 : 2], 3: 4]\n"), ] let triggeringExamples: [Example] = [ Example("let abc↓:Void\n"), @@ -98,7 +98,7 @@ final class ColonRuleTests: SwiftLintTestCase { Example("func abc(def↓: Void) {}\n"), Example("func abc(def↓ :Void) {}\n"), Example("func abc(def↓ : Void) {}\n"), - Example("func abc(def: Void, ghi↓ :Void) {}\n") + Example("func abc(def: Void, ghi↓ :Void) {}\n"), ] let corrections: [Example: Example] = [ Example("let abc↓:Void\n"): Example("let abc: Void\n"), @@ -122,7 +122,7 @@ final class ColonRuleTests: SwiftLintTestCase { Example("func abc(def↓: Void) {}\n"): Example("func abc(def: Void) {}\n"), Example("func abc(def↓ :Void) {}\n"): Example("func abc(def: Void) {}\n"), Example("func abc(def↓ : Void) {}\n"): Example("func abc(def: Void) {}\n"), - Example("func abc(def: Void, ghi↓ :Void) {}\n"): Example("func abc(def: Void, ghi: Void) {}\n") + Example("func abc(def: Void, ghi↓ :Void) {}\n"): Example("func abc(def: Void, ghi: Void) {}\n"), ] let description = ColonRule.description.with(triggeringExamples: triggeringExamples) diff --git a/Tests/SwiftLintFrameworkTests/CommandTests.swift b/Tests/SwiftLintFrameworkTests/CommandTests.swift index e03f2a092e..5633ee186d 100644 --- a/Tests/SwiftLintFrameworkTests/CommandTests.swift +++ b/Tests/SwiftLintFrameworkTests/CommandTests.swift @@ -150,7 +150,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .previous) let expanded = [ Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 0, character: nil), - Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 0, character: .max) + Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 0, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -159,7 +159,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .previous) let expanded = [ Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 0, character: nil), - Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 0, character: .max) + Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 0, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -168,7 +168,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .previous) let expanded = [ Command(action: .enable, ruleIdentifiers: ["1", "2"], line: 0, character: nil), - Command(action: .disable, ruleIdentifiers: ["1", "2"], line: 0, character: .max) + Command(action: .disable, ruleIdentifiers: ["1", "2"], line: 0, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -180,7 +180,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .this) let expanded = [ Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 1, character: nil), - Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 1, character: .max) + Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 1, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -189,7 +189,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .this) let expanded = [ Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 1, character: nil), - Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 1, character: .max) + Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 1, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -198,7 +198,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .this) let expanded = [ Command(action: .enable, ruleIdentifiers: ["1", "2"], line: 1, character: nil), - Command(action: .disable, ruleIdentifiers: ["1", "2"], line: 1, character: .max) + Command(action: .disable, ruleIdentifiers: ["1", "2"], line: 1, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -210,7 +210,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .next) let expanded = [ Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 2, character: nil), - Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 2, character: .max) + Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 2, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -219,7 +219,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .next) let expanded = [ Command(action: .enable, ruleIdentifiers: ["rule_id"], line: 2, character: nil), - Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 2, character: .max) + Command(action: .disable, ruleIdentifiers: ["rule_id"], line: 2, character: .max), ] XCTAssertEqual(command.expand(), expanded) } @@ -228,7 +228,7 @@ final class CommandTests: SwiftLintTestCase { modifier: .next) let expanded = [ Command(action: .enable, ruleIdentifiers: ["1", "2"], line: 2, character: nil), - Command(action: .disable, ruleIdentifiers: ["1", "2"], line: 2, character: .max) + Command(action: .disable, ruleIdentifiers: ["1", "2"], line: 2, character: .max), ] XCTAssertEqual(command.expand(), expanded) } diff --git a/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift b/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift index ad19c290df..9460f22367 100644 --- a/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift @@ -15,7 +15,7 @@ final class ComputedAccessorsOrderRuleTests: SwiftLintTestCase { } } } - """) + """), ] let triggeringExamples = [ Example(""" @@ -29,7 +29,7 @@ final class ComputedAccessorsOrderRuleTests: SwiftLintTestCase { } } } - """) + """), ] let description = ComputedAccessorsOrderRule.description diff --git a/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift b/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift index 446549c9c5..e2ffbbbc1f 100644 --- a/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConditionalReturnsOnNewlineRuleTests.swift @@ -11,13 +11,13 @@ final class ConditionalReturnsOnNewlineRuleTests: SwiftLintTestCase { Example("if textField.returnKeyType == .Next {"), Example("if true { // return }"), Example("/*if true { */ return }"), - Example("guard true else { return }") + Example("guard true else { return }"), ] let triggeringExamples = [ Example("↓if true { return }"), Example("↓if true { break } else { return }"), Example("↓if true { break } else { return }"), - Example("↓if true { return \"YES\" } else { return \"NO\" }") + Example("↓if true { return \"YES\" } else { return \"NO\" }"), ] let description = ConditionalReturnsOnNewlineRule.description diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index d0220008a3..91e6f85cc6 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -51,9 +51,15 @@ extension ConfigurationTests { } func testOnlyRulesMerging() { - let baseConfiguration = Configuration(rulesMode: .default(disabled: [], - optIn: [ForceTryRule.description.identifier, - ForceCastRule.description.identifier])) + let baseConfiguration = Configuration( + rulesMode: .default( + disabled: [], + optIn: [ + ForceTryRule.description.identifier, + ForceCastRule.description.identifier, + ] + ) + ) let onlyConfiguration = Configuration(rulesMode: .only([TodoRule.description.identifier])) XCTAssertTrue(baseConfiguration.contains(rule: TodoRule.self)) XCTAssertEqual(onlyConfiguration.rules.count, 1) @@ -275,7 +281,7 @@ extension ConfigurationTests { Mock.Dir.childConfigCycle3, Mock.Dir.parentConfigCycle1, Mock.Dir.parentConfigCycle2, - Mock.Dir.parentConfigCycle3 + Mock.Dir.parentConfigCycle3, ] { FileManager.default.changeCurrentDirectoryPath(path) @@ -331,7 +337,7 @@ extension ConfigurationTests { TestCase(optedInInParent: false, disabledInParent: false, optedInInChild: true, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: true, disabledInParent: false, optedInInChild: true, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: false, disabledInParent: true, optedInInChild: true, disabledInChild: true, isEnabled: false), - TestCase(optedInInParent: true, disabledInParent: true, optedInInChild: true, disabledInChild: true, isEnabled: false) + TestCase(optedInInParent: true, disabledInParent: true, optedInInChild: true, disabledInChild: true, isEnabled: false), // swiftlint:enable line_length ] XCTAssertEqual(testCases.unique.count, 4 * 4) @@ -366,7 +372,7 @@ extension ConfigurationTests { TestCase(disabledInParent: false, disabledInChild: false, isEnabled: true), TestCase(disabledInParent: true, disabledInChild: false, isEnabled: false), TestCase(disabledInParent: false, disabledInChild: true, isEnabled: false), - TestCase(disabledInParent: true, disabledInChild: true, isEnabled: false) + TestCase(disabledInParent: true, disabledInChild: true, isEnabled: false), ] XCTAssertEqual(testCases.unique.count, 2 * 2) let ruleType = BlanketDisableCommandRule.self @@ -398,7 +404,7 @@ extension ConfigurationTests { TestCase(optedInInChild: false, disabledInChild: false, isEnabled: true), TestCase(optedInInChild: true, disabledInChild: false, isEnabled: true), TestCase(optedInInChild: false, disabledInChild: true, isEnabled: false), - TestCase(optedInInChild: true, disabledInChild: true, isEnabled: false) + TestCase(optedInInChild: true, disabledInChild: true, isEnabled: false), ] XCTAssertEqual(testCases.unique.count, 2 * 2) let ruleType = ImplicitReturnRule.self @@ -438,14 +444,14 @@ extension ConfigurationTests { Configuration.disabledDefaultConfiguration(ruleIdentifier), Configuration.emptyOnlyConfiguration(), Configuration.enabledOnlyConfiguration(ruleIdentifier), - Configuration.allEnabledConfiguration() + Configuration.allEnabledConfiguration(), ] let configurations = [ Configuration(rulesMode: .default(disabled: [], optIn: [])), Configuration(rulesMode: .default(disabled: [], optIn: [ruleIdentifier])), Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [ruleIdentifier])), - Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [])) + Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [])), ] for parentConfiguration in parentConfigurations { @@ -530,7 +536,7 @@ extension ConfigurationTests { included: - Test/Test1/Test/Test - Test/Test2/Test/Test - """ + """, ] ), Configuration(configurationFiles: ["expected.yml"]) @@ -555,7 +561,7 @@ extension ConfigurationTests { - Test/Test2/Test line_length: 80 - """ + """, ] ), Configuration(configurationFiles: ["expected.yml"]) @@ -575,7 +581,7 @@ extension ConfigurationTests { line_length: 60 child_config: child2.yml - """ + """, ] ), Configuration() @@ -593,7 +599,7 @@ extension ConfigurationTests { "https://www.mock.com": """ child_config: https://www.mock.com - """ + """, ] ), Configuration() diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index fea71880f7..82f841c15f 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -130,11 +130,11 @@ final class ConfigurationTests: SwiftLintTestCase { let only = ["nesting", "todo"] let enabledRulesConfigDict = [ "opt_in_rules": ["line_length"], - "only_rules": only + "only_rules": only, ] let disabledRulesConfigDict = [ "disabled_rules": ["identifier_name"], - "only_rules": only + "only_rules": only, ] let combinedRulesConfigDict = enabledRulesConfigDict.reduce(into: disabledRulesConfigDict) { $0[$1.0] = $1.1 } var configuration = try? Configuration(dict: enabledRulesConfigDict) @@ -236,9 +236,12 @@ final class ConfigurationTests: SwiftLintTestCase { func filesToLint(inPath path: String, rootDirectory: String? = nil) -> [String] { var filesToLint: [String] = [] switch path { - case "directory": filesToLint = ["directory/File1.swift", "directory/File2.swift", - "directory/excluded/Excluded.swift", - "directory/ExcludedFile.swift"] + case "directory": filesToLint = [ + "directory/File1.swift", + "directory/File2.swift", + "directory/excluded/Excluded.swift", + "directory/ExcludedFile.swift", + ] case "directory/excluded": filesToLint = ["directory/excluded/Excluded.swift"] case "directory/ExcludedFile.swift": filesToLint = ["directory/ExcludedFile.swift"] default: XCTFail("Should not be called with path \(path)") @@ -257,9 +260,10 @@ final class ConfigurationTests: SwiftLintTestCase { func testExcludedPaths() { let fileManager = TestFileManager() - let configuration = Configuration(includedPaths: ["directory"], - excludedPaths: ["directory/excluded", - "directory/ExcludedFile.swift"]) + let configuration = Configuration( + includedPaths: ["directory"], + excludedPaths: ["directory/excluded", "directory/ExcludedFile.swift"] + ) let excludedPaths = configuration.excludedPaths(fileManager: fileManager) let paths = configuration.lintablePaths(inPath: "", @@ -323,7 +327,7 @@ final class ConfigurationTests: SwiftLintTestCase { let expectedFilenames = [ "DirectoryLevel1.swift", "Level0.swift", "Level1.swift", "Level2.swift", "Level3.swift", - "Main.swift", "Sub.swift" + "Main.swift", "Sub.swift", ] XCTAssertEqual(Set(expectedFilenames), Set(filenames)) @@ -449,9 +453,10 @@ final class ConfigurationTests: SwiftLintTestCase { extension ConfigurationTests { func testExcludeByPrefixExcludedPaths() { FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) - let configuration = Configuration(includedPaths: ["Level1"], - excludedPaths: ["Level1/Level1.swift", - "Level1/Level2/Level3"]) + let configuration = Configuration( + includedPaths: ["Level1"], + excludedPaths: ["Level1/Level1.swift", "Level1/Level2/Level3"] + ) let paths = configuration.lintablePaths(inPath: Mock.Dir.level0, forceExclude: false, excludeBy: .prefix) diff --git a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift index ea2d4bd885..194f8312ca 100644 --- a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift @@ -11,8 +11,8 @@ final class CustomRulesTests: SwiftLintTestCase { "message": "Message", "regex": "regex", "match_kinds": "comment", - "severity": "error" - ] + "severity": "error", + ], ] var comp = Configuration(identifier: "my_custom_rule") comp.name = "MyCustomRule" @@ -38,8 +38,8 @@ final class CustomRulesTests: SwiftLintTestCase { "message": "Message", "regex": "regex", "excluded_match_kinds": "comment", - "severity": "error" - ] + "severity": "error", + ], ] var comp = Configuration(identifier: "my_custom_rule") comp.name = "MyCustomRule" @@ -73,7 +73,7 @@ final class CustomRulesTests: SwiftLintTestCase { "regex": "regex", "match_kinds": "comment", "excluded_match_kinds": "argument", - "severity": "error" + "severity": "error", ] var configuration = Configuration(identifier: "my_custom_rule") @@ -87,12 +87,14 @@ final class CustomRulesTests: SwiftLintTestCase { func testCustomRuleConfigurationIgnoreInvalidRules() throws { let configDict = [ - "my_custom_rule": ["name": "MyCustomRule", - "message": "Message", - "regex": "regex", - "match_kinds": "comment", - "severity": "error"], - "invalid_rule": ["name": "InvalidRule"] // missing `regex` + "my_custom_rule": [ + "name": "MyCustomRule", + "message": "Message", + "regex": "regex", + "match_kinds": "comment", + "severity": "error", + ], + "invalid_rule": ["name": "InvalidRule"], // missing `regex` ] var customRulesConfig = CustomRulesConfiguration() try customRulesConfig.apply(configuration: configDict) @@ -107,11 +109,17 @@ final class CustomRulesTests: SwiftLintTestCase { let (regexConfig, customRules) = getCustomRules() let file = SwiftLintFile(contents: "// My file with\n// a pattern") - XCTAssertEqual(customRules.validate(file: file), - [StyleViolation(ruleDescription: regexConfig.description, - severity: .warning, - location: Location(file: nil, line: 2, character: 6), - reason: regexConfig.message)]) + XCTAssertEqual( + customRules.validate(file: file), + [ + StyleViolation( + ruleDescription: regexConfig.description, + severity: .warning, + location: Location(file: nil, line: 2, character: 6), + reason: regexConfig.message + ), + ] + ) } func testLocalDisableCustomRule() { @@ -123,11 +131,17 @@ final class CustomRulesTests: SwiftLintTestCase { func testLocalDisableCustomRuleWithMultipleRules() { let (configs, customRules) = getCustomRulesWithTwoRules() let file = SwiftLintFile(contents: "//swiftlint:disable \(configs.1.identifier) \n// file with a pattern") - XCTAssertEqual(customRules.validate(file: file), - [StyleViolation(ruleDescription: configs.0.description, - severity: .warning, - location: Location(file: nil, line: 2, character: 16), - reason: configs.0.message)]) + XCTAssertEqual( + customRules.validate(file: file), + [ + StyleViolation( + ruleDescription: configs.0.description, + severity: .warning, + location: Location(file: nil, line: 2, character: 16), + reason: configs.0.message + ), + ] + ) } func testCustomRulesIncludedDefault() { @@ -171,8 +185,10 @@ final class CustomRulesTests: SwiftLintTestCase { } func testCustomRulesCaptureGroup() { - let (_, customRules) = getCustomRules(["regex": #"\ba\s+(\w+)"#, - "capture_group": 1]) + let (_, customRules) = getCustomRules([ + "regex": #"\ba\s+(\w+)"#, + "capture_group": 1, + ]) let violations = customRules.validate(file: getTestTextFile()) XCTAssertEqual(violations.count, 1) XCTAssertEqual(violations[0].location.line, 2) @@ -180,8 +196,10 @@ final class CustomRulesTests: SwiftLintTestCase { } private func getCustomRules(_ extraConfig: [String: Any] = [:]) -> (Configuration, CustomRules) { - var config: [String: Any] = ["regex": "pattern", - "match_kinds": "comment"] + var config: [String: Any] = [ + "regex": "pattern", + "match_kinds": "comment", + ] extraConfig.forEach { config[$0] = $1 } var regexConfig = RegexConfiguration(identifier: "custom") @@ -200,8 +218,10 @@ final class CustomRulesTests: SwiftLintTestCase { } private func getCustomRulesWithTwoRules() -> ((Configuration, Configuration), CustomRules) { - let config1 = ["regex": "pattern", - "match_kinds": "comment"] + let config1 = [ + "regex": "pattern", + "match_kinds": "comment", + ] var regexConfig1 = Configuration(identifier: "custom1") do { @@ -210,8 +230,10 @@ final class CustomRulesTests: SwiftLintTestCase { XCTFail("Failed regex config") } - let config2 = ["regex": "something", - "match_kinds": "comment"] + let config2 = [ + "regex": "something", + "match_kinds": "comment", + ] var regexConfig2 = Configuration(identifier: "custom2") do { diff --git a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift index d4ff7b94de..a03337b708 100644 --- a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift @@ -35,9 +35,11 @@ final class CyclomaticComplexityConfigurationTests: SwiftLintTestCase { let warning1 = 10 let error1 = 30 let length1 = SeverityLevelsConfiguration(warning: warning1, error: error1) - let config1: [String: Any] = ["warning": warning1, - "error": error1, - "ignores_case_statements": true] + let config1: [String: Any] = [ + "warning": warning1, + "error": error1, + "ignores_case_statements": true, + ] let warning2 = 20 let error2 = 40 @@ -62,7 +64,7 @@ final class CyclomaticComplexityConfigurationTests: SwiftLintTestCase { func testCyclomaticComplexityConfigurationThrowsOnBadConfigValues() { let badConfigs: [[String: Any]] = [ ["warning": true], - ["ignores_case_statements": 300] + ["ignores_case_statements": 300], ] for badConfig in badConfigs { diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift index df8f2d43fb..b130557f09 100644 --- a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift @@ -87,10 +87,12 @@ final class DeploymentTargetConfigurationTests: SwiftLintTestCase { ) XCTAssertEqual(configuration.severityConfiguration.severity, .warning) - try configuration.apply(configuration: ["tvOS_deployment_target": 10.2, - "tvOSApplicationExtension_deployment_target": 9.1, - "watchOS_deployment_target": 5, - "watchOSApplicationExtension_deployment_target": 2.2]) + try configuration.apply(configuration: [ + "tvOS_deployment_target": 10.2, + "tvOSApplicationExtension_deployment_target": 9.1, + "watchOS_deployment_target": 5, + "watchOSApplicationExtension_deployment_target": 2.2, + ]) XCTAssertEqual( configuration.iOSDeploymentTarget, Version(platform: .iOS, major: 10, minor: 1) @@ -132,7 +134,7 @@ final class DeploymentTargetConfigurationTests: SwiftLintTestCase { ["iOS_deployment_target": ""], ["iOS_deployment_target": "5.x"], ["iOS_deployment_target": true], - ["invalid": true] + ["invalid": true], ] for badConfig in badConfigs { diff --git a/Tests/SwiftLintFrameworkTests/DisableAllTests.swift b/Tests/SwiftLintFrameworkTests/DisableAllTests.swift index 507d448028..a435b8fba1 100644 --- a/Tests/SwiftLintFrameworkTests/DisableAllTests.swift +++ b/Tests/SwiftLintFrameworkTests/DisableAllTests.swift @@ -6,7 +6,7 @@ final class DisableAllTests: SwiftLintTestCase { private let violatingPhrases = [ Example("let r = 0"), // Violates identifier_name Example(#"let myString:String = """#), // Violates colon_whitespace - Example("// TODO: Some todo") // Violates todo + Example("// TODO: Some todo"), // Violates todo ] // MARK: Violating Phrase diff --git a/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift index 6a0b84db23..74f0f4fd57 100644 --- a/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/DiscouragedDirectInitRuleTests.swift @@ -10,12 +10,12 @@ final class DiscouragedDirectInitRuleTests: SwiftLintTestCase { func testDiscouragedDirectInitWithNewIncludedTypes() { let triggeringExamples = [ Example("let foo = ↓Foo()"), - Example("let bar = ↓Bar()") + Example("let bar = ↓Bar()"), ] let nonTriggeringExamples = [ Example("let foo = Foo(arg: toto)"), - Example("let bar = Bar(arg: \"toto\")") + Example("let bar = Bar(arg: \"toto\")"), ] let description = baseDescription diff --git a/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift b/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift index da26fe344c..7dddfe4f23 100644 --- a/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/EmptyCountRuleTests.swift @@ -13,7 +13,7 @@ final class EmptyCountRuleTests: SwiftLintTestCase { Example("[Int]().count == 0o07\n"), Example("discount == 0\n"), Example("order.discount == 0\n"), - Example("count == 0\n") + Example("count == 0\n"), ] let triggeringExamples = [ Example("[Int]().↓count == 0\n"), @@ -22,7 +22,7 @@ final class EmptyCountRuleTests: SwiftLintTestCase { Example("[Int]().↓count == 0x0\n"), Example("[Int]().↓count == 0x00_00\n"), Example("[Int]().↓count == 0b00\n"), - Example("[Int]().↓count == 0o00\n") + Example("[Int]().↓count == 0o00\n"), ] let corrections = [ @@ -53,7 +53,7 @@ final class EmptyCountRuleTests: SwiftLintTestCase { Example("count == 0 && [Int]().↓count == 0o00"): 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("[Int]().count != 3 && ![Int]().isEmpty || count == 0 && [Int]().count > 2"), ] let description = EmptyCountRule.description diff --git a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift index c5b1721ac6..8a013c63bb 100644 --- a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift @@ -185,9 +185,9 @@ final class ExpiringTodoRuleTests: SwiftLintTestCase { "date_format": config.dateFormat, "date_delimiters": [ "opening": config.dateDelimiters.opening, - "closing": config.dateDelimiters.closing + "closing": config.dateDelimiters.closing, ], - "date_separator": config.dateSeparator + "date_separator": config.dateSeparator, ] } diff --git a/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift index 2c8dadf812..65dfee4653 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitInitRuleTests.swift @@ -4,13 +4,13 @@ final class ExplicitInitRuleTests: SwiftLintTestCase { func testIncludeBareInit() { let nonTriggeringExamples = [ Example("let foo = Foo()"), - Example("let foo = init()") + Example("let foo = init()"), ] + ExplicitInitRule.description.nonTriggeringExamples let triggeringExamples = [ Example("let foo: Foo = ↓.init()"), Example("let foo: [Foo] = [↓.init(), ↓.init()]"), - Example("foo(↓.init())") + Example("foo(↓.init())"), ] let description = ExplicitInitRule.description diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift index 022ce95e7e..ea362d5228 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift @@ -11,9 +11,13 @@ final class ExplicitTypeInterfaceConfigurationTests: SwiftLintTestCase { func testApplyingCustomConfiguration() throws { var config = ExplicitTypeInterfaceConfiguration() - try config.apply(configuration: ["severity": "error", - "excluded": ["local"], - "allow_redundancy": true] as [String: any Sendable]) + try config.apply( + configuration: [ + "severity": "error", + "excluded": ["local"], + "allow_redundancy": true, + ] as [String: any Sendable] + ) XCTAssertEqual(config.severityConfiguration.severity, .error) XCTAssertEqual(config.allowedKinds, Set([.instance, .class, .static])) XCTAssertTrue(config.allowRedundancy) diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift index 739a942265..8768283aaf 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift @@ -10,7 +10,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { let x: Int = 1 } } - """) + """), ] let triggeringExamples = [ Example("func foo() {\nlet ↓intVal = 1\n}"), @@ -20,7 +20,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { let ↓x = 1 } } - """) + """), ] let description = ExplicitTypeInterfaceRule.description .with(triggeringExamples: triggeringExamples) @@ -44,12 +44,12 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { func testExcludeClassVars() { let nonTriggeringExamples = ExplicitTypeInterfaceRule.description.nonTriggeringExamples + [ Example("class Foo {\n static var myStaticVar = 0\n}\n"), - Example("class Foo {\n static let myStaticLet = 0\n}\n") + Example("class Foo {\n static let myStaticLet = 0\n}\n"), ] let triggeringExamples: [Example] = [ Example("class Foo {\n var ↓myVar = 0\n\n}\n"), Example("class Foo {\n let ↓mylet = 0\n\n}\n"), - Example("class Foo {\n class var ↓myClassVar = 0\n}\n") + Example("class Foo {\n class var ↓myClassVar = 0\n}\n"), ] let description = ExplicitTypeInterfaceRule.description .with(triggeringExamples: triggeringExamples) @@ -72,7 +72,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { Example("class Foo {\n let array = [String]()\n}\n"), Example("class Foo {\n let dict = [String: String]()\n}\n"), Example("class Foo {\n let dict = [String: [String: Array]]()\n}\n"), - Example("class Foo {\n let l10n = L10n.Communication.self\n}\n") + Example("class Foo {\n let l10n = L10n.Communication.self\n}\n"), ] let triggeringExamples: [Example] = [ Example("class Foo {\n var ↓myVar = 0\n\n}\n"), @@ -80,7 +80,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { Example("class Foo {\n static var ↓myStaticVar = 0\n}\n"), Example("class Foo {\n class var ↓myClassVar = 0\n}\n"), Example("class Foo {\n let ↓array = [\"foo\", \"bar\"]\n}\n"), - Example("class Foo {\n let ↓dict = [\"foo\": \"bar\"]\n}\n") + Example("class Foo {\n let ↓dict = [\"foo\": \"bar\"]\n}\n"), ] let description = ExplicitTypeInterfaceRule.description .with(triggeringExamples: triggeringExamples) @@ -106,7 +106,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { case let error as SomeError: break default: break } - """) + """), ] let triggeringExamples = ExplicitTypeInterfaceRule.description.triggeringExamples let description = ExplicitTypeInterfaceRule.description @@ -139,7 +139,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { } } } - """) + """), ] let triggeringExamples = ExplicitTypeInterfaceRule.description.triggeringExamples let description = ExplicitTypeInterfaceRule.description @@ -162,7 +162,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { let elements: [Int] = [1, 2] for (index, element) in elements.enumerated() {} } - """) + """), ] let triggeringExamples = ExplicitTypeInterfaceRule.description.triggeringExamples @@ -198,7 +198,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { case var (x, y): break } } - """) + """), ] let triggeringExamples = [ @@ -226,7 +226,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { default: let ↓fooBar = 1 } } - """) + """), ] let description = ExplicitTypeInterfaceRule.description diff --git a/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift index 35c70859a8..8867afcf4a 100644 --- a/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileHeaderRuleTests.swift @@ -17,14 +17,14 @@ final class FileHeaderRuleTests: SwiftLintTestCase { func testFileHeaderWithRequiredString() { let nonTriggeringExamples = [ Example("// **Header"), - Example("//\n// **Header") + Example("//\n// **Header"), ] let triggeringExamples = [ Example("↓// Copyright\n"), Example("let foo = \"**Header\""), Example("let foo = 2 // **Header"), Example("let foo = 2\n// **Header"), - Example("let foo = 2 // **Header") + Example("let foo = 2 // **Header"), ] let description = FileHeaderRule.description .with(nonTriggeringExamples: nonTriggeringExamples) @@ -38,12 +38,12 @@ final class FileHeaderRuleTests: SwiftLintTestCase { func testFileHeaderWithRequiredPattern() { let nonTriggeringExamples = [ Example("// Copyright © 2016 Realm"), - Example("//\n// Copyright © 2016 Realm)") + Example("//\n// Copyright © 2016 Realm)"), ] let triggeringExamples = [ Example("↓// Copyright\n"), Example("↓// Copyright © foo Realm"), - Example("↓// Copyright © 2016 MyCompany") + Example("↓// Copyright © 2016 MyCompany"), ] let description = FileHeaderRule.description .with(nonTriggeringExamples: nonTriggeringExamples) @@ -77,11 +77,11 @@ final class FileHeaderRuleTests: SwiftLintTestCase { Example("let foo = \"**All rights reserved.\""), Example("let foo = 2 // **All rights reserved."), Example("let foo = 2\n// **All rights reserved."), - Example("let foo = 2 // **All rights reserved.") + Example("let foo = 2 // **All rights reserved."), ] let triggeringExamples = [ Example("// ↓**All rights reserved."), - Example("//\n// ↓**All rights reserved.") + Example("//\n// ↓**All rights reserved."), ] let description = FileHeaderRule.description .with(nonTriggeringExamples: nonTriggeringExamples) @@ -97,11 +97,11 @@ final class FileHeaderRuleTests: SwiftLintTestCase { Example("// FileHeaderRuleTests.m\n"), Example("let foo = \"FileHeaderRuleTests.swift\""), Example("let foo = 2 // FileHeaderRuleTests.swift."), - Example("let foo = 2\n // FileHeaderRuleTests.swift.") + Example("let foo = 2\n // FileHeaderRuleTests.swift."), ] let triggeringExamples = [ Example("//↓ FileHeaderRuleTests.swift"), - Example("//\n//↓ FileHeaderRuleTests.swift") + Example("//\n//↓ FileHeaderRuleTests.swift"), ] let description = FileHeaderRule.description .with(nonTriggeringExamples: nonTriggeringExamples) @@ -114,11 +114,11 @@ final class FileHeaderRuleTests: SwiftLintTestCase { func testFileHeaderWithForbiddenPatternAndDocComment() { let nonTriggeringExamples = [ Example("/// This is great tool with tests.\nclass GreatTool {}"), - Example("class GreatTool {}") + Example("class GreatTool {}"), ] let triggeringExamples = [ Example("// FileHeaderRule↓Tests.swift"), - Example("//\n// FileHeaderRule↓Tests.swift") + Example("//\n// FileHeaderRule↓Tests.swift"), ] let description = FileHeaderRule.description .with(nonTriggeringExamples: nonTriggeringExamples) @@ -154,8 +154,9 @@ final class FileHeaderRuleTests: SwiftLintTestCase { func testFileHeaderWithRequiredPatternUsingFilenamePlaceholder() { let configuration1 = ["required_pattern": "// SWIFTLINT_CURRENT_FILENAME\n.*\\d{4}"] - let configuration2 = ["required_pattern": - "// Copyright © \\d{4}\n// File: \"SWIFTLINT_CURRENT_FILENAME\""] + let configuration2 = [ + "required_pattern": "// Copyright © \\d{4}\n// File: \"SWIFTLINT_CURRENT_FILENAME\"", + ] // Non triggering tests XCTAssert(try validate(fileName: "FileNameMatchingSimple.swift", using: configuration1).isEmpty) diff --git a/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift index 3fe2caca40..6b629889bf 100644 --- a/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileLengthRuleTests.swift @@ -13,7 +13,7 @@ final class FileLengthRuleTests: SwiftLintTestCase { let nonTriggeringExamples = [ Example((repeatElement("print(\"swiftlint\")\n", count: 400) + ["//\n"]).joined()), Example(repeatElement("print(\"swiftlint\")\n", count: 400).joined()), - Example(repeatElement("print(\"swiftlint\")\n\n", count: 201).joined()) + Example(repeatElement("print(\"swiftlint\")\n\n", count: 201).joined()), ] let description = FileLengthRule.description diff --git a/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift index d5b000a307..e9a6f8c93d 100644 --- a/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileTypesOrderRuleTests.swift @@ -66,7 +66,7 @@ final class FileTypesOrderRuleTests: SwiftLintTestCase { LibraryItem(ContentView()) } } - """) + """), ] let reversedOrderDescription = FileTypesOrderRule.description @@ -108,7 +108,7 @@ final class FileTypesOrderRuleTests: SwiftLintTestCase { extension TestViewController: UITableViewDelegate { func someMethod() {} } - """) + """), ] let triggeringExamples = [ Example(""" @@ -132,7 +132,7 @@ final class FileTypesOrderRuleTests: SwiftLintTestCase { } class TestViewController: UIViewController {} - """) + """), ] let groupedOrderDescription = FileTypesOrderRule.description diff --git a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift index 73e5eea7c7..1f97099a70 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift @@ -19,11 +19,17 @@ final class FunctionBodyLengthRuleTests: SwiftLintTestCase { XCTAssertEqual(self.violations(longFunctionBody), []) let longerFunctionBody = violatingFuncWithBody(repeatElement("x = 0\n", count: 51).joined()) - XCTAssertEqual(self.violations(longerFunctionBody), [StyleViolation( - ruleDescription: FunctionBodyLengthRule.description, - location: Location(file: nil, line: 1, character: 6), - reason: "Function body should span 50 lines or less excluding comments and " + - "whitespace: currently spans 51 lines")]) + XCTAssertEqual( + self.violations(longerFunctionBody), + [ + StyleViolation( + ruleDescription: FunctionBodyLengthRule.description, + location: Location(file: nil, line: 1, character: 6), + reason: "Function body should span 50 lines or less excluding comments and " + + "whitespace: currently spans 51 lines" + ), + ] + ) let longerFunctionBodyWithEmptyLines = funcWithBody( repeatElement("\n", count: 100).joined() @@ -42,11 +48,17 @@ final class FunctionBodyLengthRuleTests: SwiftLintTestCase { repeatElement("x = 0\n", count: 51).joined() + "// comment only line should be ignored.\n" ) - XCTAssertEqual(self.violations(longerFunctionBodyWithComments), [StyleViolation( - ruleDescription: FunctionBodyLengthRule.description, - location: Location(file: nil, line: 1, character: 6), - reason: "Function body should span 50 lines or less excluding comments and " + - "whitespace: currently spans 51 lines")]) + XCTAssertEqual( + self.violations(longerFunctionBodyWithComments), + [ + StyleViolation( + ruleDescription: FunctionBodyLengthRule.description, + location: Location(file: nil, line: 1, character: 6), + reason: "Function body should span 50 lines or less excluding comments and " + + "whitespace: currently spans 51 lines" + ), + ] + ) } func testFunctionBodyLengthsWithMultilineComments() { @@ -60,11 +72,17 @@ final class FunctionBodyLengthRuleTests: SwiftLintTestCase { repeatElement("x = 0\n", count: 51).joined() + "/* multi line comment only line should be ignored.\n*/\n" ) - XCTAssertEqual(self.violations(longerFunctionBodyWithMultilineComments), [StyleViolation( - ruleDescription: FunctionBodyLengthRule.description, - location: Location(file: nil, line: 1, character: 6), - reason: "Function body should span 50 lines or less excluding comments and " + - "whitespace: currently spans 51 lines")]) + XCTAssertEqual( + self.violations(longerFunctionBodyWithMultilineComments), + [ + StyleViolation( + ruleDescription: FunctionBodyLengthRule.description, + location: Location(file: nil, line: 1, character: 6), + reason: "Function body should span 50 lines or less excluding comments and " + + "whitespace: currently spans 51 lines" + ), + ] + ) } func testConfiguration() { diff --git a/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift index 51c4a807af..8473e98a8f 100644 --- a/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/GenericTypeNameRuleTests.swift @@ -6,11 +6,11 @@ final class GenericTypeNameRuleTests: SwiftLintTestCase { let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ Example("func foo {}"), Example("func foo {}"), - Example("func foo {}") + Example("func foo {}"), ] let triggeringExamples = baseDescription.triggeringExamples + [ Example("func foo {}"), - Example("func foo {}") + Example("func foo {}"), ] let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples, triggeringExamples: triggeringExamples) @@ -25,7 +25,7 @@ final class GenericTypeNameRuleTests: SwiftLintTestCase { Example("typealias StringDictionary = Dictionary"), Example("class Foo {}"), Example("struct Foo {}"), - Example("enum Foo {}") + Example("enum Foo {}"), ] let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) @@ -48,7 +48,7 @@ final class GenericTypeNameRuleTests: SwiftLintTestCase { Example("func foo<↓type>() {}"), Example("class Foo<↓type> {}"), Example("struct Foo<↓type> {}"), - Example("enum Foo<↓type> {}") + Example("enum Foo<↓type> {}"), ] let nonTriggeringExamples = baseDescription.nonTriggeringExamples + triggeringExamplesToRemove.removingViolationMarkers() diff --git a/Tests/SwiftLintFrameworkTests/GlobTests.swift b/Tests/SwiftLintFrameworkTests/GlobTests.swift index 17f7f5f6e6..2cb5fb1a45 100644 --- a/Tests/SwiftLintFrameworkTests/GlobTests.swift +++ b/Tests/SwiftLintFrameworkTests/GlobTests.swift @@ -53,7 +53,7 @@ final class GlobTests: SwiftLintTestCase { func testMatchesMultipleFiles() { let expectedFiles: Set = [ mockPath.stringByAppendingPathComponent("Level0.swift"), - mockPath.stringByAppendingPathComponent("Directory.swift") + mockPath.stringByAppendingPathComponent("Directory.swift"), ] let files = Glob.resolveGlob(mockPath.stringByAppendingPathComponent("*.swift")) @@ -75,7 +75,7 @@ final class GlobTests: SwiftLintTestCase { "Level1/Level2/Level2.swift", "Level1/Level2/Level3/Level3.swift", "NestedConfig/Test/Main.swift", - "NestedConfig/Test/Sub/Sub.swift" + "NestedConfig/Test/Sub/Sub.swift", ].map(mockPath.stringByAppendingPathComponent) ) diff --git a/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift index 2c4a073fcf..324d4d197e 100644 --- a/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/IdentifierNameRuleTests.swift @@ -7,11 +7,11 @@ final class IdentifierNameRuleTests: SwiftLintTestCase { let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ Example("let Apple = 0"), Example("let some_apple = 0"), - Example("let Test123 = 0") + Example("let Test123 = 0"), ] let triggeringExamples = baseDescription.triggeringExamples + [ Example("let ap_ple = 0"), - Example("let AppleJuice = 0") + Example("let AppleJuice = 0"), ] let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples, triggeringExamples: triggeringExamples) @@ -24,7 +24,7 @@ final class IdentifierNameRuleTests: SwiftLintTestCase { Example("let myLet$ = 0"), Example("let myLet% = 0"), Example("let myLet$% = 0"), - Example("let _myLet = 0") + Example("let _myLet = 0"), ] let triggeringExamples = baseDescription.triggeringExamples.filter { !$0.code.contains("_") } let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples, @@ -51,7 +51,7 @@ final class IdentifierNameRuleTests: SwiftLintTestCase { Example("class C { class let ↓MyLet = 0 }"), Example("class C { static func ↓MyFunc() {} }"), Example("class C { class func ↓MyFunc() {} }"), - Example("func ↓√ (arg: Double) -> Double { arg }") + Example("func ↓√ (arg: Double) -> Double { arg }"), ] let nonTriggeringExamples = baseDescription.nonTriggeringExamples + triggeringExamplesToRemove.removingViolationMarkers() @@ -68,12 +68,12 @@ final class IdentifierNameRuleTests: SwiftLintTestCase { let triggeringExamples = [ Example("let ↓MyLet = 0"), Example("enum Foo { case ↓MyCase }"), - Example("func ↓IsOperator(name: String) -> Bool { true }") + Example("func ↓IsOperator(name: String) -> Bool { true }"), ] let nonTriggeringExamples = [ Example("let myLet = 0"), Example("enum Foo { case myCase }"), - Example("func isOperator(name: String) -> Bool { true }") + Example("func isOperator(name: String) -> Bool { true }"), ] verifyRule( @@ -99,11 +99,11 @@ final class IdentifierNameRuleTests: SwiftLintTestCase { ]) .with(nonTriggeringExamples: [ Example("let MyLet = 0"), - Example("enum Foo { case myCase }") + Example("enum Foo { case myCase }"), ]), ruleConfiguration: [ "validates_start_with_lowercase": true, - "allowed_symbols": ["M"] + "allowed_symbols": ["M"], ] as [String: any Sendable] ) } diff --git a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift index b1fd2c08b1..c6a62deca1 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift @@ -11,8 +11,8 @@ final class ImplicitReturnConfigurationTests: SwiftLintTestCase { "function", "getter", "initializer", - "subscript" - ] + "subscript", + ], ] try configuration.apply(configuration: config) @@ -21,7 +21,7 @@ final class ImplicitReturnConfigurationTests: SwiftLintTestCase { .function, .getter, .initializer, - .subscript + .subscript, ]) XCTAssertEqual(configuration.severityConfiguration.severity, .error) XCTAssertEqual(configuration.includedKinds, expectedKinds) diff --git a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift index 53769d4f24..6dca068e61 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift @@ -30,7 +30,7 @@ final class ImplicitlyUnwrappedOptionalConfigurationTests: SwiftLintTestCase { let badConfigs: [[String: Any]] = [ ["mode": "everything"], ["mode": false], - ["mode": 42] + ["mode": 42], ] for badConfig in badConfigs { diff --git a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift index d1fd9f15ae..4d677b5bc2 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalRuleTests.swift @@ -13,7 +13,7 @@ final class ImplicitlyUnwrappedOptionalRuleTests: SwiftLintTestCase { let triggeringExamples = [ Example("@IBOutlet private var label: UILabel!"), Example("@IBOutlet var label: UILabel!"), - Example("let int: Int!") + Example("let int: Int!"), ] let nonTriggeringExamples = [Example("if !boolean {}")] @@ -29,7 +29,7 @@ final class ImplicitlyUnwrappedOptionalRuleTests: SwiftLintTestCase { let triggeringExamples = [ Example("private weak var label: ↓UILabel!"), Example("weak var label: ↓UILabel!"), - Example("@objc weak var label: ↓UILabel!") + Example("@objc weak var label: ↓UILabel!"), ] let nonTriggeringExamples = [ @@ -37,7 +37,7 @@ final class ImplicitlyUnwrappedOptionalRuleTests: SwiftLintTestCase { Example("@IBOutlet var label: UILabel!"), Example("@IBOutlet weak var label: UILabel!"), Example("var label: UILabel!"), - Example("let int: Int!") + Example("let int: Int!"), ] let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) diff --git a/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift index b29037d14a..01b59c8c9d 100644 --- a/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift @@ -79,7 +79,7 @@ final class LineLengthConfigurationTests: SwiftLintTestCase { func testLineLengthConfigurationThrowsOnBadConfigValues() { let badConfigs: [[String: Any]] = [ ["warning": true], - ["ignores_function_declarations": 300] + ["ignores_function_declarations": 300], ] for badConfig in badConfigs { @@ -119,11 +119,13 @@ final class LineLengthConfigurationTests: SwiftLintTestCase { let warning1 = 100 let error1 = 100 let length1 = SeverityLevelsConfiguration(warning: warning1, error: error1) - let config1: [String: Any] = ["warning": warning1, - "error": error1, - "ignores_urls": true, - "ignores_function_declarations": true, - "ignores_comments": true] + let config1: [String: Any] = [ + "warning": warning1, + "error": error1, + "ignores_urls": true, + "ignores_function_declarations": true, + "ignores_comments": true, + ] let warning2 = 200 let error2 = 200 @@ -131,9 +133,11 @@ final class LineLengthConfigurationTests: SwiftLintTestCase { let config2: [String: Int] = ["warning": warning2, "error": error2] let length3 = SeverityLevelsConfiguration(warning: warning2) - let config3: [String: Bool] = ["ignores_urls": false, - "ignores_function_declarations": false, - "ignores_comments": false] + let config3: [String: Bool] = [ + "ignores_urls": false, + "ignores_function_declarations": false, + "ignores_comments": false, + ] do { try configuration.apply(configuration: config1) diff --git a/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift index e3d157293a..497ce3b6af 100644 --- a/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/LineLengthRuleTests.swift @@ -11,7 +11,7 @@ final class LineLengthRuleTests: SwiftLintTestCase { "c: String, d: String, e: String, f: String, g: String, h: String, i: String, " + "j: String, k: String, l: String, m: String, n: String, o: String, p: String, " + "q: String, r: String, s: String, t: String, u: String, v: String, w: String, " + - "x: String, y: String, z: String) {\n") + "x: String, y: String, z: String) {\n"), ] private let longComment = Example(String(repeating: "/", count: 121) + "\n") @@ -50,7 +50,7 @@ final class LineLengthRuleTests: SwiftLintTestCase { let triggeringLines = [Example(String(repeating: "/", count: 121) + "\(url)\n")] let nonTriggeringLines = [ Example("\(url) " + String(repeating: "/", count: 118) + " \(url)\n"), - Example("\(url)/" + String(repeating: "a", count: 120)) + Example("\(url)/" + String(repeating: "a", count: 120)), ] let baseDescription = LineLengthRule.description diff --git a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift index b6426186ed..18fde17fb3 100644 --- a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift +++ b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift @@ -31,7 +31,7 @@ private struct CacheTestHelper { StyleViolation(ruleDescription: ruleDescription, severity: .error, location: Location(file: file, line: 5, character: nil), - reason: "Something is wrong") + reason: "Something is wrong"), ] } @@ -195,7 +195,7 @@ final class LinterCacheTests: SwiftLintTestCase { let initialConfig = try Configuration( dict: [ "only_rules": ["custom_rules", "rule1"], - "custom_rules": ["rule1": ["regex": "([n,N]inja)"]] + "custom_rules": ["rule1": ["regex": "([n,N]inja)"]], ], ruleList: RuleList(rules: CustomRules.self) ) @@ -205,7 +205,7 @@ final class LinterCacheTests: SwiftLintTestCase { try validateNewConfigDoesntHitCache( dict: [ "only_rules": ["custom_rules", "rule1"], - "custom_rules": ["rule1": ["regex": "([n,N]injas)"]] + "custom_rules": ["rule1": ["regex": "([n,N]injas)"]], ], initialConfig: initialConfig ) @@ -214,7 +214,7 @@ final class LinterCacheTests: SwiftLintTestCase { try validateNewConfigDoesntHitCache( dict: [ "only_rules": ["custom_rules", "rule1"], - "custom_rules": ["rule1": ["regex": "([n,N]injas)"], "rule2": ["regex": "([k,K]ittens)"]] + "custom_rules": ["rule1": ["regex": "([n,N]injas)"], "rule2": ["regex": "([k,K]ittens)"]], ], initialConfig: initialConfig ) diff --git a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift index c7db1cc89f..39dc029ad1 100644 --- a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift @@ -50,8 +50,11 @@ final class MissingDocsRuleTests: SwiftLintTestCase { func testDescriptionMultipleSeverities() { let configuration = MissingDocsConfiguration( - parameters: [RuleParameter(severity: .error, value: .open), - RuleParameter(severity: .warning, value: .public)]) + parameters: [ + RuleParameter(severity: .error, value: .open), + RuleParameter(severity: .warning, value: .public), + ] + ) XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "error: [open]; warning: [public]; excludes_extensions: true; " + @@ -61,8 +64,11 @@ final class MissingDocsRuleTests: SwiftLintTestCase { func testDescriptionMultipleAcls() { let configuration = MissingDocsConfiguration( - parameters: [RuleParameter(severity: .warning, value: .open), - RuleParameter(severity: .warning, value: .public)]) + parameters: [ + RuleParameter(severity: .warning, value: .open), + RuleParameter(severity: .warning, value: .public), + ] + ) XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "warning: [open, public]; excludes_extensions: true; " + @@ -93,8 +99,10 @@ final class MissingDocsRuleTests: SwiftLintTestCase { try? configuration.apply(configuration: ["warning": "public", "error": "open"]) XCTAssertEqual( configuration.parameters.sorted { $0.value.rawValue > $1.value.rawValue }, - [RuleParameter(severity: .warning, value: .public), - RuleParameter(severity: .error, value: .open)] + [ + RuleParameter(severity: .warning, value: .public), + RuleParameter(severity: .error, value: .open), + ] ) } @@ -103,8 +111,10 @@ final class MissingDocsRuleTests: SwiftLintTestCase { try? configuration.apply(configuration: ["warning": ["public", "open"]]) XCTAssertEqual( configuration.parameters.sorted { $0.value.rawValue > $1.value.rawValue }, - [RuleParameter(severity: .warning, value: .public), - RuleParameter(severity: .warning, value: .open)] + [ + RuleParameter(severity: .warning, value: .public), + RuleParameter(severity: .warning, value: .open), + ] ) XCTAssertTrue(configuration.excludesExtensions) XCTAssertTrue(configuration.excludesInheritedTypes) @@ -122,8 +132,10 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertTrue(configuration.excludesInheritedTypes) XCTAssertEqual( configuration.parameters.sorted { $0.value.rawValue > $1.value.rawValue }, - [RuleParameter(severity: .warning, value: .public), - RuleParameter(severity: .warning, value: .open)] + [ + RuleParameter(severity: .warning, value: .public), + RuleParameter(severity: .warning, value: .open), + ] ) } @@ -141,8 +153,10 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertFalse(configuration.excludesInheritedTypes) XCTAssertEqual( configuration.parameters.sorted { $0.value.rawValue > $1.value.rawValue }, - [RuleParameter(severity: .warning, value: .public), - RuleParameter(severity: .warning, value: .open)] + [ + RuleParameter(severity: .warning, value: .public), + RuleParameter(severity: .warning, value: .open), + ] ) } @@ -153,8 +167,10 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertTrue(configuration.excludesInheritedTypes) XCTAssertEqual( configuration.parameters.sorted { $0.value.rawValue > $1.value.rawValue }, - [RuleParameter(severity: .warning, value: .public), - RuleParameter(severity: .warning, value: .open)] + [ + RuleParameter(severity: .warning, value: .public), + RuleParameter(severity: .warning, value: .open), + ] ) } @@ -165,8 +181,9 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertFalse(configuration.excludesInheritedTypes) XCTAssertEqual( configuration.parameters.sorted { $0.value.rawValue > $1.value.rawValue }, - [RuleParameter(severity: .warning, value: .public), - RuleParameter(severity: .warning, value: .open)] + [ RuleParameter(severity: .warning, value: .public), + RuleParameter(severity: .warning, value: .open), + ] ) } @@ -176,7 +193,7 @@ final class MissingDocsRuleTests: SwiftLintTestCase { configuration: [ "excludes_extensions": true, "excludes_inherited_types": false, - "error": ["public"] + "error": ["public"], ] as [String: any Sendable] ) @@ -191,12 +208,7 @@ final class MissingDocsRuleTests: SwiftLintTestCase { func testWithExcludesExtensionsDisabled() { // Perform additional tests with the ignores_comments settings disabled. let baseDescription = MissingDocsRule.description - let triggeringComments = [ - Example(""" - public extension A {} - """ - ) - ] + let triggeringComments = [Example("public extension A {}")] let nonTriggeringExamples = baseDescription.nonTriggeringExamples .filter { !triggeringComments.contains($0) } let triggeringExamples = baseDescription.triggeringExamples + triggeringComments @@ -228,7 +240,7 @@ final class MissingDocsRuleTests: SwiftLintTestCase { public class B: NSObject { // no docs override public var description: String { fatalError() } } - """) + """), ] let nonTriggeringExamples = baseDescription.nonTriggeringExamples .filter { !triggeringComments.contains($0) } diff --git a/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift b/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift index 68ba5658dc..4df00865d1 100644 --- a/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift +++ b/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift @@ -14,7 +14,7 @@ final class ModifierOrderTests: SwiftLintTestCase { public class SomeClass { static public func someFunc() {} } - """) + """), ]) .with(triggeringExamples: [ Example(""" @@ -26,7 +26,7 @@ final class ModifierOrderTests: SwiftLintTestCase { public class SomeClass { public static func someFunc() {} } - """) + """), ]) .with(corrections: [:]) @@ -43,7 +43,7 @@ final class ModifierOrderTests: SwiftLintTestCase { " fileprivate static func bar() {} \n" + " open class func barFoo() {} }"), Example("public struct Foo {" + - " private mutating func bar() {} }") + " private mutating func bar() {} }"), ]) .with(triggeringExamples: [ Example("public protocol Foo: class {} \n" + @@ -52,18 +52,24 @@ final class ModifierOrderTests: SwiftLintTestCase { " static fileprivate func bar() {} \n" + " class open func barFoo() {} }"), Example("public struct Foo {" + - " mutating private func bar() {} }") + " mutating private func bar() {} }"), ]) .with(corrections: [:]) - verifyRule(descriptionOverride, - ruleConfiguration: ["preferred_modifier_order": ["acl", - "typeMethods", - "owned", - "setterACL", - "final", - "mutators", - "override"]]) + verifyRule( + descriptionOverride, + ruleConfiguration: [ + "preferred_modifier_order": [ + "acl", + "typeMethods", + "owned", + "setterACL", + "final", + "mutators", + "override", + ], + ] + ) } // swiftlint:disable:next function_body_length @@ -112,7 +118,7 @@ final class ModifierOrderTests: SwiftLintTestCase { public class Foo { @NSCopying public final var foo: NSString } - """#) + """#), ]) .with(triggeringExamples: [ Example(#""" @@ -156,7 +162,7 @@ final class ModifierOrderTests: SwiftLintTestCase { public class Foo { @NSManaged final public var foo: NSString } - """) + """), ]) .with(corrections: [:]) @@ -186,7 +192,7 @@ final class ModifierOrderTests: SwiftLintTestCase { class Foo { final override private weak var bar: UIView? } - """) + """), ]) .with(triggeringExamples: [ Example(""" @@ -208,7 +214,7 @@ final class ModifierOrderTests: SwiftLintTestCase { class Foo { override final private weak var bar: UIView? } - """) + """), ]) .with(corrections: [:]) @@ -276,7 +282,7 @@ final class ModifierOrderTests: SwiftLintTestCase { """): Example(""" final private class Foo {} - """) + """), ]) verifyRule(descriptionOverride, @@ -347,7 +353,7 @@ final class ModifierOrderTests: SwiftLintTestCase { class Foo { var bar: UIView? } - """) + """), ]) verifyRule(descriptionOverride, @@ -369,7 +375,7 @@ final class ModifierOrderTests: SwiftLintTestCase { """): Example(""" public protocol Foo: class {}\n - """) + """), ]) verifyRule(descriptionOverride, diff --git a/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift b/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift index 37653d9409..2f66f76dbc 100644 --- a/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/MultilineArgumentsRuleTests.swift @@ -11,12 +11,12 @@ final class MultilineArgumentsRuleTests: SwiftLintTestCase { " 3,\n" + " bar: baz) { }"), Example("foo(\n" + - " 4, bar: baz) { }") + " 4, bar: baz) { }"), ] let triggeringExamples = [ Example("foo(↓1,\n" + - " bar: baz) { }") + " bar: baz) { }"), ] let description = MultilineArgumentsRule.description @@ -35,7 +35,7 @@ final class MultilineArgumentsRuleTests: SwiftLintTestCase { " bar()\n" + "}"), Example("foo(3,\n" + - " bar: 3) { }") + " bar: 3) { }"), ] let triggeringExamples = [ @@ -43,7 +43,7 @@ final class MultilineArgumentsRuleTests: SwiftLintTestCase { " ↓1, ↓bar: baz) { }"), Example("foo(\n" + " ↓2,\n" + - " bar: baz) { }") + " bar: baz) { }"), ] let description = MultilineArgumentsRule.description @@ -76,7 +76,7 @@ final class MultilineArgumentsRuleTests: SwiftLintTestCase { "})"), Example("foo(a: a, b: { [weak self] in\n" + "}, c: { flag in\n" + - "})") + "})"), ] let triggeringExamples = [ @@ -86,7 +86,7 @@ final class MultilineArgumentsRuleTests: SwiftLintTestCase { Example("foo(a: a, b: b,\n" + " c: c, d: {\n" + " }, d: {\n" + - "})") + "})"), ] let description = MultilineArgumentsRule.description diff --git a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift index 906ca47a43..9f7fac7979 100644 --- a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift @@ -5,11 +5,13 @@ final class NameConfigurationTests: SwiftLintTestCase { typealias TesteeType = NameConfiguration func testNameConfigurationSetsCorrectly() { - let config = [ "min_length": ["warning": 17, "error": 7], - "max_length": ["warning": 170, "error": 700], - "excluded": "id", - "allowed_symbols": ["$"], - "validates_start_with_lowercase": "warning"] as [String: any Sendable] + let config: [String: any Sendable] = [ + "min_length": ["warning": 17, "error": 7], + "max_length": ["warning": 170, "error": 700], + "excluded": "id", + "allowed_symbols": ["$"], + "validates_start_with_lowercase": "warning", + ] var nameConfig = TesteeType(minLengthWarning: 0, minLengthError: 0, maxLengthWarning: 0, diff --git a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift index 2df7ba3901..83a3c2db67 100644 --- a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift @@ -41,7 +41,7 @@ final class NestingRuleTests: SwiftLintTestCase { \(type) Example_1 {} } } - """) + """), ] }) nonTriggeringExamples.append(contentsOf: detectingTypes.flatMap { type -> [Example] in @@ -92,7 +92,7 @@ final class NestingRuleTests: SwiftLintTestCase { } } } - """) + """), ] }) @@ -134,7 +134,7 @@ final class NestingRuleTests: SwiftLintTestCase { } } } - """) + """), ] } @@ -194,7 +194,7 @@ final class NestingRuleTests: SwiftLintTestCase { } } } - """) + """), ] }) @@ -382,7 +382,7 @@ final class NestingRuleTests: SwiftLintTestCase { } } } - """) + """), ] }) @@ -440,7 +440,7 @@ final class NestingRuleTests: SwiftLintTestCase { } } } - """) + """), ] } @@ -492,7 +492,7 @@ final class NestingRuleTests: SwiftLintTestCase { } } } - """) + """), ]) let description = RuleDescription( @@ -543,7 +543,7 @@ final class NestingRuleTests: SwiftLintTestCase { typealias AssociatedType = Int } } - """) + """), ] }) diff --git a/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift b/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift index de6c3869d5..e80d93b639 100644 --- a/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/NumberSeparatorRuleTests.swift @@ -9,17 +9,17 @@ final class NumberSeparatorRuleTests: SwiftLintTestCase { Example("let foo = 1000"), Example("let foo = 1000.0001"), Example("let foo = 10_000.0001"), - Example("let foo = 1000.00001") + Example("let foo = 1000.00001"), ] let triggeringExamples = [ Example("let foo = ↓1_000"), Example("let foo = ↓1.000_1"), - Example("let foo = ↓1_000.000_1") + Example("let foo = ↓1_000.000_1"), ] let corrections = [ Example("let foo = ↓1_000"): Example("let foo = 1000"), Example("let foo = ↓1.000_1"): Example("let foo = 1.0001"), - Example("let foo = ↓1_000.000_1"): Example("let foo = 1000.0001") + Example("let foo = ↓1_000.000_1"): Example("let foo = 1000.0001"), ] let description = NumberSeparatorRule.description @@ -35,17 +35,17 @@ final class NumberSeparatorRuleTests: SwiftLintTestCase { Example("let foo = 1_000.000_000_1"), Example("let foo = 1.000_001"), Example("let foo = 100.0001"), - Example("let foo = 1_000.000_01") + Example("let foo = 1_000.000_01"), ] let triggeringExamples = [ Example("let foo = ↓1000"), Example("let foo = ↓1.000_1"), - Example("let foo = ↓1_000.000_1") + Example("let foo = ↓1_000.000_1"), ] let corrections = [ Example("let foo = ↓1000"): Example("let foo = 1_000"), Example("let foo = ↓1.000_1"): Example("let foo = 1.0001"), - Example("let foo = ↓1_000.000_1"): Example("let foo = 1_000.0001") + Example("let foo = ↓1_000.000_1"): Example("let foo = 1_000.0001"), ] let description = NumberSeparatorRule.description @@ -67,19 +67,19 @@ final class NumberSeparatorRuleTests: SwiftLintTestCase { Example("let foo = 2.10042"), Example("let foo = 2.100_42"), Example("let foo = 2.833333"), - Example("let foo = 2.833_333") + Example("let foo = 2.833_333"), ] let triggeringExamples = [ Example("let foo = ↓1000"), Example("let foo = ↓2100"), Example("let foo = ↓1.920442"), - Example("let foo = ↓3.343434") + Example("let foo = ↓3.343434"), ] let corrections = [ Example("let foo = ↓1000"): Example("let foo = 1_000"), Example("let foo = ↓2100"): Example("let foo = 2_100"), Example("let foo = ↓1.920442"): Example("let foo = 1.920_442"), - Example("let foo = ↓3.343434"): Example("let foo = 3.343_434") + Example("let foo = ↓3.343434"): Example("let foo = 3.343_434"), ] let description = NumberSeparatorRule.description @@ -92,9 +92,9 @@ final class NumberSeparatorRuleTests: SwiftLintTestCase { ruleConfiguration: [ "exclude_ranges": [ ["min": 1900, "max": 2030], - ["min": 2.0, "max": 3.0] + ["min": 2.0, "max": 3.0], ] as Any, - "minimum_fraction_length": 3 + "minimum_fraction_length": 3, ] as Any ) } diff --git a/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift b/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift index 04d1be52d7..61e5e7767e 100644 --- a/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift @@ -15,7 +15,7 @@ final class ObjectLiteralRuleTests: SwiftLintTestCase { [ Example("let color = ↓\(prefix)Color\(method)(red: 0.3, green: 0.3, blue: 0.3, alpha: 1)"), Example("let color = ↓\(prefix)Color\(method)(red: 100 / 255.0, green: 50 / 255.0, blue: 0, alpha: 1)"), - Example("let color = ↓\(prefix)Color\(method)(white: 0.5, alpha: 1)") + Example("let color = ↓\(prefix)Color\(method)(white: 0.5, alpha: 1)"), ] } } diff --git a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift index 360a15d216..afbf8cf29c 100644 --- a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift @@ -12,7 +12,7 @@ final class OpeningBraceRuleTests: SwiftLintTestCase { return _swift_stdlib_threadLocalStorageGet().assumingMemoryBound( to: _ThreadLocalStorage.self) } - """) + """), ])) verifyRule(description, ruleConfiguration: ["allow_multiline_func": true]) @@ -50,7 +50,7 @@ final class OpeningBraceRuleTests: SwiftLintTestCase { } } - """) + """), ] let triggeringExamples = [ @@ -79,7 +79,7 @@ final class OpeningBraceRuleTests: SwiftLintTestCase { } } - """) + """), ] let description = OpeningBraceRule.description diff --git a/Tests/SwiftLintFrameworkTests/PrefixedTopLevelConstantRuleTests.swift b/Tests/SwiftLintFrameworkTests/PrefixedTopLevelConstantRuleTests.swift index 5509fc3bd4..d2102a6db2 100644 --- a/Tests/SwiftLintFrameworkTests/PrefixedTopLevelConstantRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/PrefixedTopLevelConstantRuleTests.swift @@ -4,12 +4,12 @@ final class PrefixedTopLevelConstantRuleTests: SwiftLintTestCase { func testPrivateOnly() { let triggeringExamples = [ Example("private let ↓Foo = 20.0"), - Example("fileprivate let ↓foo = 20.0") + Example("fileprivate let ↓foo = 20.0"), ] let nonTriggeringExamples = [ Example("let Foo = 20.0"), Example("internal let Foo = \"Foo\""), - Example("public let Foo = 20.0") + Example("public let Foo = 20.0"), ] let description = PrefixedTopLevelConstantRule.description diff --git a/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift b/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift index c8405b87a6..56a97267ef 100644 --- a/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/PrivateOverFilePrivateRuleTests.swift @@ -6,12 +6,12 @@ final class PrivateOverFilePrivateRuleTests: SwiftLintTestCase { let triggeringExamples = baseDescription.triggeringExamples + [ Example("↓fileprivate extension String {}"), Example("↓fileprivate \n extension String {}"), - Example("↓fileprivate extension \n String {}") + Example("↓fileprivate extension \n String {}"), ] let corrections = [ Example("↓fileprivate extension String {}"): Example("private extension String {}"), Example("↓fileprivate \n extension String {}"): Example("private \n extension String {}"), - Example("↓fileprivate extension \n String {}"): Example("private extension \n String {}") + Example("↓fileprivate extension \n String {}"): Example("private extension \n String {}"), ] let description = baseDescription.with(nonTriggeringExamples: []) diff --git a/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift index 666b5ca79b..5da2c08750 100644 --- a/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RegexConfigurationTests.swift @@ -11,7 +11,7 @@ final class RegexConfigurationTests: SwiftLintTestCase { var config = RegexConfiguration(identifier: "example") try config.apply(configuration: [ "regex": "try!", - "excluded": "Tests/.*\\.swift" + "excluded": "Tests/.*\\.swift", ]) XCTAssertFalse(config.shouldValidate(filePath: "Tests/file.swift")) @@ -24,8 +24,8 @@ final class RegexConfigurationTests: SwiftLintTestCase { "regex": "try!", "excluded": [ "^Tests/.*\\.swift", - "^MyFramework/Tests/.*\\.swift" - ] as Any + "^MyFramework/Tests/.*\\.swift", + ] as Any, ]) XCTAssertFalse(config.shouldValidate(filePath: "Tests/file.swift")) @@ -37,7 +37,7 @@ final class RegexConfigurationTests: SwiftLintTestCase { var config = RegexConfiguration(identifier: "example") try config.apply(configuration: [ "regex": "try!", - "included": "App/.*\\.swift" + "included": "App/.*\\.swift", ]) XCTAssertFalse(config.shouldValidate(filePath: "Tests/file.swift")) @@ -51,8 +51,8 @@ final class RegexConfigurationTests: SwiftLintTestCase { "regex": "try!", "included": [ "App/.*\\.swift", - "MyFramework/.*\\.swift" - ] as Any + "MyFramework/.*\\.swift", + ] as Any, ]) XCTAssertFalse(config.shouldValidate(filePath: "Tests/file.swift")) @@ -66,12 +66,12 @@ final class RegexConfigurationTests: SwiftLintTestCase { "regex": "try!", "included": [ "App/.*\\.swift", - "MyFramework/.*\\.swift" + "MyFramework/.*\\.swift", ] as Any, "excluded": [ "Tests/.*\\.swift", - "App/Fixtures/.*\\.swift" - ] as Any + "App/Fixtures/.*\\.swift", + ] as Any, ]) XCTAssertTrue(config.shouldValidate(filePath: "App/file.swift")) diff --git a/Tests/SwiftLintFrameworkTests/RegionTests.swift b/Tests/SwiftLintFrameworkTests/RegionTests.swift index 7b4732543b..3935f583c7 100644 --- a/Tests/SwiftLintFrameworkTests/RegionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RegionTests.swift @@ -41,7 +41,7 @@ final class RegionTests: SwiftLintTestCase { disabledRuleIdentifiers: ["rule_id"]), Region(start: Location(file: nil, line: 2, character: 28), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: []) + disabledRuleIdentifiers: []), ]) } // enable/disable @@ -53,7 +53,7 @@ final class RegionTests: SwiftLintTestCase { disabledRuleIdentifiers: []), Region(start: Location(file: nil, line: 2, character: 29), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: ["rule_id"]) + disabledRuleIdentifiers: ["rule_id"]), ]) } } @@ -68,7 +68,7 @@ final class RegionTests: SwiftLintTestCase { disabledRuleIdentifiers: ["1", "2", "3"]), Region(start: Location(file: nil, line: 2, character: .max), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: []) + disabledRuleIdentifiers: []), ]) } @@ -97,7 +97,7 @@ final class RegionTests: SwiftLintTestCase { disabledRuleIdentifiers: ["3"]), Region(start: Location(file: nil, line: 6, character: 22), end: Location(file: nil, line: .max, character: .max), - disabledRuleIdentifiers: []) + disabledRuleIdentifiers: []), ]) } } diff --git a/Tests/SwiftLintFrameworkTests/ReporterTests.swift b/Tests/SwiftLintFrameworkTests/ReporterTests.swift index 9aaed87757..48cd296309 100644 --- a/Tests/SwiftLintFrameworkTests/ReporterTests.swift +++ b/Tests/SwiftLintFrameworkTests/ReporterTests.swift @@ -33,7 +33,7 @@ final class ReporterTests: SwiftLintTestCase { StyleViolation(ruleDescription: ColonRule.description, severity: .error, location: Location(file: nil), - reason: nil) + reason: nil), ] } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index 886537167b..5aa422a442 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -472,7 +472,7 @@ final class RuleConfigurationDescriptionTests: XCTestCase { "set": [4, 5, 6], "SEVERITY": "error", "warning": 12, - "levels": ["warning": 6, "error": 7] + "levels": ["warning": 6, "error": 7], ]) XCTAssertFalse(configuration.flag) @@ -508,7 +508,7 @@ final class RuleConfigurationDescriptionTests: XCTestCase { "severity": "error", "warning": 3, "unknown": 1, - "unsupported": true + "unsupported": true, ]) }, """ diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift index 8937c2df9a..db0a56ddb9 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift @@ -18,7 +18,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { "warning": 8, "error": 18 ], "check_nesting_in_closures_and_statements": false, - "always_allow_one_type_in_functions": true + "always_allow_one_type_in_functions": true, ] as [String: any Sendable] var nestingConfig = defaultNestingConfiguration do { @@ -91,8 +91,10 @@ final class RuleConfigurationTests: SwiftLintTestCase { func testSeverityLevelConfigParams() { let severityConfig = SeverityLevelsConfiguration(warning: 17, error: 7) - XCTAssertEqual(severityConfig.params, [RuleParameter(severity: .error, value: 7), - RuleParameter(severity: .warning, value: 17)]) + XCTAssertEqual( + severityConfig.params, + [RuleParameter(severity: .error, value: 7), RuleParameter(severity: .warning, value: 17)] + ) } func testSeverityLevelConfigPartialParams() { @@ -247,7 +249,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { let conf2 = [ "severity": "error", "excluded": "viewWillAppear(_:)", - "included": ["*", "testMethod1()", "testMethod2(_:)"] + "included": ["*", "testMethod1()", "testMethod2(_:)"], ] as [String: any Sendable] do { try configuration.apply(configuration: conf2) @@ -264,7 +266,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { let conf3 = [ "severity": "warning", "excluded": "*", - "included": ["testMethod1()", "testMethod2(_:)"] + "included": ["testMethod1()", "testMethod2(_:)"], ] as [String: any Sendable] do { try configuration.apply(configuration: conf3) @@ -293,8 +295,8 @@ final class RuleConfigurationTests: SwiftLintTestCase { "required", "convenience", "lazy", - "dynamic" - ] + "dynamic", + ], ] try configuration.apply(configuration: config) @@ -309,7 +311,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { .required, .convenience, .lazy, - .dynamic + .dynamic, ] XCTAssertEqual(configuration.severityConfiguration.severity, .warning) XCTAssertEqual(configuration.preferredModifierOrder, expected) diff --git a/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift index baedc7ad02..51ffc479ce 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingClosureConfigurationTests.swift @@ -10,8 +10,12 @@ final class TrailingClosureConfigurationTests: SwiftLintTestCase { func testApplyingCustomConfiguration() throws { var config = TrailingClosureConfiguration() - try config.apply(configuration: ["severity": "error", - "only_single_muted_parameter": true] as [String: any Sendable]) + try config.apply( + configuration: [ + "severity": "error", + "only_single_muted_parameter": true, + ] as [String: any Sendable] + ) XCTAssertEqual(config.severityConfiguration.severity, .error) XCTAssertTrue(config.onlySingleMutedParameter) } diff --git a/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift b/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift index 08698e087a..c50697287d 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingClosureRuleTests.swift @@ -7,7 +7,7 @@ final class TrailingClosureRuleTests: SwiftLintTestCase { .with(nonTriggeringExamples: originalDescription.nonTriggeringExamples + [ Example("foo.reduce(0, combine: { $0 + 1 })"), Example("offsets.sorted(by: { $0.offset < $1.offset })"), - Example("foo.something(0, { $0 + 1 })") + Example("foo.something(0, { $0 + 1 })"), ]) .with(triggeringExamples: [Example("foo.map(↓{ $0 + 1 })")]) .with(corrections: [ @@ -23,7 +23,7 @@ final class TrailingClosureRuleTests: SwiftLintTestCase { for n in list { n.forEach { print($0) } } - """) + """), ]) verifyRule(description, ruleConfiguration: ["only_single_muted_parameter": true]) diff --git a/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift b/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift index 00de1bec92..dc26b39ebb 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift @@ -21,7 +21,7 @@ final class TrailingCommaRuleTests: SwiftLintTestCase { Example("struct Bar {\n let foo = [1: 2,\n 2: 3↓]\n}\n"), Example("let foo = [1, 2,\n 3↓] + [4,\n 5, 6↓]\n"), Example("let foo = [1, 2,\n 3↓ ]"), - Example("let foo = [\"אבג\", \"αβγ\",\n\"🇺🇸\"↓]\n") + Example("let foo = [\"אבג\", \"αβγ\",\n\"🇺🇸\"↓]\n"), ] private static let nonTriggeringExamples = [ @@ -38,7 +38,7 @@ final class TrailingCommaRuleTests: SwiftLintTestCase { Example("let foo = [1: 2, 2: 3]\n"), Example("let foo = [1: 2, 2: 3 ]\n"), Example("struct Bar {\n let foo = [1: 2, 2: 3]\n}\n"), - Example("let foo = [1, 2, 3] + [4, 5, 6]\n") + Example("let foo = [1, 2, 3] + [4, 5, 6]\n"), ] private static let corrections: [Example: Example] = { diff --git a/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift index 1f02f6e8f6..6de8111141 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingWhitespaceRuleTests.swift @@ -17,7 +17,7 @@ final class TrailingWhitespaceRuleTests: SwiftLintTestCase { let baseDescription = TrailingWhitespaceRule.description let triggeringComments = [ Example("// \n"), - Example("let name: String // \n") + Example("let name: String // \n"), ] let nonTriggeringExamples = baseDescription.nonTriggeringExamples .filter { !triggeringComments.contains($0) } diff --git a/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift b/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift index 2c7a85a947..f79efb7ab9 100644 --- a/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TypeContentsOrderRuleTests.swift @@ -8,8 +8,8 @@ final class TypeContentsOrderRuleTests: SwiftLintTestCase { Example([ "class TestViewController: UIViewController {", TypeContentsOrderRuleExamples.defaultOrderParts.reversed().joined(separator: "\n\n"), - "}" - ].joined(separator: "\n")) + "}", + ].joined(separator: "\n")), ] let triggeringExamples = [ Example(""" @@ -133,7 +133,7 @@ final class TypeContentsOrderRuleTests: SwiftLintTestCase { } } } - """) + """), ] let reversedOrderDescription = TypeContentsOrderRule.description @@ -157,8 +157,8 @@ final class TypeContentsOrderRuleTests: SwiftLintTestCase { "type_property", "subtype", ["type_alias", "associated_type"], - "case" - ] as [Any] + "case", + ] as [Any], ] ) } @@ -278,7 +278,7 @@ final class TypeContentsOrderRuleTests: SwiftLintTestCase { hasLayoutedView2 = true } } - """) + """), ] let triggeringExamples = [ Example(""" @@ -329,7 +329,7 @@ final class TypeContentsOrderRuleTests: SwiftLintTestCase { // some code } } - """) + """), ] let groupedOrderDescription = TypeContentsOrderRule.description @@ -343,8 +343,8 @@ final class TypeContentsOrderRuleTests: SwiftLintTestCase { ["type_alias", "associated_type", "subtype"], ["type_property", "instance_property", "ib_inspectable", "ib_outlet"], ["initializer", "type_method", "deinitializer"], - ["view_life_cycle_method", "ib_action", "other_method", "subscript"] - ] + ["view_life_cycle_method", "ib_action", "other_method", "subscript"], + ], ] ) } diff --git a/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift index 73e66cd34e..2c8819a5ec 100644 --- a/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TypeNameRuleTests.swift @@ -6,11 +6,11 @@ final class TypeNameRuleTests: SwiftLintTestCase { let nonTriggeringExamples = baseDescription.nonTriggeringExamples + [ Example("class apple {}"), Example("struct some_apple {}"), - Example("protocol test123 {}") + Example("protocol test123 {}"), ] let triggeringExamples = baseDescription.triggeringExamples + [ Example("enum ap_ple {}"), - Example("typealias appleJuice = Void") + Example("typealias appleJuice = Void"), ] let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples, triggeringExamples: triggeringExamples) @@ -24,7 +24,7 @@ final class TypeNameRuleTests: SwiftLintTestCase { Example("struct MyType$ {}"), Example("enum MyType$ {}"), Example("typealias Foo$ = Void"), - Example("protocol Foo {\n associatedtype Bar$\n }") + Example("protocol Foo {\n associatedtype Bar$\n }"), ] let description = baseDescription.with(nonTriggeringExamples: nonTriggeringExamples) @@ -47,7 +47,7 @@ final class TypeNameRuleTests: SwiftLintTestCase { Example("private typealias ↓foo = Void"), Example("class ↓myType {}"), Example("struct ↓myType {}"), - Example("enum ↓myType {}") + Example("enum ↓myType {}"), ] let nonTriggeringExamples = baseDescription.nonTriggeringExamples + triggeringExamplesToRemove.removingViolationMarkers() diff --git a/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift b/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift index e17c3e873a..8ee55ec026 100644 --- a/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/UnneededOverrideRuleTests.swift @@ -22,7 +22,7 @@ final class UnneededOverrideRuleTests: SwiftLintTestCase { private override init() { super.init() } - """) + """), ] + UnneededOverrideRuleExamples.nonTriggeringExamples let triggeringExamples = [ @@ -39,7 +39,7 @@ final class UnneededOverrideRuleTests: SwiftLintTestCase { super.init(frame: frame) } } - """) + """), ] let corrections = [ @@ -52,7 +52,7 @@ final class UnneededOverrideRuleTests: SwiftLintTestCase { """): Example(""" class Foo { } - """) + """), ] let description = UnneededOverrideRule.description diff --git a/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift index cca2d1ee8d..8b1e4dc492 100644 --- a/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/UnusedDeclarationConfigurationTests.swift @@ -7,7 +7,7 @@ final class UnusedDeclarationConfigurationTests: XCTestCase { let config = [ "severity": "warning", "include_public_and_open": true, - "related_usrs_to_skip": ["a", "b"] + "related_usrs_to_skip": ["a", "b"], ] as [String: any Sendable] try testee.apply(configuration: config) diff --git a/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift index 1f458abae4..20d725b487 100644 --- a/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift @@ -21,7 +21,7 @@ final class VerticalWhitespaceRuleTests: SwiftLintTestCase { .with(triggeringExamples: []) .with(corrections: [ Example("let b = 0\n\n↓\n↓\n↓\n\nclass AAA {}\n"): Example("let b = 0\n\n\nclass AAA {}\n"), - Example("let b = 0\n\n\nclass AAA {}\n"): Example("let b = 0\n\n\nclass AAA {}\n") + Example("let b = 0\n\n\nclass AAA {}\n"): Example("let b = 0\n\n\nclass AAA {}\n"), ]) verifyRule(maxEmptyLinesDescription, diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index fffb3146d1..bf3e0c544a 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -36,7 +36,7 @@ private extension SwiftLintFile { "-F", frameworks, "-sdk", sdk, - "-j4", path! + "-j4", path!, ] } } @@ -172,7 +172,8 @@ private func render(violations: [StyleViolation], in contents: String) -> String "\(violation.severity.rawValue): ", "\(violation.ruleName) Violation: ", violation.reason, - " (\(violation.ruleIdentifier))"].joined() + " (\(violation.ruleIdentifier))", + ].joined() if line >= contents.count { contents.append(message) } else { From aa9f474cb953f2dd09990456c54672aa091af369 Mon Sep 17 00:00:00 2001 From: Koichiro Ueki <43738558+Ueeek@users.noreply.github.com> Date: Sat, 29 Jun 2024 20:13:41 +0900 Subject: [PATCH 099/265] Add new `no_empty_block` rule (#5617) --- CHANGELOG.md | 5 + .../Models/BuiltInRules.swift | 1 + .../Rules/Idiomatic/NoEmptyBlockRule.swift | 114 ++++++++++++++++++ .../VerticalWhitespaceOpeningBracesRule.swift | 2 - Source/SwiftLintCore/Helpers/Stack.swift | 2 +- .../SwiftLintCore/Models/RuleRegistry.swift | 2 +- .../Rules/SuperfluousDisableCommandRule.swift | 2 +- Tests/CLITests/RulesFilterTests.swift | 6 +- Tests/GeneratedTests/GeneratedTests.swift | 6 + .../default_rule_configurations.yml | 2 + .../ConfigurationTests+Mock.swift | 2 +- .../RuleConfigurationDescriptionTests.swift | 2 +- Tests/SwiftLintFrameworkTests/RuleTests.swift | 8 +- 13 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index b2bee7f7fe..f383dbf7b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,11 @@ [Martin Redington](https://github.com/mildm8nnered) [#5552](https://github.com/realm/SwiftLint/issues/5552) +* Add `no_empty_block` default rule to validate that code blocks are not empty. + They should at least contain a comment. + [Ueeek](https://github.com/Ueeek) + [#5615](https://github.com/realm/SwiftLint/issues/5615) + #### Bug Fixes * Fix a few false positives and negatives by updating the parser to support diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index e0c198a06d..d30f9779f6 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -126,6 +126,7 @@ public let builtInRules: [any Rule.Type] = [ NSObjectPreferIsEqualRule.self, NestingRule.self, NimbleOperatorRule.self, + NoEmptyBlockRule.self, NoExtensionAccessModifierRule.self, NoFallthroughOnlyRule.self, NoGroupingExtensionRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift new file mode 100644 index 0000000000..2ed5b456f1 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift @@ -0,0 +1,114 @@ +import SwiftSyntax + +@SwiftSyntaxRule +struct NoEmptyBlockRule: Rule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "no_empty_block", + name: "No Empty Block", + description: "Code blocks should contain at least one statement or comment", + kind: .idiomatic, + nonTriggeringExamples: [ + Example(""" + var flag = true { + willSet { /* do something */ } + } + """), + Example(""" + do { + /* do something */ + } catch { + /* do something */ + } + """), + Example(""" + defer { + /* do something */ + } + """), + Example(""" + deinit { /* do something */ } + """), + Example(""" + for _ in 0..<10 { /* do something */ } + """), + Example(""" + func f() { + /* do something */ + } + """), + Example(""" + if flag { + /* do something */ + } else { + /* do something */ + } + """), + Example(""" + init() { /* do something */ } + """), + Example(""" + repeat { /* do something */ } while (flag) + """), + Example(""" + while i < 10 { /* do something */ } + """), + ], + triggeringExamples: [ + Example(""" + var flag = true { + willSet ↓{} + } + """), + Example(""" + do ↓{ + } catch ↓{ + } + """), + Example(""" + defer ↓{} + """), + Example(""" + deinit ↓{} + """), + Example(""" + for _ in 0..<10 ↓{} + """), + Example(""" + func f() ↓{} + """), + Example(""" + if flag ↓{ + } else ↓{ + } + """), + Example(""" + init() ↓{} + """), + Example(""" + repeat ↓{} while (flag) + """), + Example(""" + while i < 10 ↓{} + """), + ] + ) +} + +private extension NoEmptyBlockRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: CodeBlockSyntax) { + // No need to show a warning since Empty Block of `guard` is compile error. + guard node.parent?.kind != .guardStmt else { return } + + guard node.statements.isEmpty, + !node.leftBrace.trailingTrivia.containsComments, + !node.rightBrace.leadingTrivia.containsComments else { + return + } + + violations.append(node.leftBrace.positionAfterSkippingLeadingTrivia) + } + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift index 339c7998eb..3547c63a3d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift @@ -141,8 +141,6 @@ struct VerticalWhitespaceOpeningBracesRule: Rule { } extension VerticalWhitespaceOpeningBracesRule: OptInRule { - init(configuration: Any) throws {} - static let description = RuleDescription( identifier: "vertical_whitespace_opening_braces", name: "Vertical Whitespace after Opening Braces", diff --git a/Source/SwiftLintCore/Helpers/Stack.swift b/Source/SwiftLintCore/Helpers/Stack.swift index f5b8573678..d69fb6cdac 100644 --- a/Source/SwiftLintCore/Helpers/Stack.swift +++ b/Source/SwiftLintCore/Helpers/Stack.swift @@ -3,7 +3,7 @@ public struct Stack { private var elements = [Element]() /// Creates an empty `Stack`. - public init() {} + public init() { /* Publish no-op initializer */ } /// The number of elements in this stack. public var count: Int { diff --git a/Source/SwiftLintCore/Models/RuleRegistry.swift b/Source/SwiftLintCore/Models/RuleRegistry.swift index 016ccd7240..e58dabdfb4 100644 --- a/Source/SwiftLintCore/Models/RuleRegistry.swift +++ b/Source/SwiftLintCore/Models/RuleRegistry.swift @@ -12,7 +12,7 @@ public final class RuleRegistry: @unchecked Sendable { /// accessed will not work. public private(set) lazy var list = RuleList(rules: registeredRules) - private init() {} + private init() { /* To guarantee that this is singleton. */ } /// Register rules. /// diff --git a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift index f7dee1b17b..947328916f 100644 --- a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift +++ b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift @@ -1,7 +1,7 @@ package struct SuperfluousDisableCommandRule: SourceKitFreeRule { package var configuration = SeverityConfiguration(.warning) - package init() {} + package init() { /* Make initializer as accessible as its type. */ } package static let description = RuleDescription( identifier: "superfluous_disable_command", diff --git a/Tests/CLITests/RulesFilterTests.swift b/Tests/CLITests/RulesFilterTests.swift index fa1cd87592..eb99810373 100644 --- a/Tests/CLITests/RulesFilterTests.swift +++ b/Tests/CLITests/RulesFilterTests.swift @@ -137,7 +137,7 @@ private struct RuleMock1: Rule { static let description = RuleDescription(identifier: "RuleMock1", name: "", description: "", kind: .style) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { @@ -152,7 +152,7 @@ private struct RuleMock2: Rule { static let description = RuleDescription(identifier: "RuleMock2", name: "", description: "", kind: .style) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { @@ -167,7 +167,7 @@ private struct CorrectableRuleMock: CorrectableRule { static let description = RuleDescription(identifier: "CorrectableRuleMock", name: "", description: "", kind: .style) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 25d750903f..3234b3f02b 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -745,6 +745,12 @@ final class NimbleOperatorRuleGeneratedTests: SwiftLintTestCase { } } +final class NoEmptyBlockRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(NoEmptyBlockRule.description) + } +} + final class NoExtensionAccessModifierRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NoExtensionAccessModifierRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 404b9ef45d..cf0473b077 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -333,6 +333,8 @@ nesting: ignore_typealiases_and_associatedtypes: false nimble_operator: severity: warning +no_empty_block: + severity: warning no_extension_access_modifier: severity: error no_fallthrough_only: diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift index c540a1a565..3bb99e7cee 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift @@ -90,7 +90,7 @@ struct RuleMock: Rule { static let description = RuleDescription(identifier: "RuleMock", name: "", description: "", kind: .style) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { [] } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index 5aa422a442..99678587e4 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -221,7 +221,7 @@ final class RuleConfigurationDescriptionTests: XCTestCase { @ConfigurationElement(key: "invisible") var invisible = true - mutating func apply(configuration: Any) throws {} + mutating func apply(configuration: Any) throws { /* conformance for test */ } func isEqualTo(_ ruleConfiguration: some RuleConfiguration) -> Bool { false } } diff --git a/Tests/SwiftLintFrameworkTests/RuleTests.swift b/Tests/SwiftLintFrameworkTests/RuleTests.swift index b1ed928830..45a28015f9 100644 --- a/Tests/SwiftLintFrameworkTests/RuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleTests.swift @@ -10,7 +10,7 @@ struct RuleWithLevelsMock: Rule { kind: .style, deprecatedAliases: ["mock"]) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() try self.configuration.apply(configuration: configuration) @@ -26,7 +26,7 @@ final class RuleTests: SwiftLintTestCase { static let description = RuleDescription(identifier: "RuleMock1", name: "", description: "", kind: .style) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { @@ -40,7 +40,7 @@ final class RuleTests: SwiftLintTestCase { static let description = RuleDescription(identifier: "RuleMock2", name: "", description: "", kind: .style) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { @@ -55,7 +55,7 @@ final class RuleTests: SwiftLintTestCase { name: "", description: "", kind: .style) - init() {} + init() { /* conformance for test */ } init(configuration: Any) throws { self.init() try self.configuration.apply(configuration: configuration) From d274a81340622dc504857c570deea322bbf76502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 29 Jun 2024 13:34:22 +0200 Subject: [PATCH 100/265] Lint Package.swift as well (#5646) --- .swiftlint.yml | 1 + Package.swift | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 808f32ed4e..e956504102 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -3,6 +3,7 @@ included: - Plugins - Source - Tests + - Package.swift excluded: - Tests/SwiftLintFrameworkTests/Resources diff --git a/Package.swift b/Package.swift index 5815d4e11d..8dcec252bd 100644 --- a/Package.swift +++ b/Package.swift @@ -8,10 +8,11 @@ let swiftFeatures: [SwiftSetting] = [ .enableUpcomingFeature("ImportObjcForwardDeclarations"), .enableUpcomingFeature("ForwardTrailingClosures"), .enableUpcomingFeature("InternalImportsByDefault"), - .enableUpcomingFeature("ImplicitOpenExistentials") + .enableUpcomingFeature("ImplicitOpenExistentials"), ] let swiftLintPluginDependencies: [Target.Dependency] + #if os(macOS) swiftLintPluginDependencies = [.target(name: "SwiftLintBinary")] #else @@ -25,7 +26,7 @@ let package = Package( .executable(name: "swiftlint", targets: ["swiftlint"]), .library(name: "SwiftLintFramework", targets: ["SwiftLintFramework"]), .plugin(name: "SwiftLintBuildToolPlugin", targets: ["SwiftLintBuildToolPlugin"]), - .plugin(name: "SwiftLintCommandPlugin", targets: ["SwiftLintCommandPlugin"]) + .plugin(name: "SwiftLintCommandPlugin", targets: ["SwiftLintCommandPlugin"]), ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), @@ -34,7 +35,7 @@ let package = Package( .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), .package(url: "https://github.com/JohnSundell/CollectionConcurrencyKit.git", from: "0.2.0"), - .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.8.0")) + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.8.0")), ], targets: [ .plugin( @@ -77,7 +78,7 @@ let package = Package( .product(name: "SwiftSyntaxBuilder", package: "swift-syntax"), .product(name: "SwiftyTextTable", package: "SwiftyTextTable"), .product(name: "Yams", package: "Yams"), - "SwiftLintCoreMacros" + "SwiftLintCoreMacros", ], swiftSettings: swiftFeatures ), @@ -98,7 +99,7 @@ let package = Package( "SwiftLintExtraRules", // Workaround for https://github.com/apple/swift-package-manager/issues/6940: .product(name: "ArgumentParser", package: "swift-argument-parser"), - "CollectionConcurrencyKit" + "CollectionConcurrencyKit", ], swiftSettings: swiftFeatures ), @@ -115,7 +116,7 @@ let package = Package( dependencies: [ "SwiftLintFramework", "SwiftLintTestHelpers", - "SwiftLintCoreMacros" + "SwiftLintCoreMacros", ], exclude: [ "Resources", @@ -126,7 +127,7 @@ let package = Package( name: "GeneratedTests", dependencies: [ "SwiftLintFramework", - "SwiftLintTestHelpers" + "SwiftLintTestHelpers", ], swiftSettings: swiftFeatures ), @@ -134,7 +135,7 @@ let package = Package( name: "IntegrationTests", dependencies: [ "SwiftLintFramework", - "SwiftLintTestHelpers" + "SwiftLintTestHelpers", ], exclude: [ "default_rule_configurations.yml" @@ -145,14 +146,14 @@ let package = Package( name: "ExtraRulesTests", dependencies: [ "SwiftLintFramework", - "SwiftLintTestHelpers" + "SwiftLintTestHelpers", ] ), .macro( name: "SwiftLintCoreMacros", dependencies: [ .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), - .product(name: "SwiftCompilerPlugin", package: "swift-syntax") + .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), ], path: "Source/SwiftLintCoreMacros", swiftSettings: swiftFeatures @@ -172,8 +173,8 @@ let package = Package( package.targets.append( .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.55.1/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "722a705de1cf4e0e07f2b7d2f9f631f3a8b2635a0c84cce99f9677b38aa4a1d6" + url: "https://github.com/realm/SwiftLint/releases/download/0.55.1/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "722a705de1cf4e0e07f2b7d2f9f631f3a8b2635a0c84cce99f9677b38aa4a1d6" ) ) #endif From 593bb625fb8afe7c95602a98a69ed0326c7a9533 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 29 Jun 2024 15:58:35 +0100 Subject: [PATCH 101/265] Adds `--working-directory` command line option (#5560) --- CHANGELOG.md | 5 +++++ Source/swiftlint/Commands/Analyze.swift | 1 + Source/swiftlint/Commands/Lint.swift | 1 + Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift | 2 ++ Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift | 11 +++++++++++ 5 files changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f383dbf7b6..1243903cd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -406,6 +406,11 @@ [Martin Redington](https://github.com/mildm8nnered) [#5450](https://github.com/realm/SwiftLint/issues/5450) +* Add a `--working-directory` command line option, for users who cannot + otherwise control which directory SwiftLint is run from. + [Martin Redington](https://github.com/mildm8nnered) + [#5424](https://github.com/realm/SwiftLint/issues/5424) + ## 0.54.0: Macro-Economic Forces #### Breaking diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index 5b14d891ac..337a8d2809 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -33,6 +33,7 @@ extension SwiftLint { reporter: common.reporter, baseline: common.baseline, writeBaseline: common.writeBaseline, + workingDirectory: common.workingDirectory, quiet: quiet, output: common.output, progress: common.progress, diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index b15cf9e602..901d4386bd 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -45,6 +45,7 @@ extension SwiftLint { reporter: common.reporter, baseline: common.baseline, writeBaseline: common.writeBaseline, + workingDirectory: common.workingDirectory, quiet: quiet, output: common.output, progress: common.progress, diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift index 19d3a416f1..59a6c08007 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -42,6 +42,8 @@ struct LintOrAnalyzeArguments: ParsableArguments { var baseline: String? @Option(help: "The path to save detected violations to as a new baseline.") var writeBaseline: String? + @Option(help: "The working directory to use when running SwiftLint.") + var workingDirectory: String? @Flag(help: "Use the in-process version of SourceKit.") var inProcessSourcekit = false @Option(help: "The file where violations should be saved. Prints to stdout by default.") diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift index 816c759a5e..97cc91faa4 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -26,6 +26,16 @@ enum LintOrAnalyzeMode { struct LintOrAnalyzeCommand { static func run(_ options: LintOrAnalyzeOptions) async throws { + if let workingDirectory = options.workingDirectory { + if !FileManager.default.changeCurrentDirectoryPath(workingDirectory) { + throw SwiftLintError.usageError( + description: """ + Could not change working directory to '\(workingDirectory)'. \ + Make sure it exists and is accessible. + """ + ) + } + } if options.inProcessSourcekit { // TODO: [08/11/2024] Remove deprecation warning after ~2 years. queuedPrintError( @@ -261,6 +271,7 @@ struct LintOrAnalyzeOptions { let reporter: String? let baseline: String? let writeBaseline: String? + let workingDirectory: String? let quiet: Bool let output: String? let progress: Bool From 6642d45a2d4829f047d540e23418b716c9cd2edf Mon Sep 17 00:00:00 2001 From: woxtu Date: Wed, 3 Jul 2024 03:09:19 +0900 Subject: [PATCH 102/265] Rewrite `missing_docs` rule with SwiftSyntax (#5048) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 16 +- .../Rules/Lint/MissingDocsRule.swift | 434 +++++++++++++----- .../Rules/Lint/MissingDocsRuleExamples.swift | 223 +++++++++ .../MissingDocsConfiguration.swift | 7 + .../default_rule_configurations.yml | 1 + .../MissingDocsRuleTests.swift | 77 +--- 6 files changed, 578 insertions(+), 180 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 1243903cd5..3814a4cedb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,12 @@ improvements done in the [SwiftSyntax](https://github.com/apple/swift-syntax) library. +* Rewrite the following rules with SwiftSyntax: + * `missing_docs` + + [woxtu](https://github.com/woxtu) + [SimplyDanny](https://github.com/SimplyDanny) + * Adds `baseline` and `write_baseline` configuration file settings, equivalent to the `--baseline` and `--write-baseline` command line options. [Martin Redington](https://github.com/mildm8nnered) @@ -32,8 +38,14 @@ * Add `no_empty_block` default rule to validate that code blocks are not empty. They should at least contain a comment. - [Ueeek](https://github.com/Ueeek) - [#5615](https://github.com/realm/SwiftLint/issues/5615) + [Ueeek](https://github.com/Ueeek) + [#5615](https://github.com/realm/SwiftLint/issues/5615) + +* Add new option `evaluate_effective_access_control_level` to `missing_docs` + rule. Setting it to `true` stops the rule from triggering on declarations + inside of types with lower visibility. These declarations effectively + have at most the same access level. + [SimplyDanny](https://github.com/SimplyDanny) #### Bug Fixes diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift index 49e36967c4..2ae715b229 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift @@ -1,139 +1,329 @@ -import SourceKittenFramework - -private extension SwiftLintFile { - func missingDocOffsets(in dictionary: SourceKittenDictionary, - acls: [AccessControlLevel], - excludesExtensions: Bool, - excludesInheritedTypes: Bool, - excludesTrivialInit: Bool) -> [(ByteCount, AccessControlLevel)] { - if dictionary.enclosedSwiftAttributes.contains(.override) || - (dictionary.inheritedTypes.isNotEmpty && excludesInheritedTypes) { - return [] - } - let substructureOffsets = dictionary.substructure.flatMap { - missingDocOffsets( - in: $0, - acls: acls, - excludesExtensions: excludesExtensions, - excludesInheritedTypes: excludesInheritedTypes, - excludesTrivialInit: excludesTrivialInit - ) +import SwiftLintCore +import SwiftSyntax + +@SwiftSyntaxRule +struct MissingDocsRule: OptInRule { + var configuration = MissingDocsConfiguration() + + static let description = RuleDescription( + identifier: "missing_docs", + name: "Missing Docs", + description: "Declarations should be documented.", + kind: .lint, + nonTriggeringExamples: MissingDocsRuleExamples.nonTriggeringExamples, + triggeringExamples: MissingDocsRuleExamples.triggeringExamples + ) +} + +private extension MissingDocsRule { + final class Visitor: ViolationsSyntaxVisitor { + private var aclScope = Stack() + + override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind { + defer { + aclScope.push( + behavior: .actor(node.modifiers.accessibility), + evalEffectiveAcl: configuration.evaluateEffectiveAccessControlLevel + ) + } + if node.inherits, configuration.excludesInheritedTypes { + return .skipChildren + } + collectViolation(from: node, on: node.actorKeyword) + return .visitChildren + } + + override func visitPost(_ node: ActorDeclSyntax) { + aclScope.pop() + } + + override func visitPost(_ node: AssociatedTypeDeclSyntax) { + collectViolation(from: node, on: node.associatedtypeKeyword) + } + + override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { + defer { + aclScope.push( + behavior: .class(node.modifiers.accessibility), + evalEffectiveAcl: configuration.evaluateEffectiveAccessControlLevel + ) + } + if node.inherits, configuration.excludesInheritedTypes { + return .skipChildren + } + collectViolation(from: node, on: node.classKeyword) + return .visitChildren + } + + override func visitPost(_ node: ClassDeclSyntax) { + aclScope.pop() } - let isTrivialInit = dictionary.declarationKind == .functionMethodInstance && - dictionary.name == "init()" && - dictionary.enclosedVarParameters.isEmpty - if isTrivialInit && excludesTrivialInit { - return substructureOffsets + override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + .skipChildren } - guard let kind = dictionary.declarationKind, - !SwiftDeclarationKind.extensionKinds.contains(kind) || !excludesExtensions, - case let isDeinit = kind == .functionMethodInstance && dictionary.name == "deinit", - !isDeinit, - let offset = dictionary.offset, - let acl = dictionary.accessibility, - acls.contains(acl) else { - return substructureOffsets + override func visit(_ node: CodeBlockSyntax) -> SyntaxVisitorContinueKind { + .skipChildren } - if dictionary.docLength != nil { - return substructureOffsets + + override func visitPost(_ node: EnumCaseDeclSyntax) { + guard !node.hasDocComment, case let .enum(enumAcl) = aclScope.peek() else { + return + } + let acl = enumAcl ?? .internal + if let parameter = configuration.parameters.first(where: { $0.value == acl }) { + node.elements.forEach { + violations.append( + ReasonedRuleViolation( + position: $0.name.positionAfterSkippingLeadingTrivia, + reason: "\(acl) declarations should be documented", + severity: parameter.severity + ) + ) + } + } + } + + override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { + defer { + aclScope.push( + behavior: .enum(node.modifiers.accessibility), + evalEffectiveAcl: configuration.evaluateEffectiveAccessControlLevel + ) + } + if node.inherits, configuration.excludesInheritedTypes { + return .skipChildren + } + collectViolation(from: node, on: node.enumKeyword) + return .visitChildren + } + + override func visitPost(_ node: EnumDeclSyntax) { + aclScope.pop() + } + + override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + defer { aclScope.push(.extension(node.modifiers.accessibility)) } + if node.inherits, configuration.excludesInheritedTypes { + return .skipChildren + } + if !configuration.excludesExtensions { + collectViolation(from: node, on: node.extensionKeyword) + } + return .visitChildren + } + + override func visitPost(_ node: ExtensionDeclSyntax) { + aclScope.pop() + } + + override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { + collectViolation(from: node, on: node.funcKeyword) + return .skipChildren + } + + override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { + if node.signature.parameterClause.parameters.isNotEmpty || !configuration.excludesTrivialInit { + collectViolation(from: node, on: node.initKeyword) + } + return .skipChildren + } + + override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { + defer { + aclScope.push( + behavior: .protocol(node.modifiers.accessibility), + evalEffectiveAcl: configuration.evaluateEffectiveAccessControlLevel + ) + } + if node.inherits, configuration.excludesInheritedTypes { + return .skipChildren + } + collectViolation(from: node, on: node.protocolKeyword) + return .visitChildren + } + + override func visitPost(_ node: ProtocolDeclSyntax) { + aclScope.pop() + } + + override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { + defer { + aclScope.push( + behavior: .struct(node.modifiers.accessibility), + evalEffectiveAcl: configuration.evaluateEffectiveAccessControlLevel + ) + } + if node.inherits, configuration.excludesInheritedTypes { + return .skipChildren + } + collectViolation(from: node, on: node.structKeyword) + return .visitChildren + } + + override func visitPost(_ node: StructDeclSyntax) { + aclScope.pop() + } + + override func visit(_ node: SubscriptDeclSyntax) -> SyntaxVisitorContinueKind { + collectViolation(from: node, on: node.subscriptKeyword) + return .skipChildren + } + + override func visitPost(_ node: TypeAliasDeclSyntax) { + collectViolation(from: node, on: node.typealiasKeyword) + } + + override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind { + collectViolation(from: node, on: node.bindingSpecifier) + return .skipChildren + } + + private func collectViolation(from node: some WithModifiersSyntax, on token: TokenSyntax) { + if node.modifiers.contains(keyword: .override) || node.hasDocComment { + return + } + let acl = aclScope.computeAcl( + givenExplicitAcl: node.modifiers.accessibility, + evalEffectiveAcl: configuration.evaluateEffectiveAccessControlLevel + ) + if let parameter = configuration.parameters.first(where: { $0.value == acl }) { + violations.append( + ReasonedRuleViolation( + position: (node.modifiers.staticOrClass ?? token).positionAfterSkippingLeadingTrivia, + reason: "\(acl) declarations should be documented", + severity: parameter.severity + ) + ) + } } - return substructureOffsets + [(offset, acl)] } } -struct MissingDocsRule: OptInRule { - init() { - configuration = MissingDocsConfiguration() +private extension DeclGroupSyntax { + var inherits: Bool { + if let types = inheritanceClause?.inheritedTypes, types.isNotEmpty { + return types.contains { !$0.type.is(SuppressedTypeSyntax.self) } + } + return false } +} - typealias ConfigurationType = MissingDocsConfiguration +private extension SyntaxProtocol { + var hasDocComment: Bool { + switch leadingTrivia.pieces.last(where: { !$0.isWhitespace }) { + case .docBlockComment, .docLineComment: + return true + default: + guard let item = parent?.as(CodeBlockItemSyntax.self), + let itemList = item.parent?.as(CodeBlockItemListSyntax.self), + itemList.first == item else { + return false + } + let ifConfigDecl = itemList + .parent?.as(IfConfigClauseSyntax.self)? + .parent?.as(IfConfigClauseListSyntax.self)? + .parent?.as(IfConfigDeclSyntax.self) + if let ifConfigDecl { + return ifConfigDecl.hasDocComment + } + return false + } + } +} - var configuration: MissingDocsConfiguration +private extension DeclModifierListSyntax { + var accessibility: AccessControlLevel? { + filter { $0.detail == nil }.compactMap { AccessControlLevel(description: $0.name.text) }.first + } - static let description = RuleDescription( - identifier: "missing_docs", - name: "Missing Docs", - description: "Declarations should be documented.", - kind: .lint, - nonTriggeringExamples: [ - // locally-defined superclass member is documented, but subclass member is not - Example(""" - /// docs - public class A { - /// docs - public func b() {} - } - // no docs - public class B: A { override public func b() {} } - """), - // externally-defined superclass member is documented, but subclass member is not - Example(""" - import Foundation - // no docs - public class B: NSObject { - // no docs - override public var description: String { fatalError() } } - """), - Example(""" - /// docs - public class A { - deinit {} - } - """), - Example(""" - public extension A {} - """), - Example(""" - /// docs - public class A { - public init() {} - } - """, configuration: ["excludes_trivial_init": true]), - ], - triggeringExamples: [ - // public, undocumented - Example("public func a() {}"), - // public, undocumented - Example("// regular comment\npublic func a() {}"), - // public, undocumented - Example("/* regular comment */\npublic func a() {}"), - // protocol member and inherited member are both undocumented - Example(""" - /// docs - public protocol A { - // no docs - var b: Int { get } } - /// docs - public struct C: A { - - public let b: Int - } - """), - Example(""" - /// docs - public class A { - public init(argument: String) {} - } - """, configuration: ["excludes_trivial_init": true]), - ] - ) + var staticOrClass: TokenSyntax? { + first { $0.name.text == "static" || $0.name.text == "class" }?.name + } +} + +private enum AccessControlBehavior { + case `actor`(AccessControlLevel?) + case local + case `class`(AccessControlLevel?) + case `enum`(AccessControlLevel?) + case `extension`(AccessControlLevel?) + case `protocol`(AccessControlLevel?) + case `struct`(AccessControlLevel?) + + var effectiveAcl: AccessControlLevel { + explicitAcl ?? .internal + } + + var explicitAcl: AccessControlLevel? { + switch self { + case let .actor(acl): acl + case .local: nil + case let .class(acl): acl + case let .enum(acl): acl + case let .extension(acl): acl + case let .protocol(acl): acl + case let .struct(acl): acl + } + } + + func sameWith(acl: AccessControlLevel) -> Self { + switch self { + case .actor: .actor(acl) + case .local: .local + case .class: .class(acl) + case .enum: .enum(acl) + case .extension: .extension(acl) + case .protocol: .protocol(acl) + case .struct: .struct(acl) + } + } +} + +/// Implementation of Swift's effective ACL logic. Should be moved to a specialized syntax visitor for reuse some time. +private extension Stack { + mutating func push(behavior: AccessControlBehavior, evalEffectiveAcl: Bool) { + if let parentBehavior = peek() { + switch parentBehavior { + case .local: + push(.local) + case .actor, .class, .struct, .enum: + if behavior.effectiveAcl <= parentBehavior.effectiveAcl || !evalEffectiveAcl { + push(behavior) + } else { + push(behavior.sameWith(acl: parentBehavior.effectiveAcl)) + } + case .extension, .protocol: + if behavior.explicitAcl != nil { + push(behavior) + } else { + push(behavior.sameWith(acl: parentBehavior.effectiveAcl)) + } + } + } else { + push(behavior) + } + } - func validate(file: SwiftLintFile) -> [StyleViolation] { - let acls = configuration.parameters.map { $0.value } - let dict = file.structureDictionary - return file.missingDocOffsets( - in: dict, - acls: acls, - excludesExtensions: configuration.excludesExtensions, - excludesInheritedTypes: configuration.excludesInheritedTypes, - excludesTrivialInit: configuration.excludesTrivialInit - ).map { offset, acl in - StyleViolation(ruleDescription: Self.description, - severity: configuration.parameters.first { $0.value == acl }?.severity ?? .warning, - location: Location(file: file, byteOffset: offset), - reason: "\(acl.description) declarations should be documented") + func computeAcl(givenExplicitAcl acl: AccessControlLevel?, evalEffectiveAcl: Bool) -> AccessControlLevel { + if let parentBehavior = peek() { + switch parentBehavior { + case .local: + .private + case .actor, .class, .struct, .enum: + if let acl { + acl < parentBehavior.effectiveAcl || !evalEffectiveAcl ? acl : parentBehavior.effectiveAcl + } else { + parentBehavior.effectiveAcl >= .internal ? .internal : parentBehavior.effectiveAcl + } + case .protocol: + parentBehavior.effectiveAcl + case .extension: + acl ?? parentBehavior.effectiveAcl + } + } else { + acl ?? .internal } } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift new file mode 100644 index 0000000000..bb35f01ef0 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift @@ -0,0 +1,223 @@ +struct MissingDocsRuleExamples { + static let nonTriggeringExamples = [ + // locally-defined superclass member is documented, but subclass member is not + Example(""" + /// docs + public class A { + /// docs + public func b() {} + } + // no docs + public class B: A { override public func b() {} } + """), + // externally-defined superclass member is documented, but subclass member is not + Example(""" + import Foundation + // no docs + public class B: NSObject { + // no docs + override public var description: String { fatalError() } } + """), + Example(""" + /// docs + public class A { + var j = 1 + var i: Int { 1 } + func f() {} + deinit {} + } + """), + Example(""" + public extension A {} + """), + Example(""" + enum E { + case A + } + """), + Example(""" + /// docs + public class A { + public init() {} + } + """, configuration: ["excludes_trivial_init": true]), + Example(""" + class C { + public func f() {} + } + """, configuration: ["evaluate_effective_access_control_level": true]), + Example(""" + public struct S: ~Copyable, P { + public init() {} + } + """), + Example(""" + /// my doc + #if os(macOS) + public func f() {} + #else + public func f() async {} + #endif + """, excludeFromDocumentation: true), + Example(""" + /// my doc + #if os(macOS) + #if is(iOS) + public func f() {} + #endif + #else + public func f() async {} + #endif + """, excludeFromDocumentation: true), + ] + + static let triggeringExamples = [ + // public, undocumented + Example("public ↓func a() {}"), + // public, undocumented + Example("// regular comment\npublic ↓func a() {}"), + // public, undocumented + Example("/* regular comment */\npublic ↓func a() {}"), + // protocol member and inherited member are both undocumented + Example(""" + /// docs + public protocol A { + // no docs + ↓var b: Int { get } + } + /// docs + public struct C: A { + public let b: Int + } + """), + // Violation marker is on `static` keyword. + Example(""" + /// a doc + public class C { + public ↓static let i = 1 + } + """), + // `excludes_extensions` only excludes the extension declaration itself; not its children. + Example(""" + public extension A { + public ↓func f() {} + ↓static var i: Int { 1 } + ↓struct S { + func f() {} + } + ↓class C { + func f() {} + } + ↓actor A { + func f() {} + } + ↓enum E { + case ↓a + func f() {} + } + } + """), + Example(""" + public extension A { + ↓enum E { + enum Inner { + case a + } + } + } + """), + Example(""" + extension E { + public ↓struct S { + public ↓static let i = 1 + } + } + """), + Example(""" + extension E { + public ↓func f() {} + } + """), + Example(""" + /// docs + public class A { + public ↓init(argument: String) {} + } + """, configuration: ["excludes_trivial_init": true]), + Example(""" + public ↓struct C: A { + public ↓let b: Int + } + """, configuration: ["excludes_inherited_types": false]), + Example(""" + public ↓extension A { + public ↓func f() {} + } + """, configuration: ["excludes_extensions": false]), + Example(""" + public extension E { + ↓var i: Int { + let j = 1 + func f() {} + return j + } + } + """), + Example(""" + #if os(macOS) + public ↓func f() {} + #endif + """), + Example(""" + public ↓enum E { + case ↓A + func f() {} + init(_ i: Int) { self = .A } + } + """), + Example(""" + open ↓class C { + public ↓enum E { + case ↓A + func f() {} + init(_ i: Int) { self = .A } + } + } + """, excludeFromDocumentation: true), + /// Nested types inherit the ACL from the declaring extension. + Example(""" + /// a doc + public struct S {} + public extension S { + ↓enum E { + case ↓A + } + } + """), + Example(""" + public extension URL { + fileprivate enum E { + static let source = "" + } + ↓static var a: Int { 1 } + } + """, excludeFromDocumentation: true), + Example(""" + class C { + public ↓func f() {} + } + """, configuration: ["evaluate_effective_access_control_level": false]), + Example(""" + public ↓struct S: ~Copyable, ~Escapable { + public ↓init() {} + } + """), + Example(""" + /// my doc + #if os(macOS) + public func f() {} + public ↓func g() {} + #endif + """, excludeFromDocumentation: true), + ] +} diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift index f9404436fa..ee410d80e6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift @@ -14,6 +14,8 @@ struct MissingDocsConfiguration: RuleConfiguration { private(set) var excludesInheritedTypes = true @ConfigurationElement(key: "excludes_trivial_init") private(set) var excludesTrivialInit = false + @ConfigurationElement(key: "evaluate_effective_access_control_level") + private(set) var evaluateEffectiveAccessControlLevel = false var parameterDescription: RuleConfigurationDescription? { let parametersDescription = parameters.group { $0.severity } @@ -26,6 +28,7 @@ struct MissingDocsConfiguration: RuleConfiguration { $excludesExtensions.key => .flag(excludesExtensions) $excludesInheritedTypes.key => .flag(excludesInheritedTypes) $excludesTrivialInit.key => .flag(excludesTrivialInit) + $evaluateEffectiveAccessControlLevel.key => .flag(evaluateEffectiveAccessControlLevel) } mutating func apply(configuration: Any) throws { @@ -45,6 +48,10 @@ struct MissingDocsConfiguration: RuleConfiguration { self.excludesTrivialInit = excludesTrivialInit } + if let evaluateEffectiveAccessControlLevel = dict[$evaluateEffectiveAccessControlLevel.key] as? Bool { + self.evaluateEffectiveAccessControlLevel = evaluateEffectiveAccessControlLevel + } + if let parameters = try parameters(from: dict) { self.parameters = parameters } diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index cf0473b077..c87aa691cb 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -303,6 +303,7 @@ missing_docs: excludes_extensions: true excludes_inherited_types: true excludes_trivial_init: false + evaluate_effective_access_control_level: false modifier_order: severity: warning preferred_modifier_order: [override, acl, setterACL, dynamic, mutators, lazy, final, required, convenience, typeMethods, owned] diff --git a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift index 39dc029ad1..10e22074c8 100644 --- a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift @@ -7,7 +7,8 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "warning: [open, public]; excludes_extensions: true; " + - "excludes_inherited_types: true; excludes_trivial_init: false" + "excludes_inherited_types: true; excludes_trivial_init: false; " + + "evaluate_effective_access_control_level: false" ) } @@ -16,7 +17,8 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "warning: [open, public]; excludes_extensions: false; " + - "excludes_inherited_types: false; excludes_trivial_init: false" + "excludes_inherited_types: false; excludes_trivial_init: false; " + + "evaluate_effective_access_control_level: false" ) } @@ -25,16 +27,22 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "warning: [open, public]; excludes_extensions: false; " + - "excludes_inherited_types: true; excludes_trivial_init: false" + "excludes_inherited_types: true; excludes_trivial_init: false; " + + "evaluate_effective_access_control_level: false" ) } func testDescriptionExcludesExtensionsTrueExcludesInheritedTypesFalse() { - let configuration = MissingDocsConfiguration(excludesExtensions: true, excludesInheritedTypes: false) + let configuration = MissingDocsConfiguration( + excludesExtensions: true, + excludesInheritedTypes: false, + evaluateEffectiveAccessControlLevel: true + ) XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "warning: [open, public]; excludes_extensions: true; " + - "excludes_inherited_types: false; excludes_trivial_init: false" + "excludes_inherited_types: false; excludes_trivial_init: false; " + + "evaluate_effective_access_control_level: true" ) } @@ -44,7 +52,8 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "error: [open]; excludes_extensions: true; " + - "excludes_inherited_types: true; excludes_trivial_init: false" + "excludes_inherited_types: true; excludes_trivial_init: false; " + + "evaluate_effective_access_control_level: false" ) } @@ -58,7 +67,8 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "error: [open]; warning: [public]; excludes_extensions: true; " + - "excludes_inherited_types: true; excludes_trivial_init: false" + "excludes_inherited_types: true; excludes_trivial_init: false; " + + "evaluate_effective_access_control_level: false" ) } @@ -72,7 +82,8 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "warning: [open, public]; excludes_extensions: true; " + - "excludes_inherited_types: true; excludes_trivial_init: false" + "excludes_inherited_types: true; excludes_trivial_init: false; " + + "evaluate_effective_access_control_level: false" ) } @@ -81,7 +92,8 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertEqual( configuration.parameterDescription?.oneLiner(), "warning: [open, public]; excludes_extensions: true; " + - "excludes_inherited_types: true; excludes_trivial_init: true" + "excludes_inherited_types: true; excludes_trivial_init: true; " + + "evaluate_effective_access_control_level: false" ) } @@ -204,51 +216,4 @@ final class MissingDocsRuleTests: SwiftLintTestCase { [RuleParameter(severity: .error, value: .public)] ) } - - func testWithExcludesExtensionsDisabled() { - // Perform additional tests with the ignores_comments settings disabled. - let baseDescription = MissingDocsRule.description - let triggeringComments = [Example("public extension A {}")] - let nonTriggeringExamples = baseDescription.nonTriggeringExamples - .filter { !triggeringComments.contains($0) } - let triggeringExamples = baseDescription.triggeringExamples + triggeringComments - let description = baseDescription - .with(nonTriggeringExamples: nonTriggeringExamples) - .with(triggeringExamples: triggeringExamples) - verifyRule(description, - ruleConfiguration: ["excludes_extensions": false]) - } - - func testWithExcludesInheritedTypesDisabled() { - // Perform additional tests with the ignores_comments settings disabled. - let baseDescription = MissingDocsRule.description - let triggeringComments = [ - // locally-defined superclass member is documented, but subclass member is not - Example(""" - /// docs - public class A { - /// docs - public func b() {} - } - // no docs - public class B: A { override public func b() {} } - """), - // externally-defined superclass member is documented, but subclass member is not - Example(""" - import Foundation - // no docs - public class B: NSObject { - // no docs - override public var description: String { fatalError() } } - """), - ] - let nonTriggeringExamples = baseDescription.nonTriggeringExamples - .filter { !triggeringComments.contains($0) } - let triggeringExamples = baseDescription.triggeringExamples + triggeringComments - let description = baseDescription - .with(nonTriggeringExamples: nonTriggeringExamples) - .with(triggeringExamples: triggeringExamples) - verifyRule(description, - ruleConfiguration: ["excludes_inherited_types": false]) - } } From e0b9295412854b40ae7d9603869615b7c42e5501 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 6 Jul 2024 19:32:36 -0400 Subject: [PATCH 103/265] Add update checker (#5613) --- CHANGELOG.md | 8 +++ README.md | 3 + .../Extensions/Configuration+Merging.swift | 3 +- .../Extensions/Configuration+Parsing.swift | 4 +- .../SwiftLintCore/Models/Configuration.swift | 19 ++++-- .../SwiftLintCore/Models/SwiftVersion.swift | 14 ++++- Source/SwiftLintCore/Models/Version.swift | 14 ++++- Source/swiftlint/Commands/Analyze.swift | 3 +- Source/swiftlint/Commands/Lint.swift | 3 +- Source/swiftlint/Commands/Version.swift | 11 +++- .../Helpers/LintOrAnalyzeArguments.swift | 2 + .../Helpers/LintOrAnalyzeCommand.swift | 4 ++ Source/swiftlint/Helpers/UpdateChecker.swift | 59 +++++++++++++++++++ .../ConfigurationTests.swift | 6 ++ 14 files changed, 138 insertions(+), 15 deletions(-) create mode 100644 Source/swiftlint/Helpers/UpdateChecker.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 3814a4cedb..a767d5b379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,14 @@ have at most the same access level. [SimplyDanny](https://github.com/SimplyDanny) +* Add new `--check-for-updates` command line option for the `lint`, `analyze`, + and `version` subcommands to check for new versions of SwiftLint, and an + equivalent `check_for_updates` configuration file setting. + [Martin Redington](https://github.com/mildm8nnered) + [SimplyDanny](https://github.com/SimplyDanny) + [Ian Leitch](https://github.com/ileitch) + [#5613](https://github.com/realm/SwiftLint/issues/5613) + #### Bug Fixes * Fix a few false positives and negatives by updating the parser to support diff --git a/README.md b/README.md index f287c0394d..0da7a7e5fe 100644 --- a/README.md +++ b/README.md @@ -703,6 +703,9 @@ baseline: Baseline.json # The path to save detected violations to as a new baseline. write_baseline: Baseline.json +# If true, SwiftLint will check for updates after linting or analyzing. +check_for_updates: true + # configurable rules can be customized from this configuration file # binary rules can set their severity level force_cast: warning # implicitly diff --git a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift index 1d58f464c8..9fdd0bc44f 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift @@ -27,7 +27,8 @@ extension Configuration { allowZeroLintableFiles: childConfiguration.allowZeroLintableFiles, strict: childConfiguration.strict, baseline: childConfiguration.baseline, - writeBaseline: childConfiguration.writeBaseline + writeBaseline: childConfiguration.writeBaseline, + checkForUpdates: childConfiguration.checkForUpdates ) } diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 096e31f81f..610e45ba78 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -17,6 +17,7 @@ extension Configuration { case strict = "strict" case baseline = "baseline" case writeBaseline = "write_baseline" + case checkForUpdates = "check_for_updates" case childConfig = "child_config" case parentConfig = "parent_config" case remoteConfigTimeout = "remote_timeout" @@ -99,7 +100,8 @@ extension Configuration { allowZeroLintableFiles: dict[Key.allowZeroLintableFiles.rawValue] as? Bool ?? false, strict: dict[Key.strict.rawValue] as? Bool ?? false, baseline: dict[Key.baseline.rawValue] as? String, - writeBaseline: dict[Key.writeBaseline.rawValue] as? String + writeBaseline: dict[Key.writeBaseline.rawValue] as? String, + checkForUpdates: dict[Key.checkForUpdates.rawValue] as? Bool ?? false ) } diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 5e0c6be8ee..72e2a7ccca 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -44,6 +44,9 @@ public struct Configuration { /// The path to write a baseline to. public let writeBaseline: String? + /// Check for updates. + public let checkForUpdates: Bool + /// This value is `true` iff the `--config` parameter was used to specify (a) configuration file(s) /// In particular, this means that the value is also `true` if the `--config` parameter /// was used to explicitly specify the default `.swiftlint.yml` as the configuration file @@ -81,7 +84,8 @@ public struct Configuration { allowZeroLintableFiles: Bool, strict: Bool, baseline: String?, - writeBaseline: String? + writeBaseline: String?, + checkForUpdates: Bool ) { self.rulesWrapper = rulesWrapper self.fileGraph = fileGraph @@ -95,6 +99,7 @@ public struct Configuration { self.strict = strict self.baseline = baseline self.writeBaseline = writeBaseline + self.checkForUpdates = checkForUpdates } /// Creates a Configuration by copying an existing configuration. @@ -114,6 +119,7 @@ public struct Configuration { strict = configuration.strict baseline = configuration.baseline writeBaseline = configuration.writeBaseline + checkForUpdates = configuration.checkForUpdates } /// Creates a `Configuration` by specifying its properties directly, @@ -125,7 +131,7 @@ public struct Configuration { /// - parameter ruleList: The list of all rules. Used for alias resolving and as a fallback /// if `allRulesWrapped` is nil. /// - parameter filePath The underlaying file graph. If `nil` is specified, a empty file graph - /// with the current working directory as the `rootDirectory` will be used + /// with the current working directory as the `rootDirectory` will be used. /// - parameter includedPaths: Included paths to lint. /// - parameter excludedPaths: Excluded paths to not lint. /// - parameter indentation: The style to use when indenting Swift source code. @@ -139,6 +145,7 @@ public struct Configuration { /// - parameter strict: Treat warnings as errors. /// - parameter baseline: The path to read a baseline from. /// - parameter writeBaseline: The path to write a baseline to. + /// - parameter checkForUpdates: Check for updates to SwiftLint. package init( rulesMode: RulesMode = .default(disabled: [], optIn: []), allRulesWrapped: [ConfigurationRuleWrapper]? = nil, @@ -154,7 +161,8 @@ public struct Configuration { allowZeroLintableFiles: Bool = false, strict: Bool = false, baseline: String? = nil, - writeBaseline: String? = nil + writeBaseline: String? = nil, + checkForUpdates: Bool = false ) { if let pinnedVersion, pinnedVersion != Version.current.value { queuedPrintError( @@ -182,7 +190,8 @@ public struct Configuration { allowZeroLintableFiles: allowZeroLintableFiles, strict: strict, baseline: baseline, - writeBaseline: writeBaseline + writeBaseline: writeBaseline, + checkForUpdates: checkForUpdates ) } @@ -289,6 +298,7 @@ extension Configuration: Hashable { hasher.combine(strict) hasher.combine(baseline) hasher.combine(writeBaseline) + hasher.combine(checkForUpdates) hasher.combine(basedOnCustomConfigurationFiles) hasher.combine(cachePath) hasher.combine(rules.map { type(of: $0).description.identifier }) @@ -309,6 +319,7 @@ extension Configuration: Hashable { lhs.strict == rhs.strict && lhs.baseline == rhs.baseline && lhs.writeBaseline == rhs.writeBaseline && + lhs.checkForUpdates == rhs.checkForUpdates && lhs.rulesMode == rhs.rulesMode } } diff --git a/Source/SwiftLintCore/Models/SwiftVersion.swift b/Source/SwiftLintCore/Models/SwiftVersion.swift index 64d59af6bb..fefb6cec0a 100644 --- a/Source/SwiftLintCore/Models/SwiftVersion.swift +++ b/Source/SwiftLintCore/Models/SwiftVersion.swift @@ -2,7 +2,7 @@ import Foundation import SourceKittenFramework /// A value describing the version of the Swift compiler. -public struct SwiftVersion: RawRepresentable, Codable, Comparable, Sendable { +public struct SwiftVersion: RawRepresentable, Codable, VersionComparable, Sendable { public typealias RawValue = String public let rawValue: String @@ -10,15 +10,23 @@ public struct SwiftVersion: RawRepresentable, Codable, Comparable, Sendable { public init(rawValue: String) { self.rawValue = rawValue } +} + +/// A comparable `major.minor.patch` version number. +public protocol VersionComparable: Comparable { + /// The version string. + var rawValue: String { get } +} - public static func == (lhs: SwiftVersion, rhs: SwiftVersion) -> Bool { +extension VersionComparable { + public static func == (lhs: Self, rhs: Self) -> Bool { if let lhsComparators = lhs.comparators, let rhsComparators = rhs.comparators { return lhsComparators == rhsComparators } return lhs.rawValue == rhs.rawValue } - public static func < (lhs: SwiftVersion, rhs: SwiftVersion) -> Bool { + public static func < (lhs: Self, rhs: Self) -> Bool { if let lhsComparators = lhs.comparators, let rhsComparators = rhs.comparators { return lhsComparators.lexicographicallyPrecedes(rhsComparators) } diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index 39d1ef4920..3180438493 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -1,8 +1,20 @@ /// A type describing the SwiftLint version. -public struct Version { +public struct Version: VersionComparable { /// The string value for this version. public let value: String + /// An alias for `value` required for protocol conformance. + public var rawValue: String { + value + } + /// The current SwiftLint version. public static let current = Version(value: "0.55.1") + + /// Public initializer. + /// + /// - parameter value: The string value for this version. + public init(value: String) { + self.value = value + } } diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index 337a8d2809..6b5e70e794 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -44,7 +44,8 @@ extension SwiftLint { format: common.format, compilerLogPath: compilerLogPath, compileCommands: compileCommands, - inProcessSourcekit: common.inProcessSourcekit + inProcessSourcekit: common.inProcessSourcekit, + checkForUpdates: common.checkForUpdates ) try await LintOrAnalyzeCommand.run(options) diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index 901d4386bd..fc6e392ca1 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -56,7 +56,8 @@ extension SwiftLint { format: common.format, compilerLogPath: nil, compileCommands: nil, - inProcessSourcekit: common.inProcessSourcekit + inProcessSourcekit: common.inProcessSourcekit, + checkForUpdates: common.checkForUpdates ) try await LintOrAnalyzeCommand.run(options) } diff --git a/Source/swiftlint/Commands/Version.swift b/Source/swiftlint/Commands/Version.swift index 8cbcb082fa..aaa35dd897 100644 --- a/Source/swiftlint/Commands/Version.swift +++ b/Source/swiftlint/Commands/Version.swift @@ -2,21 +2,26 @@ import ArgumentParser import SwiftLintFramework extension SwiftLint { - struct Version: ParsableCommand { - @Flag(help: "Display full version info") + struct Version: AsyncParsableCommand { + @Flag(help: "Display full version info.") var verbose = false + @Flag(help: "Check whether a later version of SwiftLint is available after processing all files.") + var checkForUpdates = false static let configuration = CommandConfiguration(abstract: "Display the current version of SwiftLint") static var value: String { SwiftLintFramework.Version.current.value } - func run() throws { + func run() async { if verbose, let buildID = ExecutableInfo.buildID { print("Version:", Self.value) print("Build ID:", buildID) } else { print(Self.value) } + if checkForUpdates { + UpdateChecker.checkForUpdates() + } ExitHelper.successfullyExit() } } diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift index 59a6c08007..e1a2e987cc 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -50,6 +50,8 @@ struct LintOrAnalyzeArguments: ParsableArguments { var output: String? @Flag(help: "Show a live-updating progress bar instead of each file being processed.") var progress = false + @Flag(help: "Check whether a later version of SwiftLint is available after processing all files.") + var checkForUpdates = false } // MARK: - Common Argument Help diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift index 97cc91faa4..d1bbbb47fc 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -60,6 +60,9 @@ struct LintOrAnalyzeCommand { try Signposts.record(name: "LintOrAnalyzeCommand.PostProcessViolations") { try postProcessViolations(files: files, builder: builder) } + if options.checkForUpdates || builder.configuration.checkForUpdates { + UpdateChecker.checkForUpdates() + } } private static func collectViolations(builder: LintOrAnalyzeResultBuilder) async throws -> [SwiftLintFile] { @@ -283,6 +286,7 @@ struct LintOrAnalyzeOptions { let compilerLogPath: String? let compileCommands: String? let inProcessSourcekit: Bool + let checkForUpdates: Bool var verb: String { if autocorrect { diff --git a/Source/swiftlint/Helpers/UpdateChecker.swift b/Source/swiftlint/Helpers/UpdateChecker.swift new file mode 100644 index 0000000000..15f4294b85 --- /dev/null +++ b/Source/swiftlint/Helpers/UpdateChecker.swift @@ -0,0 +1,59 @@ +// swiftlint:disable file_header +// +// Adapted from periphery's UpdateChecker.swift +// +// https://github.com/peripheryapp/periphery +// +// Copyright (c) 2019 Ian Leitch +// Licensed under the MIT License +// +// See https://github.com/peripheryapp/periphery/blob/master/LICENSE.md for license information +// + +import Foundation +#if canImport(FoundationNetworking) +import FoundationNetworking +#endif +import SwiftLintFramework + +enum UpdateChecker { + static func checkForUpdates() { + guard let url = URL(string: "https://api.github.com/repos/realm/SwiftLint/releases/latest"), + let data = sendRequest(to: url), + let latestVersionNumber = parseVersionNumber(data) else { + print("Could not check latest SwiftLint version") + return + } + + let latestVersion = SwiftLintFramework.Version(value: latestVersionNumber) + if latestVersion > SwiftLintFramework.Version.current { + print("A new version of SwiftLint is available: \(latestVersionNumber)") + } else { + print("Your version of SwiftLint is up to date.") + } + } + + private static func parseVersionNumber(_ data: Data) -> String? { + guard let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []) as? [AnyHashable: Any] else { + return nil + } + return jsonObject["tag_name"] as? String + } + + private static func sendRequest(to url: URL) -> Data? { + var request = URLRequest(url: url) + request.setValue("SwiftLint", forHTTPHeaderField: "User-Agent") + request.setValue("application/vnd.github.v3+json", forHTTPHeaderField: "Accept") + let semaphore = DispatchSemaphore(value: 0) + var result: Data? + + let task = URLSession.shared.dataTask(with: request) { data, _, _ in + result = data + semaphore.signal() + } + task.resume() + + semaphore.wait() + return result + } +} diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 82f841c15f..858673608c 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -58,6 +58,7 @@ final class ConfigurationTests: SwiftLintTestCase { XCTAssertFalse(config.strict) XCTAssertNil(config.baseline) XCTAssertNil(config.writeBaseline) + XCTAssertFalse(config.checkForUpdates) } func testInitWithRelativePathAndRootPath() { @@ -447,6 +448,11 @@ final class ConfigurationTests: SwiftLintTestCase { let configuration = try Configuration(dict: ["write_baseline": baselinePath]) XCTAssertEqual(configuration.writeBaseline, baselinePath) } + + func testCheckForUpdates() throws { + let configuration = try Configuration(dict: ["check_for_updates": true]) + XCTAssertTrue(configuration.checkForUpdates) + } } // MARK: - ExcludeByPrefix option tests From 714bf4c8c20449d51a2fcd87866714c2823b8abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 7 Jul 2024 13:11:41 +0200 Subject: [PATCH 104/265] Document modified configurations used to lint examples (#5402) --- CHANGELOG.md | 3 ++ .../Documentation/RuleDocumentation.swift | 39 ++++++++++++------- .../Extensions/String+SwiftLint.swift | 4 ++ .../Models/RuleConfigurationDescription.swift | 15 ++++--- Source/SwiftLintCore/Protocols/Rule.swift | 16 +++----- Source/swiftlint/Commands/Rules.swift | 12 +++--- Tests/IntegrationTests/IntegrationTests.swift | 2 +- .../ConfigurationTests+MultipleConfigs.swift | 8 +++- 8 files changed, 61 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a767d5b379..ba52a01c10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,9 @@ [Ueeek](https://github.com/Ueeek) [#5615](https://github.com/realm/SwiftLint/issues/5615) +* Add modified configurations to examples in rule documentation. + [SimplyDanny](https://github.com/SimplyDanny) + * Add new option `evaluate_effective_access_control_level` to `missing_docs` rule. Setting it to `true` stops the rule from triggering on declarations inside of types with lower visibility. These declarations effectively diff --git a/Source/SwiftLintCore/Documentation/RuleDocumentation.swift b/Source/SwiftLintCore/Documentation/RuleDocumentation.swift index c46729fb00..c47a5d8383 100644 --- a/Source/SwiftLintCore/Documentation/RuleDocumentation.swift +++ b/Source/SwiftLintCore/Documentation/RuleDocumentation.swift @@ -52,6 +52,27 @@ struct RuleDocumentation { } return content.joined(separator: "\n\n") } + + private func formattedCode(_ example: Example) -> String { + if let config = example.configuration, let configuredRule = try? ruleType.init(configuration: config) { + let configDescription = configuredRule.createConfigurationDescription(exclusiveOptions: Set(config.keys)) + return """ + ```swift + // + // \(configDescription.yaml().linesPrefixed(with: "// ")) + // + + \(example.code) + + ``` + """ + } + return """ + ```swift + \(example.code) + ``` + """ + } } private func h1(_ text: String) -> String { "# \(text)" } @@ -60,30 +81,20 @@ private func h2(_ text: String) -> String { "## \(text)" } private func detailsSummary(_ rule: some Rule) -> String { let ruleDescription = """ - * **Identifier:** \(type(of: rule).description.identifier) + * **Identifier:** `\(type(of: rule).description.identifier)` * **Enabled by default:** \(rule is any OptInRule ? "No" : "Yes") * **Supports autocorrection:** \(rule is any CorrectableRule ? "Yes" : "No") * **Kind:** \(type(of: rule).description.kind) * **Analyzer rule:** \(rule is any AnalyzerRule ? "Yes" : "No") * **Minimum Swift compiler version:** \(type(of: rule).description.minSwiftVersion.rawValue) """ - if rule.configurationDescription.hasContent { - let configurationTable = rule.configurationDescription.markdown() - .split(separator: "\n") - .joined(separator: "\n ") + let description = rule.createConfigurationDescription() + if description.hasContent { return ruleDescription + """ * **Default configuration:** - \(configurationTable) + \(description.markdown().linesPrefixed(with: " ")) """ } return ruleDescription } - -private func formattedCode(_ example: Example) -> String { - return """ - ```swift - \(example.code) - ``` - """ -} diff --git a/Source/SwiftLintCore/Extensions/String+SwiftLint.swift b/Source/SwiftLintCore/Extensions/String+SwiftLint.swift index 44a7969490..fc9ebac802 100644 --- a/Source/SwiftLintCore/Extensions/String+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/String+SwiftLint.swift @@ -124,4 +124,8 @@ public extension String { .map { String(repeating: " ", count: spaces) + $0 } .joined(separator: "\n") } + + func linesPrefixed(with prefix: Self) -> Self { + split(separator: "\n").joined(separator: "\n\(prefix)") + } } diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index ce3f091476..11ce3b518b 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -27,7 +27,7 @@ public protocol Documentable { public struct RuleConfigurationDescription: Equatable { fileprivate let options: [RuleConfigurationOption] - fileprivate init(options: [RuleConfigurationOption]) { + fileprivate init(options: [RuleConfigurationOption], exclusiveOptions: Set = []) { if options.contains(.noOptions) { if options.count > 1 { queuedFatalError( @@ -39,15 +39,18 @@ public struct RuleConfigurationDescription: Equatable { ) } self.options = [] - } else { - self.options = options.filter { $0.value != .empty } + return } + let nonEmptyOptions = options.filter { $0.value != .empty } + self.options = exclusiveOptions.isEmpty + ? nonEmptyOptions + : nonEmptyOptions.filter { exclusiveOptions.contains($0.key) } } - static func from(configuration: some RuleConfiguration) -> Self { + static func from(configuration: some RuleConfiguration, exclusiveOptions: Set = []) -> Self { // Prefer custom descriptions. if let customDescription = configuration.parameterDescription { - return customDescription + return Self(options: customDescription.options, exclusiveOptions: exclusiveOptions) } let options: [RuleConfigurationOption] = Mirror(reflecting: configuration).children .compactMap { child -> RuleConfigurationDescription? in @@ -69,7 +72,7 @@ public struct RuleConfigurationDescription: Equatable { """ ) } - return Self(options: options) + return Self(options: options, exclusiveOptions: exclusiveOptions) } func allowedKeys() -> [String] { diff --git a/Source/SwiftLintCore/Protocols/Rule.swift b/Source/SwiftLintCore/Protocols/Rule.swift index 4aef5a78fa..ca48dc1ea9 100644 --- a/Source/SwiftLintCore/Protocols/Rule.swift +++ b/Source/SwiftLintCore/Protocols/Rule.swift @@ -3,19 +3,12 @@ import SourceKittenFramework /// An executable value that can identify issues (violations) in Swift source code. public protocol Rule { - /// The rule's description type. - associatedtype Description: Documentable - /// The type of the configuration used to configure this rule. associatedtype ConfigurationType: RuleConfiguration /// A verbose description of many of this rule's properties. static var description: RuleDescription { get } - /// A description of how this rule has been configured to run. It can be built using the annotated result builder. - @RuleConfigurationDescriptionBuilder - var configurationDescription: Description { get } - /// This rule's configuration. var configuration: ConfigurationType { get set } @@ -32,6 +25,9 @@ public protocol Rule { /// - throws: Throws if the configuration didn't match the expected format. init(configuration: Any) throws + /// Create a description of how this rule has been configured to run. + func createConfigurationDescription(exclusiveOptions: Set) -> RuleConfigurationDescription + /// Executes the rule on a file and returns any violations to the rule's expectations. /// /// - parameter file: The file for which to execute the rule. @@ -109,11 +105,11 @@ public extension Rule { /// The cache description which will be used to determine if a previous /// cached value is still valid given the new cache value. var cacheDescription: String { - (self as? any CacheDescriptionProvider)?.cacheDescription ?? configurationDescription.oneLiner() + (self as? any CacheDescriptionProvider)?.cacheDescription ?? createConfigurationDescription().oneLiner() } - var configurationDescription: some Documentable { - RuleConfigurationDescription.from(configuration: configuration) + func createConfigurationDescription(exclusiveOptions: Set = []) -> RuleConfigurationDescription { + RuleConfigurationDescription.from(configuration: configuration, exclusiveOptions: exclusiveOptions) } } diff --git a/Source/swiftlint/Commands/Rules.swift b/Source/swiftlint/Commands/Rules.swift index ef56251f08..dc709af831 100644 --- a/Source/swiftlint/Commands/Rules.swift +++ b/Source/swiftlint/Commands/Rules.swift @@ -70,10 +70,11 @@ extension SwiftLint { } print("\(description.consoleDescription)") - if rule.configurationDescription.hasContent { + let configDescription = rule.createConfigurationDescription() + if configDescription.hasContent { print("\nConfiguration (YAML):\n") print(" \(description.identifier):") - print(rule.configurationDescription.yaml().indent(by: 4)) + print(configDescription.yaml().indent(by: 4)) } guard description.triggeringExamples.isNotEmpty else { return } @@ -85,9 +86,10 @@ extension SwiftLint { } private func printConfig(for rule: any Rule) { - if rule.configurationDescription.hasContent { + let configDescription = rule.createConfigurationDescription() + if configDescription.hasContent { print("\(type(of: rule).identifier):") - print(rule.configurationDescription.yaml().indent(by: 2)) + print(configDescription.yaml().indent(by: 2)) } } @@ -141,7 +143,7 @@ private extension TextTable { ruleType.description.kind.rawValue, (rule is any AnalyzerRule) ? "yes" : "no", (rule is any SourceKitFreeRule) ? "no" : "yes", - truncate((defaultConfig ? rule : configuredRule ?? rule).configurationDescription.oneLiner()), + truncate((defaultConfig ? rule : configuredRule ?? rule).createConfigurationDescription().oneLiner()), ]) } } diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index 47ec32879e..67316b3613 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -60,7 +60,7 @@ final class IntegrationTests: SwiftLintTestCase { .map { """ \($0.identifier): - \($0.init().configurationDescription.yaml().indent(by: 2)) + \($0.init().createConfigurationDescription().yaml().indent(by: 2)) """ } .joined(separator: "\n") diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index 91e6f85cc6..bca39db30e 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -621,8 +621,12 @@ extension ConfigurationTests { ) XCTAssertEqual( - Set(configuration1.rulesWrapper.allRulesWrapped.map { $0.rule.configurationDescription.oneLiner() }), - Set(configuration2.rulesWrapper.allRulesWrapped.map { $0.rule.configurationDescription.oneLiner() }) + Set(configuration1.rulesWrapper.allRulesWrapped.map { + $0.rule.createConfigurationDescription().oneLiner() + }), + Set(configuration2.rulesWrapper.allRulesWrapped.map { + $0.rule.createConfigurationDescription().oneLiner() + }) ) XCTAssertEqual(Set(configuration1.includedPaths), Set(configuration2.includedPaths)) From f41c45667bf5dab720dc8101f03dbaf2503d26b1 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 7 Jul 2024 14:00:43 -0400 Subject: [PATCH 105/265] Enable the `closure_body_length` and `multiline_literal_brackets` rules (#5654) --- .swiftlint.yml | 5 +++-- .../Rules/Idiomatic/DuplicateImportsRuleExamples.swift | 1 + Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift | 3 ++- Tests/SwiftLintFrameworkTests/NestingRuleTests.swift | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index e956504102..8c71d1aa4d 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -16,7 +16,6 @@ opt_in_rules: disabled_rules: - anonymous_argument_in_multiline_closure - anyobject_protocol - - closure_body_length - conditional_returns_on_newline - convenience_type - discouraged_optional_collection @@ -34,7 +33,6 @@ disabled_rules: - multiline_arguments - multiline_arguments_brackets - multiline_function_chains - - multiline_literal_brackets - multiline_parameters - multiline_parameters_brackets - no_extension_access_modifier @@ -64,6 +62,9 @@ balanced_xctest_lifecycle: &unit_test_configuration test_parent_classes: - SwiftLintTestCase - XCTestCase +closure_body_length: + warning: 50 + error: 100 empty_xctest_method: *unit_test_configuration file_name: excluded: diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift index 2cd2c8d6e8..848c082da6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift @@ -37,6 +37,7 @@ internal struct DuplicateImportsRuleExamples { static let triggeringExamples = Array(corrections.keys.sorted()) + // swiftlint:disable:next closure_body_length static let corrections: [Example: Example] = { var corrections = [ Example(""" diff --git a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift index 10e22074c8..531373d1bc 100644 --- a/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/MissingDocsRuleTests.swift @@ -193,7 +193,8 @@ final class MissingDocsRuleTests: SwiftLintTestCase { XCTAssertFalse(configuration.excludesInheritedTypes) XCTAssertEqual( configuration.parameters.sorted { $0.value.rawValue > $1.value.rawValue }, - [ RuleParameter(severity: .warning, value: .public), + [ + RuleParameter(severity: .warning, value: .public), RuleParameter(severity: .warning, value: .open), ] ) diff --git a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift index 83a3c2db67..4386d10d4f 100644 --- a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift @@ -138,6 +138,7 @@ final class NestingRuleTests: SwiftLintTestCase { ] } + // swiftlint:disable:next closure_body_length triggeringExamples.append(contentsOf: detectingTypes.flatMap { type -> [Example] in [ .init(""" @@ -213,6 +214,7 @@ final class NestingRuleTests: SwiftLintTestCase { // swiftlint:disable:next function_body_length func testNestingWithoutCheckNestingInClosuresAndStatements() { var nonTriggeringExamples = NestingRule.description.nonTriggeringExamples + // swiftlint:disable:next closure_body_length nonTriggeringExamples.append(contentsOf: detectingTypes.flatMap { type -> [Example] in [ .init(""" @@ -386,6 +388,7 @@ final class NestingRuleTests: SwiftLintTestCase { ] }) + // swiftlint:disable:next closure_body_length var triggeringExamples = detectingTypes.flatMap { type -> [Example] in [ .init(""" From 202adf0220c020375ca4cfd06b8eb9b28c9fb0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 9 Jul 2024 20:52:01 +0200 Subject: [PATCH 106/265] Transfer checksum of binary package to plugin repository --- .github/workflows/plugins-release.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/plugins-release.yml b/.github/workflows/plugins-release.yml index 66b4c664e6..fd2f6b5704 100644 --- a/.github/workflows/plugins-release.yml +++ b/.github/workflows/plugins-release.yml @@ -8,10 +8,20 @@ jobs: dispatch: runs-on: ubuntu-latest steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Parse checksum + id: parse_checksum + run: echo "checksum=$(grep -o '[a-fA-F0-9]\{64\}' Package.swift)" >> $GITHUB_OUTPUT - name: Dispatch release of plugins package uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.SIMPLYDANNY_PLUGINS_SYNC }} repository: SimplyDanny/SwiftLintPlugins event-type: swiftlint-release - client-payload: '{"title": "${{ github.event.release.name }}", "tag": "${{ github.ref_name }}"}' + client-payload: |- + { + "title": "${{ github.event.release.name }}", + "tag": "${{ github.ref_name }}", + "checksum": "${{ steps.parse_checksum.outputs.checksum }}" + } From ed10aec5f82c3cd4e62d3966034d2face1adb2a4 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 10 Jul 2024 12:15:19 +0100 Subject: [PATCH 107/265] Enable `implicit_return` and fix all violations (#5658) --- .swiftlint.yml | 1 - .../SourceKittenDictionary+SwiftUI.swift | 4 +- ...scouragedOptionalBooleanRuleExamples.swift | 2 +- ...iscouragedOptionalCollectionExamples.swift | 2 +- .../Rules/Idiomatic/GenericTypeNameRule.swift | 2 +- .../Idiomatic/NoGroupingExtensionRule.swift | 4 +- .../Rules/Idiomatic/ObjectLiteralRule.swift | 2 +- .../PreferZeroOverExplicitInitRule.swift | 10 ++--- .../Rules/Idiomatic/SyntacticSugarRule.swift | 10 ++--- .../Idiomatic/UnneededBreakInSwitchRule.swift | 2 +- .../VoidFunctionInTernaryConditionRule.swift | 2 +- .../Idiomatic/XCTSpecificMatcherRule.swift | 2 +- .../Lint/AccessibilityLabelForImageRule.swift | 2 +- .../AccessibilityTraitForButtonRule.swift | 4 +- .../Rules/Lint/CommentSpacingRule.swift | 8 ++-- .../Rules/Lint/CompilerProtocolInitRule.swift | 2 +- .../Rules/Lint/ExpiringTodoRule.swift | 4 +- .../Rules/Lint/PeriodSpacingRule.swift | 10 ++--- .../Lint/ProhibitedInterfaceBuilderRule.swift | 2 +- .../Rules/Lint/QuickDiscouragedCallRule.swift | 6 +-- .../QuickDiscouragedFocusedTestRule.swift | 2 +- .../QuickDiscouragedPendingTestRule.swift | 2 +- .../Rules/Lint/RequiredEnumCaseRule.swift | 2 +- .../Rules/Lint/StrongIBOutletRule.swift | 2 +- .../Rules/Lint/UnusedDeclarationRule.swift | 16 ++++---- .../Rules/Lint/UnusedImportRule.swift | 6 +-- .../ClosureBodyLengthRuleExamples.swift | 14 +++---- .../Rules/Metrics/FileLengthRule.swift | 2 +- .../Rules/Metrics/TypeBodyLengthRule.swift | 2 +- .../ContainsOverFilterCountRule.swift | 4 +- .../ContainsOverFilterIsEmptyRule.swift | 2 +- .../ContainsOverFirstNotNilRule.swift | 6 +-- .../ContainsOverRangeNilComparisonRule.swift | 2 +- .../CyclomaticComplexityConfiguration.swift | 2 +- .../FileHeaderConfiguration.swift | 6 +-- .../ImplicitReturnConfiguration.swift | 2 +- .../LineLengthConfiguration.swift | 2 +- .../NameConfiguration.swift | 4 +- .../Style/ClosureEndIndentationRule.swift | 13 +++--- .../Style/ClosureParameterPositionRule.swift | 2 +- .../Rules/Style/CollectionAlignmentRule.swift | 12 +++--- .../Rules/Style/CommaInheritanceRule.swift | 4 +- .../Rules/Style/CommaRule.swift | 2 +- .../ComputedAccessorsOrderRuleExamples.swift | 4 +- .../Rules/Style/EmptyEnumArgumentsRule.swift | 4 +- .../Rules/Style/ExplicitSelfRule.swift | 4 +- .../Rules/Style/FileHeaderRule.swift | 10 ++--- .../LiteralExpressionEndIndentationRule.swift | 9 ++--- .../Rules/Style/ModifierOrderRule.swift | 6 +-- .../Style/MultilineFunctionChainsRule.swift | 10 ++--- .../MultilineParametersBracketsRule.swift | 4 +- .../Style/NumberSeparatorRuleExamples.swift | 4 +- .../Style/OperatorUsageWhitespaceRule.swift | 8 ++-- .../PreferSelfTypeOverTypeOfSelfRule.swift | 2 +- .../Rules/Style/SingleTestClassRule.swift | 8 ++-- .../Rules/Style/SortedImportsRule.swift | 14 +++---- .../Rules/Style/StatementPositionRule.swift | 12 +++--- .../Rules/Style/SwitchCaseAlignmentRule.swift | 5 +-- .../Rules/Style/SwitchCaseOnNewlineRule.swift | 2 +- .../Rules/Style/TrailingNewlineRule.swift | 2 +- .../Rules/Style/TypeContentsOrderRule.swift | 2 +- .../VerticalWhitespaceBetweenCasesRule.swift | 4 +- .../VerticalWhitespaceClosingBracesRule.swift | 2 +- .../VerticalWhitespaceOpeningBracesRule.swift | 2 +- .../Rules/Style/VerticalWhitespaceRule.swift | 2 +- .../Extensions/Array+SwiftLint.swift | 8 ++-- .../Extensions/Configuration+FileGraph.swift | 4 +- .../Configuration+FileGraphSubtypes.swift | 2 +- .../Configuration+LintableFiles.swift | 4 +- .../Extensions/Configuration+Merging.swift | 2 +- .../Extensions/Configuration+Parsing.swift | 8 ++-- .../Extensions/Dictionary+SwiftLint.swift | 40 +++++++++---------- .../Extensions/FileManager+SwiftLint.swift | 2 +- .../Extensions/NSRange+SwiftLint.swift | 2 +- .../NSRegularExpression+SwiftLint.swift | 6 +-- .../Extensions/String+SwiftLint.swift | 10 ++--- ...ftDeclarationAttributeKind+Swiftlint.swift | 4 +- .../Extensions/SwiftLintFile+Cache.swift | 14 +++---- .../Extensions/SwiftLintFile+Regex.swift | 16 ++++---- .../Extensions/SwiftSyntax+SwiftLint.swift | 2 +- .../Extensions/SyntaxKind+SwiftLint.swift | 2 +- .../Models/AccessControlLevel.swift | 4 +- .../SwiftLintCore/Models/Configuration.swift | 4 +- Source/SwiftLintCore/Models/Correction.swift | 2 +- Source/SwiftLintCore/Models/Example.swift | 6 +-- ...hableConfigurationRuleWrapperWrapper.swift | 2 +- Source/SwiftLintCore/Models/Linter.swift | 16 ++++---- Source/SwiftLintCore/Models/LinterCache.swift | 4 +- Source/SwiftLintCore/Models/Location.swift | 2 +- Source/SwiftLintCore/Models/Region.swift | 6 +-- .../Models/RuleDescription.swift | 6 +-- Source/SwiftLintCore/Models/RuleList.swift | 6 +-- .../SwiftLintCore/Models/RuleRegistry.swift | 2 +- Source/SwiftLintCore/Models/RuleStorage.swift | 2 +- .../SwiftLintCore/Models/StyleViolation.swift | 2 +- .../SwiftLintCore/Models/SwiftLintFile.swift | 8 ++-- .../Models/SwiftLintSyntaxMap.swift | 6 +-- .../Models/SwiftLintSyntaxToken.swift | 8 ++-- .../SwiftLintCore/Models/SwiftVersion.swift | 6 +-- .../Models/ViolationSeverity.swift | 2 +- Source/SwiftLintCore/Models/YamlParser.swift | 6 +-- Source/SwiftLintCore/Protocols/ASTRule.swift | 10 ++--- .../Protocols/CollectingRule.swift | 6 +-- Source/SwiftLintCore/Protocols/Rule.swift | 8 ++-- .../SwiftLintCore/Reporters/CSVReporter.swift | 2 +- .../Reporters/CheckstyleReporter.swift | 4 +- .../Reporters/CodeClimateReporter.swift | 4 +- .../GitHubActionsLoggingReporter.swift | 4 +- .../Reporters/GitLabJUnitReporter.swift | 2 +- .../Reporters/HTMLReporter.swift | 3 +- .../Reporters/JSONReporter.swift | 4 +- .../Reporters/MarkdownReporter.swift | 2 +- .../Reporters/RelativePathReporter.swift | 4 +- .../Reporters/SARIFReporter.swift | 2 +- .../Reporters/SonarQubeReporter.swift | 4 +- .../Reporters/XcodeReporter.swift | 4 +- .../RegexConfiguration.swift | 4 +- Source/SwiftLintCore/Rules/CustomRules.swift | 4 +- .../Rules/SuperfluousDisableCommandRule.swift | 4 +- .../Commands/Common/RulesFilterOptions.swift | 4 +- .../Configuration+CommandLine.swift | 2 +- Source/swiftlint/Helpers/Benchmark.swift | 2 +- .../Helpers/CompilerArgumentsExtractor.swift | 2 +- .../Helpers/LintOrAnalyzeCommand.swift | 4 +- .../Helpers/LintableFilesVisitor.swift | 14 +++---- Tests/CLITests/RulesFilterTests.swift | 6 +-- Tests/IntegrationTests/IntegrationTests.swift | 2 +- .../CollectingRuleTests.swift | 14 +++---- .../ConfigurationTests+MultipleConfigs.swift | 4 +- .../ConfigurationTests.swift | 2 +- .../CustomRulesTests.swift | 2 +- .../ExpiringTodoRuleTests.swift | 4 +- .../FunctionBodyLengthRuleTests.swift | 2 +- Tests/SwiftLintFrameworkTests/GlobTests.swift | 2 +- .../LinterCacheTests.swift | 12 +++--- .../ObjectLiteralRuleTests.swift | 2 +- .../ReporterTests.swift | 2 +- Tests/SwiftLintFrameworkTests/RuleTests.swift | 8 ++-- .../YamlSwiftLintTests.swift | 2 +- Tests/SwiftLintTestHelpers/TestHelpers.swift | 22 +++++----- 140 files changed, 360 insertions(+), 367 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 8c71d1aa4d..b4f528c7cd 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -26,7 +26,6 @@ disabled_rules: - file_types_order - force_unwrapping - function_default_parameter_at_end - - implicit_return - indentation_width - inert_defer - missing_docs diff --git a/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift b/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift index fc6a4d52fd..088917375e 100644 --- a/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift +++ b/Source/SwiftLintBuiltInRules/Extensions/SourceKittenDictionary+SwiftUI.swift @@ -135,7 +135,7 @@ extension SourceKittenDictionary { /// Whether or not the dictionary represents a SwiftUI View with an `accesibilityHidden(true)` /// or `accessibility(hidden: true)` modifier. func hasAccessibilityHiddenModifier(in file: SwiftLintFile) -> Bool { - return hasModifier( + hasModifier( anyOf: [ SwiftUIModifier( name: "accessibilityHidden", @@ -153,7 +153,7 @@ extension SourceKittenDictionary { /// Whether or not the dictionary represents a SwiftUI View with an `accessibilityElement()` or /// `accessibilityElement(children: .ignore)` modifier (`.ignore` is the default parameter value). func hasAccessibilityElementChildrenIgnoreModifier(in file: SwiftLintFile) -> Bool { - return hasModifier( + hasModifier( anyOf: [ SwiftUIModifier( name: "accessibilityElement", diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift index 77b3056c03..40506631bd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalBooleanRuleExamples.swift @@ -167,5 +167,5 @@ private func wrapExample(_ type: String, _ test: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example("\(type) Foo {\n\t\(test)\n}", file: file, line: line) + Example("\(type) Foo {\n\t\(test)\n}", file: file, line: line) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift index ea8e5b76df..b289d34cb6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DiscouragedOptionalCollectionExamples.swift @@ -214,7 +214,7 @@ private func wrapExample(_ type: String, _ test: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example(""" + Example(""" \(type) Foo { \(test) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift index 154a6b6173..91502f3403 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/GenericTypeNameRule.swift @@ -39,7 +39,7 @@ struct GenericTypeNameRule: Rule { Example("typealias BackwardTriple = (T3, T2_Bar, T1)"), Example("typealias DictionaryOfStrings<↓T_Foo: Hashable> = Dictionary"), ] + ["class", "struct", "enum"].flatMap { type -> [Example] in - return [ + [ Example("\(type) Foo<↓T_Foo> {}"), Example("\(type) Foo {}"), Example("\(type) Foo<↓T_Foo, ↓U_Foo> {}"), diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift index 0c4a79e2af..78665318cb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift @@ -23,9 +23,9 @@ struct NoGroupingExtensionRule: OptInRule { ) func validate(file: SwiftLintFile) -> [StyleViolation] { - return Visitor(configuration: configuration, file: file) + Visitor(configuration: configuration, file: file) .walk(tree: file.syntaxTree) { visitor in - return visitor.extensionDeclarations.compactMap { decl in + visitor.extensionDeclarations.compactMap { decl in guard visitor.typeDeclarations.contains(decl.name) else { return nil } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift index 04e03df62f..44696dc92f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift @@ -72,7 +72,7 @@ private extension ObjectLiteralRule { } private func inits(forClasses names: [String]) -> [String] { - return names.flatMap { name in + names.flatMap { name in [ name, name + ".init", diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift index 3658911bd1..c9f0bd9064 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferZeroOverExplicitInitRule.swift @@ -74,31 +74,31 @@ private extension FunctionCallExprSyntax { } var isCGPointZeroCall: Bool { - return name == "CGPoint" && + name == "CGPoint" && argumentNames == ["x", "y"] && argumentsAreAllZero } var isCGSizeCall: Bool { - return name == "CGSize" && + name == "CGSize" && argumentNames == ["width", "height"] && argumentsAreAllZero } var isCGRectCall: Bool { - return name == "CGRect" && + name == "CGRect" && argumentNames == ["x", "y", "width", "height"] && argumentsAreAllZero } var isCGVectorCall: Bool { - return name == "CGVector" && + name == "CGVector" && argumentNames == ["dx", "dy"] && argumentsAreAllZero } var isUIEdgeInsetsCall: Bool { - return name == "UIEdgeInsets" && + name == "UIEdgeInsets" && argumentNames == ["top", "left", "bottom", "right"] && argumentsAreAllZero } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift index b398598357..0f5c7ae179 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift @@ -20,15 +20,15 @@ struct SyntacticSugarRule: CorrectableRule, SourceKitFreeRule { return visitor.walk(file: file) { visitor in flattenViolations(visitor.violations) }.map { violation in - return StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: file, byteOffset: ByteCount(violation.position)), - reason: violation.type.violationReason) + StyleViolation(ruleDescription: Self.description, + severity: configuration.severity, + location: Location(file: file, byteOffset: ByteCount(violation.position)), + reason: violation.type.violationReason) } } private func flattenViolations(_ violations: [SyntacticSugarRuleViolation]) -> [SyntacticSugarRuleViolation] { - return violations.flatMap { [$0] + flattenViolations($0.children) } + violations.flatMap { [$0] + flattenViolations($0.children) } } func correct(file: SwiftLintFile) -> [Correction] { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift index 657d07d54b..abf8ed04c2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift @@ -4,7 +4,7 @@ private func embedInSwitch( _ text: String, case: String = "case .bar", file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example(""" + Example(""" switch foo { \(`case`): \(text) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift index 51b7e2890c..8d6cc648c5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift @@ -144,7 +144,7 @@ private extension VoidFunctionInTernaryConditionRule { private extension ExprListSyntax { var containsAssignment: Bool { - return children(viewMode: .sourceAccurate).contains(where: { $0.is(AssignmentExprSyntax.self) }) + children(viewMode: .sourceAccurate).contains(where: { $0.is(AssignmentExprSyntax.self) }) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift index 7979adc1cc..f99ed60dcb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift @@ -124,7 +124,7 @@ private enum TwoArgsXCTAssert: String { .prefix(2) .map { $0.expression.trimmedDescription } .sorted { arg1, _ -> Bool in - return protectedArguments.contains(arg1) + protectedArguments.contains(arg1) } // diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift index a5432e5b80..b2f6a69ea2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift @@ -124,7 +124,7 @@ private extension SourceKittenDictionary { /// Whether or not the dictionary represents a SwiftUI View with an `accesibilityLabel(_:)` /// or `accessibility(label:)` modifier. func hasAccessibilityLabelModifier(in file: SwiftLintFile) -> Bool { - return hasModifier( + hasModifier( anyOf: [ SwiftUIModifier( name: "accessibilityLabel", diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift index 7fa33b38df..d122ad0bae 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift @@ -88,7 +88,7 @@ private extension SourceKittenDictionary { /// or by a `gesture`, `simultaneousGesture`, or `highPriorityGesture` modifier with an argument /// starting with a `TapGesture` object with a count of 1 (default value is 1). func hasOnSingleTapModifier(in file: SwiftLintFile) -> Bool { - return hasModifier( + hasModifier( anyOf: [ SwiftUIModifier( name: "onTapGesture", @@ -120,7 +120,7 @@ private extension SourceKittenDictionary { /// Whether or not the dictionary represents a SwiftUI View with an `accessibilityAddTraits()` or /// `accessibility(addTraits:)` modifier with the specified trait (specify trait as a String). func hasAccessibilityTrait(_ trait: String, in file: SwiftLintFile) -> Bool { - return hasModifier( + hasModifier( anyOf: [ SwiftUIModifier( name: "accessibilityAddTraits", diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift index 0acdce2a9b..6a6ab516f2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift @@ -123,7 +123,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { .filter(\.kind.isComment) .map { $0.range.toSourceKittenByteRange() } .compactMap { (range: ByteRange) -> [NSRange]? in - return file.stringView + file.stringView .substringWithByteRange(range) .map(StringView.init) .map { commentBody in @@ -134,7 +134,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { .compactMap { result in // Set the location to be directly before the first non-slash, // non-whitespace character which was matched - return file.stringView.byteRangeToNSRange( + file.stringView.byteRangeToNSRange( ByteRange( // Safe to mix NSRange offsets with byte offsets here because the regex can't // contain multi-byte characters @@ -149,7 +149,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { } func validate(file: SwiftLintFile) -> [StyleViolation] { - return violationRanges(in: file).map { range in + violationRanges(in: file).map { range in StyleViolation( ruleDescription: Self.description, severity: configuration.severity, @@ -159,6 +159,6 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { } func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { - return (violationRange, " ") + (violationRange, " ") } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift index d97ceaf1e5..0227dcf8fe 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CompilerProtocolInitRule.swift @@ -105,7 +105,7 @@ private struct ExpressibleByCompiler { }() func match(arguments: [String]) -> Bool { - return self.arguments.contains(arguments) + self.arguments.contains(arguments) } private static let byArrayLiteral: ExpressibleByCompiler = { diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift index e0f6776343..1e09ba3db0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift @@ -117,13 +117,13 @@ struct ExpiringTodoRule: OptInRule { private extension Date { var isAfterToday: Bool { - return Calendar.current.compare(.init(), to: self, toGranularity: .day) == .orderedAscending + Calendar.current.compare(.init(), to: self, toGranularity: .day) == .orderedAscending } } private extension SyntaxKind { /// Returns if the syntax kind is comment-like. var isCommentLike: Bool { - return Self.commentKinds.contains(self) + Self.commentKinds.contains(self) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift index fbda7181e3..80263d702e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift @@ -53,16 +53,16 @@ struct PeriodSpacingRule: SourceKitFreeRule, OptInRule, SubstitutionCorrectableR .filter(\.kind.isComment) .map { $0.range.toSourceKittenByteRange() } .compactMap { (range: ByteRange) -> [NSRange]? in - return file.stringView + file.stringView .substringWithByteRange(range) .map(StringView.init) .map { commentBody in // Look for a period followed by two or more whitespaces but not new line or carriage returns - return regex(#"\.[^\S\r\n]{2,}"#) + regex(#"\.[^\S\r\n]{2,}"#) .matches(in: commentBody) .compactMap { result in // Set the location to start from the second whitespace till the last one. - return file.stringView.byteRangeToNSRange( + file.stringView.byteRangeToNSRange( ByteRange( // Safe to mix NSRange offsets with byte offsets here because the // regex can't contain multi-byte characters @@ -77,7 +77,7 @@ struct PeriodSpacingRule: SourceKitFreeRule, OptInRule, SubstitutionCorrectableR } func validate(file: SwiftLintFile) -> [StyleViolation] { - return violationRanges(in: file).map { range in + violationRanges(in: file).map { range in StyleViolation( ruleDescription: Self.description, severity: configuration.severity, @@ -87,6 +87,6 @@ struct PeriodSpacingRule: SourceKitFreeRule, OptInRule, SubstitutionCorrectableR } func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { - return (violationRange, "") + (violationRange, "") } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift index c3ca38b0e8..662f12c961 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ProhibitedInterfaceBuilderRule.swift @@ -37,7 +37,7 @@ private extension ProhibitedInterfaceBuilderRule { } private func wrapExample(_ text: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example(""" + Example(""" class ViewController: UIViewController { \(text) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRule.swift index 13d5380cab..9b65c81127 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedCallRule.swift @@ -15,7 +15,7 @@ struct QuickDiscouragedCallRule: OptInRule { func validate(file: SwiftLintFile) -> [StyleViolation] { let dict = file.structureDictionary let testClasses = dict.substructure.filter { - return $0.inheritedTypes.isNotEmpty && + $0.inheritedTypes.isNotEmpty && $0.declarationKind == .class } @@ -34,7 +34,7 @@ struct QuickDiscouragedCallRule: OptInRule { } private func validate(file: SwiftLintFile, dictionary: SourceKittenDictionary) -> [StyleViolation] { - return dictionary.traverseDepthFirst { subDict in + dictionary.traverseDepthFirst { subDict in guard let kind = subDict.expressionKind else { return nil } return validate(file: file, kind: kind, dictionary: subDict) } @@ -60,7 +60,7 @@ struct QuickDiscouragedCallRule: OptInRule { } private func violationOffsets(in substructure: [SourceKittenDictionary]) -> [ByteCount] { - return substructure.flatMap { dictionary -> [ByteCount] in + substructure.flatMap { dictionary -> [ByteCount] in let substructure = dictionary.substructure.flatMap { dict -> [SourceKittenDictionary] in if dict.expressionKind == .closure { return dict.substructure diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRule.swift index c59e7a32e3..e04c831aba 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedFocusedTestRule.swift @@ -48,7 +48,7 @@ private extension ClassDeclSyntax { private extension FunctionDeclSyntax { var isSpecFunction: Bool { - return name.tokenKind == .identifier("spec") && + name.tokenKind == .identifier("spec") && signature.parameterClause.parameters.isEmpty && modifiers.contains(keyword: .override) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRule.swift index d326c26d18..14c4bb8acc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/QuickDiscouragedPendingTestRule.swift @@ -48,7 +48,7 @@ private extension ClassDeclSyntax { private extension FunctionDeclSyntax { var isSpecFunction: Bool { - return name.tokenKind == .identifier("spec") && + name.tokenKind == .identifier("spec") && signature.parameterClause.parameters.isEmpty && modifiers.contains(keyword: .override) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift index 741ef7e1a4..e702deee4a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredEnumCaseRule.swift @@ -167,7 +167,7 @@ private extension RequiredEnumCaseRule { private extension EnumDeclSyntax { var enumCasesNames: [String] { - return memberBlock.members + memberBlock.members .flatMap { member -> [String] in guard let enumCaseDecl = member.decl.as(EnumCaseDeclSyntax.self) else { return [] diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift index 36daed5e35..8a88d4f866 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/StrongIBOutletRule.swift @@ -69,7 +69,7 @@ private extension VariableDeclSyntax { } private func wrapExample(_ text: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example(""" + Example(""" class ViewController: UIViewController { \(text) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index 8d483a72ec..6b0d3ede37 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -70,7 +70,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { // Unused declarations are: // 1. all declarations // 2. minus all references - return declaredUSRs + declaredUSRs .filter { !allReferencedUSRs.contains($0.usr) } .map { $0.nameOffset } .sorted() @@ -81,7 +81,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { private extension SwiftLintFile { func index(compilerArguments: [String]) -> SourceKittenDictionary? { - return path + path .flatMap { path in try? Request.index(file: path, arguments: compilerArguments) .send() @@ -90,7 +90,7 @@ private extension SwiftLintFile { } func referencedUSRs(index: SourceKittenDictionary, editorOpen: SourceKittenDictionary) -> Set { - return Set(index.traverseEntitiesDepthFirst { parent, entity -> String? in + Set(index.traverseEntitiesDepthFirst { parent, entity -> String? in if let usr = entity.usr, let kind = entity.kind, kind.starts(with: "source.lang.swift.ref"), @@ -109,7 +109,7 @@ private extension SwiftLintFile { func declaredUSRs(index: SourceKittenDictionary, editorOpen: SourceKittenDictionary, compilerArguments: [String], configuration: UnusedDeclarationConfiguration) -> Set { - return Set(index.traverseEntitiesDepthFirst { _, indexEntity in + Set(index.traverseEntitiesDepthFirst { _, indexEntity in self.declaredUSR(indexEntity: indexEntity, editorOpen: editorOpen, compilerArguments: compilerArguments, configuration: configuration) }) @@ -225,15 +225,15 @@ private extension SwiftLintFile { private extension SourceKittenDictionary { var usr: String? { - return value["key.usr"] as? String + value["key.usr"] as? String } var annotatedDeclaration: String? { - return value["key.annotated_decl"] as? String + value["key.annotated_decl"] as? String } var isImplicit: Bool { - return value["key.is_implicit"] as? Bool == true + value["key.is_implicit"] as? Bool == true } func propertyAtOffset(_ offset: ByteCount, property: KeyPath) -> T? { @@ -251,7 +251,7 @@ private extension SourceKittenDictionary { } func shouldSkipRelated(relatedUSRsToSkip: Set) -> Bool { - return (value["key.related"] as? [[String: any SourceKitRepresentable]])? + (value["key.related"] as? [[String: any SourceKitRepresentable]])? .compactMap { SourceKittenDictionary($0).usr } .contains(where: relatedUSRsToSkip.contains) == true } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift index 5a51d7f0e3..0e342fabd7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift @@ -18,7 +18,7 @@ struct UnusedImportRule: CorrectableRule, AnalyzerRule { ) func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] { - return importUsage(in: file, compilerArguments: compilerArguments).map { importUsage in + importUsage(in: file, compilerArguments: compilerArguments).map { importUsage in StyleViolation(ruleDescription: Self.description, severity: configuration.severity, location: Location(file: file, characterOffset: importUsage.violationRange?.location ?? 1), @@ -186,7 +186,7 @@ private extension SwiftLintFile { } func rangedAndSortedUnusedImports(of unusedImports: [String]) -> [(String, NSRange)] { - return unusedImports + unusedImports .compactMap { module in match(pattern: "^(@(?!_exported)\\w+ +)?import +\(module)\\b.*?\n").first.map { (module, $0.0) } } @@ -240,7 +240,7 @@ private extension SwiftLintFile { } func offsetPerLine() -> [Int: Int64] { - return Dictionary( + Dictionary( uniqueKeysWithValues: contents.bridge() .components(separatedBy: "\n") .map { Int64($0.bridge().lengthOfBytes(using: .utf8)) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift index af7f9b1ce7..db248733f9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/ClosureBodyLengthRuleExamples.swift @@ -30,7 +30,7 @@ internal struct ClosureBodyLengthRuleExamples { // MARK: - Private private func singleLineClosure(file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example("foo.bar { $0 }", file: file, line: line) + Example("foo.bar { $0 }", file: file, line: line) } private func trailingClosure(_ violationSymbol: String = "", @@ -39,7 +39,7 @@ private func trailingClosure(_ violationSymbol: String = "", emptyLinesCount: Int, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example(""" + Example(""" foo.bar \(violationSymbol){ toto in \((0.. Example { - return Example(""" + Example(""" foo.bar(\(violationSymbol){ toto in \((0.. Example { - return Example(""" + Example(""" foo.bar(label: \(violationSymbol){ toto in \((0.. Example { - return Example(""" + Example(""" foo.bar(label: \(violationSymbol){ toto in \((0.. Example { - return Example(""" + Example(""" foo.bar(label: \(violationSymbol){ toto in \((0.. Example { - return Example(""" + Example(""" let foo: Bar = \(violationSymbol){ toto in \tlet bar = Bar() \((0.. Int { let commentKinds = SyntaxKind.commentKinds return file.syntaxKindsByLines.filter { kinds in - return !Set(kinds).isSubset(of: commentKinds) + !Set(kinds).isSubset(of: commentKinds) }.count } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift index 0e5689c110..0c3da3c68b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/TypeBodyLengthRule.swift @@ -6,7 +6,7 @@ private func wrapExample( _ add: String = "", file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example("\(prefix)\(type) Abc {\n" + + Example("\(prefix)\(type) Abc {\n" + repeatElement(template, count: count).joined() + "\(add)}\n", file: file, line: line) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift index 4018c4b1c6..ba5eae2559 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterCountRule.swift @@ -10,7 +10,7 @@ struct ContainsOverFilterCountRule: OptInRule { description: "Prefer `contains` over comparing `filter(where:).count` to 0", kind: .performance, nonTriggeringExamples: [">", "==", "!="].flatMap { operation in - return [ + [ Example("let result = myList.filter(where: { $0 % 2 == 0 }).count \(operation) 1"), Example("let result = myList.filter { $0 % 2 == 0 }.count \(operation) 1"), Example("let result = myList.filter(where: { $0 % 2 == 0 }).count \(operation) 01"), @@ -21,7 +21,7 @@ struct ContainsOverFilterCountRule: OptInRule { Example("let result = myList.contains(10)"), ], triggeringExamples: [">", "==", "!="].flatMap { operation in - return [ + [ Example("let result = ↓myList.filter(where: { $0 % 2 == 0 }).count \(operation) 0"), Example("let result = ↓myList.filter { $0 % 2 == 0 }.count \(operation) 0"), Example("let result = ↓myList.filter(where: someFunction).count \(operation) 0"), diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift index 166459389f..d2546c70cf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFilterIsEmptyRule.swift @@ -10,7 +10,7 @@ struct ContainsOverFilterIsEmptyRule: OptInRule { description: "Prefer `contains` over using `filter(where:).isEmpty`", kind: .performance, nonTriggeringExamples: [">", "==", "!="].flatMap { operation in - return [ + [ Example("let result = myList.filter(where: { $0 % 2 == 0 }).count \(operation) 1"), Example("let result = myList.filter { $0 % 2 == 0 }.count \(operation) 1"), ] diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift index b77eb1b9e3..fbe945218e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverFirstNotNilRule.swift @@ -10,14 +10,14 @@ struct ContainsOverFirstNotNilRule: OptInRule { description: "Prefer `contains` over `first(where:) != nil` and `firstIndex(where:) != nil`.", kind: .performance, nonTriggeringExamples: ["first", "firstIndex"].flatMap { method in - return [ + [ Example("let \(method) = myList.\(method)(where: { $0 % 2 == 0 })"), Example("let \(method) = myList.\(method) { $0 % 2 == 0 }"), ] }, triggeringExamples: ["first", "firstIndex"].flatMap { method in - return ["!=", "=="].flatMap { comparison in - return [ + ["!=", "=="].flatMap { comparison in + [ Example("↓myList.\(method) { $0 % 2 == 0 } \(comparison) nil"), Example("↓myList.\(method)(where: { $0 % 2 == 0 }) \(comparison) nil"), Example("↓myList.map { $0 + 1 }.\(method)(where: { $0 % 2 == 0 }) \(comparison) nil"), diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift index 05b62733a9..a0f5857480 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/ContainsOverRangeNilComparisonRule.swift @@ -16,7 +16,7 @@ struct ContainsOverRangeNilComparisonRule: OptInRule { Example("resourceString.range(of: rule.regex, options: .regularExpression) != nil"), ], triggeringExamples: ["!=", "=="].flatMap { comparison in - return [ + [ Example("↓myString.range(of: \"Test\") \(comparison) nil") ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift index bb396f6c51..3d366cd6c2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift @@ -11,6 +11,6 @@ struct CyclomaticComplexityConfiguration: RuleConfiguration { private(set) var ignoresCaseStatements = false var params: [RuleParameter] { - return length.params + length.params } } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift index fd0557b99a..f3176dcf76 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift @@ -85,13 +85,11 @@ struct FileHeaderConfiguration: SeverityBasedRuleConfiguration { } private func regexFromString(for file: SwiftLintFile, using pattern: String) -> NSRegularExpression? { - return makeRegex(for: file, using: pattern, options: Self.stringRegexOptions, - escapeFileName: false) + makeRegex(for: file, using: pattern, options: Self.stringRegexOptions, escapeFileName: false) } private func regexFromPattern(for file: SwiftLintFile, using pattern: String) -> NSRegularExpression? { - return makeRegex(for: file, using: pattern, options: Self.patternRegexOptions, - escapeFileName: true) + makeRegex(for: file, using: pattern, options: Self.patternRegexOptions, escapeFileName: true) } func forbiddenRegex(for file: SwiftLintFile) -> NSRegularExpression? { diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift index 8c1c2af319..edcd8f2c68 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift @@ -29,6 +29,6 @@ struct ImplicitReturnConfiguration: SeverityBasedRuleConfiguration { } func isKindIncluded(_ kind: ReturnKind) -> Bool { - return self.includedKinds.contains(kind) + includedKinds.contains(kind) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift index af1845eb9e..a8baca89c9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift @@ -18,6 +18,6 @@ struct LineLengthConfiguration: RuleConfiguration { private(set) var excludedLinesPatterns: Set = [] var params: [RuleParameter] { - return length.params + length.params } } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift index 0cf9e7ced7..6c9ee3e4b4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NameConfiguration.swift @@ -20,11 +20,11 @@ struct NameConfiguration: RuleConfiguration, InlinableOptionType { private(set) var validatesStartWithLowercase = StartWithLowercaseConfiguration.error var minLengthThreshold: Int { - return max(minLength.warning, minLength.error ?? minLength.warning) + max(minLength.warning, minLength.error ?? minLength.warning) } var maxLengthThreshold: Int { - return min(maxLength.warning, maxLength.error ?? maxLength.warning) + min(maxLength.warning, maxLength.error ?? maxLength.warning) } var allowedSymbolsAndAlphanumerics: CharacterSet { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift index 018848ef83..4c64aa58ed 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift @@ -17,8 +17,8 @@ struct ClosureEndIndentationRule: Rule, OptInRule { fileprivate static let notWhitespace = regex("[^\\s]") func validate(file: SwiftLintFile) -> [StyleViolation] { - return violations(in: file).map { violation in - return styleViolation(for: violation, in: file) + violations(in: file).map { violation in + styleViolation(for: violation, in: file) } } @@ -62,8 +62,7 @@ extension ClosureEndIndentationRule: CorrectableRule { } var corrections = correctedLocations.map { - return Correction(ruleDescription: Self.description, - location: Location(file: file, characterOffset: $0)) + Correction(ruleDescription: Self.description, location: Location(file: file, characterOffset: $0)) } file.write(correctedContents) @@ -114,7 +113,7 @@ extension ClosureEndIndentationRule { } fileprivate func violations(in file: SwiftLintFile) -> [Violation] { - return file.structureDictionary.traverseDepthFirst { subDict in + file.structureDictionary.traverseDepthFirst { subDict in guard let kind = subDict.expressionKind else { return nil } return violations(in: file, of: kind, dictionary: subDict) } @@ -204,7 +203,7 @@ extension ClosureEndIndentationRule { } return closureArguments.compactMap { dictionary in - return validateClosureArgument(in: file, dictionary: dictionary) + validateClosureArgument(in: file, dictionary: dictionary) } } @@ -311,7 +310,7 @@ extension ClosureEndIndentationRule { private func filterClosureArguments(_ arguments: [SourceKittenDictionary], file: SwiftLintFile) -> [SourceKittenDictionary] { - return arguments.filter { argument in + arguments.filter { argument in guard let bodyByteRange = argument.bodyByteRange, let range = file.stringView.byteRangeToNSRange(bodyByteRange), let match = regex("\\s*\\{").firstMatch(in: file.contents, options: [], range: range)?.range, diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift index fb9ba872f4..4acb0078b5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureParameterPositionRule.swift @@ -119,7 +119,7 @@ private extension ClosureParameterPositionRule { return } let localViolations = positionsToCheck.dropLast().filter { position in - return locationConverter.location(for: position).line != startLine + locationConverter.location(for: position).line != startLine } violations.append(contentsOf: localViolations) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift index 1cd10347aa..916f9bd2c7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/CollectionAlignmentRule.swift @@ -93,7 +93,7 @@ extension CollectionAlignmentRule { } private var alignColonsTriggeringExamples: [Example] { - return [ + [ Example(""" doThings(arg: [ "foo": 1, @@ -122,7 +122,7 @@ extension CollectionAlignmentRule { } private var alignColonsNonTriggeringExamples: [Example] { - return [ + [ Example(""" doThings(arg: [ "foo": 1, @@ -155,7 +155,7 @@ extension CollectionAlignmentRule { } private var alignLeftTriggeringExamples: [Example] { - return [ + [ Example(""" doThings(arg: [ "foo": 1, @@ -184,7 +184,7 @@ extension CollectionAlignmentRule { } private var alignLeftNonTriggeringExamples: [Example] { - return [ + [ Example(""" doThings(arg: [ "foo": 1, @@ -217,7 +217,7 @@ extension CollectionAlignmentRule { } private var sharedTriggeringExamples: [Example] { - return [ + [ Example(""" let coordinates = [ CLLocationCoordinate2D(latitude: 0, longitude: 33), @@ -236,7 +236,7 @@ extension CollectionAlignmentRule { } private var sharedNonTriggeringExamples: [Example] { - return [ + [ Example(""" let coordinates = [ CLLocationCoordinate2D(latitude: 0, longitude: 33), diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift index 36ce7df4f3..35e4d094ab 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift @@ -61,7 +61,7 @@ struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, // MARK: - Rule func validate(file: SwiftLintFile) -> [StyleViolation] { - return violationRanges(in: file).map { + violationRanges(in: file).map { StyleViolation(ruleDescription: Self.description, severity: configuration.severity, location: Location(file: file, characterOffset: $0.location)) @@ -71,7 +71,7 @@ struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, // MARK: - SubstitutionCorrectableRule func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { - return (violationRange, ", ") + (violationRange, ", ") } func violationRanges(in file: SwiftLintFile) -> [NSRange] { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift index e71c5eb08f..18f7425c59 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/CommaRule.swift @@ -89,7 +89,7 @@ struct CommaRule: CorrectableRule, SourceKitFreeRule { ) func validate(file: SwiftLintFile) -> [StyleViolation] { - return violationRanges(in: file).map { + violationRanges(in: file).map { StyleViolation(ruleDescription: Self.description, severity: configuration.severity, location: Location(file: file, byteOffset: $0.0.location)) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift index 703125bcc1..d2f0be9aa5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ComputedAccessorsOrderRuleExamples.swift @@ -1,6 +1,6 @@ struct ComputedAccessorsOrderRuleExamples { static var nonTriggeringExamples: [Example] { - return [ + [ Example(""" class Foo { var foo: Int { @@ -168,7 +168,7 @@ struct ComputedAccessorsOrderRuleExamples { } static var triggeringExamples: [Example] { - return [ + [ Example(""" class Foo { var foo: Int { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift index d52bd8a7d9..765e1c9c70 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift @@ -4,7 +4,7 @@ private func wrapInSwitch( variable: String = "foo", _ str: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example( + Example( """ switch \(variable) { \(str): break @@ -13,7 +13,7 @@ private func wrapInSwitch( } private func wrapInFunc(_ str: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example(""" + Example(""" func example(foo: Foo) { switch foo { case \(str): diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift index 7593d67430..5aa83a05ed 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift @@ -16,7 +16,7 @@ struct ExplicitSelfRule: CorrectableRule, AnalyzerRule { ) func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] { - return violationRanges(in: file, compilerArguments: compilerArguments).map { + violationRanges(in: file, compilerArguments: compilerArguments).map { StyleViolation(ruleDescription: Self.description, severity: configuration.severity, location: Location(file: file, characterOffset: $0.location)) @@ -86,7 +86,7 @@ private let kindsToFind: Set = [ private extension SwiftLintFile { func allCursorInfo(compilerArguments: [String], atByteOffsets byteOffsets: [ByteCount]) throws -> [[String: any SourceKitRepresentable]] { - return try byteOffsets.compactMap { offset in + try byteOffsets.compactMap { offset in if isExplicitAccess(at: offset) { return nil } let cursorInfoRequest = Request.cursorInfoWithoutSymbolGraph( file: self.path!, offset: offset, arguments: compilerArguments diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift index bfb6f41fd8..866fa84269 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/FileHeaderRule.swift @@ -95,15 +95,15 @@ struct FileHeaderRule: OptInRule { } private func makeViolation(at location: Location) -> StyleViolation { - return StyleViolation(ruleDescription: Self.description, - severity: configuration.severityConfiguration.severity, - location: location, - reason: "Header comments should be consistent with project patterns") + StyleViolation(ruleDescription: Self.description, + severity: configuration.severityConfiguration.severity, + location: location, + reason: "Header comments should be consistent with project patterns") } } private extension SyntaxKind { var isFileHeaderKind: Bool { - return self == .comment || self == .commentURL + self == .comment || self == .commentURL } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift index 4aad4e58fe..57ae0d070d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift @@ -122,8 +122,8 @@ struct LiteralExpressionEndIndentationRule: Rule, OptInRule { ) func validate(file: SwiftLintFile) -> [StyleViolation] { - return violations(in: file).map { violation in - return styleViolation(for: violation, in: file) + violations(in: file).map { violation in + styleViolation(for: violation, in: file) } } @@ -169,8 +169,7 @@ extension LiteralExpressionEndIndentationRule: CorrectableRule { } var corrections = correctedLocations.map { - return Correction(ruleDescription: Self.description, - location: Location(file: file, characterOffset: $0)) + Correction(ruleDescription: Self.description, location: Location(file: file, characterOffset: $0)) } file.write(correctedContents) @@ -214,7 +213,7 @@ extension LiteralExpressionEndIndentationRule { } fileprivate func violations(in file: SwiftLintFile) -> [Violation] { - return file.structureDictionary.traverseDepthFirst { subDict in + file.structureDictionary.traverseDepthFirst { subDict in guard let kind = subDict.expressionKind else { return nil } guard let violation = violation(in: file, of: kind, dictionary: subDict) else { return nil } return [violation] diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift index 227a0a36d5..729ab435f3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift @@ -39,7 +39,7 @@ struct ModifierOrderRule: ASTRule, OptInRule, CorrectableRule { } func correct(file: SwiftLintFile) -> [Correction] { - return file.structureDictionary.traverseDepthFirst { subDict in + file.structureDictionary.traverseDepthFirst { subDict in guard subDict.declarationKind != nil else { return nil } return correct(file: file, dictionary: subDict) } @@ -171,7 +171,7 @@ private extension SourceKittenDictionary { private extension String { func lastComponentAfter(_ character: String) -> String { - return components(separatedBy: character).last ?? "" + components(separatedBy: character).last ?? "" } } @@ -180,5 +180,5 @@ private struct ModifierDescription: Equatable { let group: SwiftDeclarationAttributeKind.ModifierGroup let offset: ByteCount let length: ByteCount - var range: ByteRange { return ByteRange(location: offset, length: length) } + var range: ByteRange { ByteRange(location: offset, length: length) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift index e8bd868bda..b38b330ef2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift @@ -95,10 +95,10 @@ struct MultilineFunctionChainsRule: ASTRule, OptInRule { func validate(file: SwiftLintFile, kind: SwiftExpressionKind, dictionary: SourceKittenDictionary) -> [StyleViolation] { - return violatingOffsets(file: file, kind: kind, dictionary: dictionary).map { offset in - return StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: file, characterOffset: offset)) + violatingOffsets(file: file, kind: kind, dictionary: dictionary).map { offset in + StyleViolation(ruleDescription: Self.description, + severity: configuration.severity, + location: Location(file: file, characterOffset: offset)) } } @@ -214,7 +214,7 @@ struct MultilineFunctionChainsRule: ASTRule, OptInRule { private extension SourceKittenDictionary { var subcalls: [SourceKittenDictionary] { - return substructure.compactMap { dictionary -> SourceKittenDictionary? in + substructure.compactMap { dictionary -> SourceKittenDictionary? in guard dictionary.expressionKind == .call else { return nil } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift index db56b81f50..5021c338c6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersBracketsRule.swift @@ -91,7 +91,7 @@ struct MultilineParametersBracketsRule: OptInRule { ) func validate(file: SwiftLintFile) -> [StyleViolation] { - return violations(in: file.structureDictionary, file: file) + violations(in: file.structureDictionary, file: file) } private func violations(in substructure: SourceKittenDictionary, file: SwiftLintFile) -> [StyleViolation] { @@ -112,7 +112,7 @@ struct MultilineParametersBracketsRule: OptInRule { let parameters = substructure.substructure.filter { $0.declarationKind == .varParameter } let parameterBodies = parameters.compactMap { $0.content(in: file) } let parametersNewlineCount = parameterBodies.map { body in - return body.countOccurrences(of: "\n") + body.countOccurrences(of: "\n") }.reduce(0, +) let declarationNewlineCount = functionName.countOccurrences(of: "\n") let isMultiline = declarationNewlineCount > parametersNewlineCount diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift index 472c1c491f..a63da2377c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/NumberSeparatorRuleExamples.swift @@ -1,6 +1,6 @@ internal struct NumberSeparatorRuleExamples { static let nonTriggeringExamples: [Example] = { - return ["-", "+", ""].flatMap { (sign: String) -> [Example] in + ["-", "+", ""].flatMap { (sign: String) -> [Example] in [ Example("let foo = \(sign)100"), Example("let foo = \(sign)1_000"), @@ -33,7 +33,7 @@ internal struct NumberSeparatorRuleExamples { static let corrections = makeCorrections(signs: [("-↓", "-"), ("+↓", "+"), ("↓", "")]) private static func makeTriggeringExamples(signs: [String]) -> [Example] { - return signs.flatMap { (sign: String) -> [Example] in + signs.flatMap { (sign: String) -> [Example] in [ Example("let foo = \(sign)10_0"), Example("let foo = \(sign)1000"), diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRule.swift index af8818806e..b732349283 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRule.swift @@ -16,7 +16,7 @@ struct OperatorUsageWhitespaceRule: OptInRule, CorrectableRule, SourceKitFreeRul ) func validate(file: SwiftLintFile) -> [StyleViolation] { - return violationRanges(file: file).map { range, _ in + violationRanges(file: file).map { range, _ in StyleViolation(ruleDescription: Self.description, severity: configuration.severityConfiguration.severity, location: Location(file: file, byteOffset: range.location)) @@ -45,7 +45,7 @@ struct OperatorUsageWhitespaceRule: OptInRule, CorrectableRule, SourceKitFreeRul return (range, correction) } .filter { range, _ in - return file.ruleEnabled(violatingRanges: [range], for: self).isNotEmpty + file.ruleEnabled(violatingRanges: [range], for: self).isNotEmpty } var correctedContents = file.contents @@ -100,7 +100,7 @@ struct OperatorUsageWhitespaceRule: OptInRule, CorrectableRule, SourceKitFreeRul .flatMap { [lineIndex + $0, lineIndex - $0] } func isValidIndex(_ idx: Int) -> Bool { - return idx != lineIndex && idx >= 0 && idx < file.stringView.lines.count + idx != lineIndex && idx >= 0 && idx < file.stringView.lines.count } for lineIndex in lineIndexesAround where isValidIndex(lineIndex) { @@ -214,7 +214,7 @@ private class OperatorUsageWhitespaceVisitor: SyntaxVisitor { private extension Trivia { var containsTooMuchWhitespacing: Bool { - return contains { element in + contains { element in guard case let .spaces(spaces) = element, spaces > 1 else { return false } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift index 7ebaa37f0a..6266949b9d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfTypeOverTypeOfSelfRule.swift @@ -135,7 +135,7 @@ private extension PreferSelfTypeOverTypeOfSelfRule { private extension FunctionCallExprSyntax { var hasViolation: Bool { - return isTypeOfSelfCall && + isTypeOfSelfCall && arguments.map(\.label?.text) == ["of"] && arguments.first?.expression.as(DeclReferenceExprSyntax.self)?.baseName.tokenKind == .keyword(.self) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift index 1e29c0dc8d..b21194b5dd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SingleTestClassRule.swift @@ -56,10 +56,10 @@ struct SingleTestClassRule: SourceKitFreeRule, OptInRule { guard classes.count > 1 else { return [] } return classes.map { position in - return StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: file, position: position.position), - reason: "\(classes.count) test classes found in this file") + StyleViolation(ruleDescription: Self.description, + severity: configuration.severity, + location: Location(file: file, position: position.position), + reason: "\(classes.count) test classes found in this file") } } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift index 22cfd90478..6f206c8487 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift @@ -3,19 +3,19 @@ import SourceKittenFramework fileprivate extension Line { var contentRange: NSRange { - return NSRange(location: range.location, length: content.bridge().length) + NSRange(location: range.location, length: content.bridge().length) } // `Line` in this rule always contains word import // This method returns contents of line that are before import func importAttributes() -> String { - return content[importAttributesRange()].trimmingCharacters(in: .whitespaces) + content[importAttributesRange()].trimmingCharacters(in: .whitespaces) } // `Line` in this rule always contains word import // This method returns contents of line that are after import func importModule() -> Substring { - return content[importModuleRange()] + content[importModuleRange()] } func importAttributesRange() -> Range { @@ -37,7 +37,7 @@ private extension Sequence where Element == Line { // Groups lines, so that lines that are one after the other // will end up in same group. func grouped() -> [[Line]] { - return reduce(into: [[]]) { result, line in + reduce(into: [[]]) { result, line in guard let last = result.last?.last else { result = [[line]] return @@ -93,8 +93,8 @@ struct SortedImportsRule: CorrectableRule, OptInRule { } private func violatingOffsets(inGroups groups: [[Line]]) -> [Int] { - return groups.flatMap { group in - return zip(group, group.dropFirst()).reduce(into: []) { violatingOffsets, groupPair in + groups.flatMap { group in + zip(group, group.dropFirst()).reduce(into: []) { violatingOffsets, groupPair in let (previous, current) = groupPair let isOrderedCorrectly = should(previous, comeBefore: current) if isOrderedCorrectly { @@ -144,7 +144,7 @@ struct SortedImportsRule: CorrectableRule, OptInRule { } let result = group.map { $0.content }.joined(separator: "\n") let union = group.dropFirst().reduce(first) { result, line in - return NSUnionRange(result, line.contentRange) + NSUnionRange(result, line.contentRange) } correctedContents.replaceCharacters(in: union, with: result) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift index 8db9e908b2..c30bbd0d65 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift @@ -87,7 +87,7 @@ private extension StatementPositionRule { static let defaultPattern = "\\}(?:[\\s\\n\\r]{2,}|[\\n\\t\\r]+)?\\b(else|catch)\\b" func defaultValidate(file: SwiftLintFile) -> [StyleViolation] { - return defaultViolationRanges(in: file, matching: Self.defaultPattern).compactMap { range in + defaultViolationRanges(in: file, matching: Self.defaultPattern).compactMap { range in StyleViolation(ruleDescription: Self.description, severity: configuration.severity, location: Location(file: file, characterOffset: range.location)) @@ -95,8 +95,8 @@ private extension StatementPositionRule { } func defaultViolationRanges(in file: SwiftLintFile, matching pattern: String) -> [NSRange] { - return file.match(pattern: pattern).filter { _, syntaxKinds in - return syntaxKinds.starts(with: [.keyword]) + file.match(pattern: pattern).filter { _, syntaxKinds in + syntaxKinds.starts(with: [.keyword]) }.compactMap { $0.0 } } @@ -122,7 +122,7 @@ private extension StatementPositionRule { // Uncuddled Behaviors private extension StatementPositionRule { func uncuddledValidate(file: SwiftLintFile) -> [StyleViolation] { - return uncuddledViolationRanges(in: file).compactMap { range in + uncuddledViolationRanges(in: file).compactMap { range in StyleViolation(ruleDescription: Self.uncuddledDescription, severity: configuration.severity, location: Location(file: file, characterOffset: range.location)) @@ -139,7 +139,7 @@ private extension StatementPositionRule { static func uncuddledMatchValidator(contents: StringView) -> ((NSTextCheckingResult) -> NSTextCheckingResult?) { - return { match in + { match in if match.numberOfRanges != 5 { return match } @@ -159,7 +159,7 @@ private extension StatementPositionRule { static func uncuddledMatchFilter(contents: StringView, syntaxMap: SwiftLintSyntaxMap) -> ((NSTextCheckingResult) -> Bool) { - return { match in + { match in let range = match.range guard let matchRange = contents.NSRangeToByteRange(start: range.location, length: range.length) else { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift index eec2198dca..46592dd7a6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseAlignmentRule.swift @@ -93,14 +93,13 @@ extension SwitchCaseAlignmentRule { } var triggeringExamples: [Example] { - return (indentedCasesOption ? nonIndentedCases : indentedCases) + (indentedCasesOption ? nonIndentedCases : indentedCases) + invalidCases + invalidOneLiners } var nonTriggeringExamples: [Example] { - return indentedCasesOption ? indentedCases : nonIndentedCases - + validOneLiners + indentedCasesOption ? indentedCases : nonIndentedCases + validOneLiners } private var indentedCases: [Example] { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift index b75d08d40a..71159534e5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SwitchCaseOnNewlineRule.swift @@ -1,7 +1,7 @@ import SwiftSyntax private func wrapInSwitch(_ str: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return Example(""" + Example(""" switch foo { \(str) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift index d1b399021a..1cf4cb22a7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingNewlineRule.swift @@ -14,7 +14,7 @@ extension String { } fileprivate func trailingNewlineCount() -> Int? { - return countOfTrailingCharacters(in: .newlines) + countOfTrailingCharacters(in: .newlines) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift index 2bb9198769..0cba45cf3d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift @@ -68,7 +68,7 @@ struct TypeContentsOrderRule: OptInRule { } private func typeContentOffsets(in typeStructure: SourceKittenDictionary) -> [TypeContentOffset] { - return typeStructure.substructure.compactMap { typeContentStructure in + typeStructure.substructure.compactMap { typeContentStructure in guard let typeContent = typeContent(for: typeContentStructure) else { return nil } return (typeContent, typeContentStructure.offset!) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift index ba7cf549d1..bdd84043f6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift @@ -3,7 +3,7 @@ import SourceKittenFramework private extension SwiftLintFile { func violatingRanges(for pattern: String) -> [NSRange] { - return match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentKinds) + match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentKinds) } } @@ -130,7 +130,7 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { private let pattern = "([^\\n{][ \\t]*\\n)([ \\t]*(?:case[^\\n]+|default):[ \\t]*\\n)" private func violationRanges(in file: SwiftLintFile) -> [NSRange] { - return file.violatingRanges(for: pattern).filter { + file.violatingRanges(for: pattern).filter { !isFalsePositive(in: file, range: $0) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRule.swift index 2dda75ade3..6ca1625927 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceClosingBracesRule.swift @@ -70,6 +70,6 @@ struct VerticalWhitespaceClosingBracesRule: CorrectableRule, OptInRule { private extension SwiftLintFile { func violatingRanges(for pattern: String) -> [NSRange] { - return match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentAndStringKinds) + match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentAndStringKinds) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift index 3547c63a3d..b6150b2aac 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceOpeningBracesRule.swift @@ -3,7 +3,7 @@ import SourceKittenFramework private extension SwiftLintFile { func violatingRanges(for pattern: String) -> [NSRange] { - return match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentAndStringKinds) + match(pattern: pattern, excludingSyntaxKinds: SyntaxKind.commentAndStringKinds) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift index ea9fcfa699..b8b64ca4cd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceRule.swift @@ -43,7 +43,7 @@ struct VerticalWhitespaceRule: CorrectableRule { } return linesSections.map { eachLastLine, eachSectionCount in - return StyleViolation( + StyleViolation( ruleDescription: Self.description, severity: configuration.severityConfiguration.severity, location: Location(file: file.path, line: eachLastLine.index), diff --git a/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift index 65d8c62e63..e06fb18ea2 100644 --- a/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift @@ -59,7 +59,7 @@ public extension Array { /// /// - returns: The elements grouped by applying the specified transformation. func group(by transform: (Element) -> U) -> [U: [Element]] { - return Dictionary(grouping: self, by: { transform($0) }) + Dictionary(grouping: self, by: { transform($0) }) } /// Returns the elements failing the `belongsInSecondPartition` test, followed by the elements passing the @@ -83,7 +83,7 @@ public extension Array { /// /// - returns: The result of applying `transform` on every element and flattening the results. func parallelFlatMap(transform: (Element) -> [T]) -> [T] { - return parallelMap(transform: transform).flatMap { $0 } + parallelMap(transform: transform).flatMap { $0 } } /// Same as `compactMap` but spreads the work in the `transform` block in parallel using GCD's `concurrentPerform`. @@ -92,7 +92,7 @@ public extension Array { /// /// - returns: The result of applying `transform` on every element and discarding the `nil` ones. func parallelCompactMap(transform: (Element) -> T?) -> [T] { - return parallelMap(transform: transform).compactMap { $0 } + parallelMap(transform: transform).compactMap { $0 } } /// Same as `map` but spreads the work in the `transform` block in parallel using GCD's `concurrentPerform`. @@ -114,7 +114,7 @@ public extension Array { public extension Collection { /// Whether this collection has one or more element. var isNotEmpty: Bool { - return !isEmpty + !isEmpty } /// Get the only element in the collection. diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift index 379b6cfcd8..0b125a3068 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift @@ -179,7 +179,7 @@ package extension Configuration { } private func findPossiblyExistingVertex(sameAs vertex: Vertex) -> Vertex? { - return vertices.first { + vertices.first { $0.originalRemoteString != nil && $0.originalRemoteString == vertex.originalRemoteString } ?? vertices.first { $0.filePath == vertex.filePath } } @@ -237,7 +237,7 @@ package extension Configuration { } return verticesToMerge.map { - return ( + ( configurationDict: $0.configurationDict, rootDirectory: $0.rootDirectory ) diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift index 431fbd0faa..f1a8283cf7 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraphSubtypes.swift @@ -81,7 +81,7 @@ internal extension Configuration.FileGraph { } internal static func == (lhs: Vertex, rhs: Vertex) -> Bool { - return lhs.filePath == rhs.filePath + lhs.filePath == rhs.filePath && lhs.originalRemoteString == rhs.originalRemoteString && lhs.rootDirectory == rhs.rootDirectory } diff --git a/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift b/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift index b9c4466db3..af11657c0f 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift @@ -18,7 +18,7 @@ extension Configuration { /// - returns: Files to lint. public func lintableFiles(inPath path: String, forceExclude: Bool, excludeBy: ExcludeBy) -> [SwiftLintFile] { - return lintablePaths(inPath: path, forceExclude: forceExclude, excludeBy: excludeBy) + lintablePaths(inPath: path, forceExclude: forceExclude, excludeBy: excludeBy) .compactMap(SwiftLintFile.init(pathDeferringReading:)) } @@ -109,7 +109,7 @@ extension Configuration { /// /// - returns: The expanded excluded file paths. public func excludedPaths(fileManager: some LintableFileManager = FileManager.default) -> [String] { - return excludedPaths + excludedPaths .flatMap(Glob.resolveGlob) .parallelFlatMap { fileManager.filesToLint(inPath: $0, rootDirectory: rootDirectory) } } diff --git a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift index 9fdd0bc44f..05e5dfd490 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift @@ -84,7 +84,7 @@ extension Configuration { /// /// - returns: A new configuration. public func configuration(for file: SwiftLintFile) -> Configuration { - return (file.path?.bridge().deletingLastPathComponent).map(configuration(forDirectory:)) ?? self + (file.path?.bridge().deletingLastPathComponent).map(configuration(forDirectory:)) ?? self } private func configuration(forDirectory directory: String) -> Configuration { diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 610e45ba78..9f6b91acb5 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -44,7 +44,7 @@ extension Configuration { enableAllRules: Bool = false, cachePath: String? = nil ) throws { - func defaultStringArray(_ object: Any?) -> [String] { return [String].array(of: object) ?? [] } + func defaultStringArray(_ object: Any?) -> [String] { [String].array(of: object) ?? [] } // Use either the new 'opt_in_rules' or fallback to the deprecated 'enabled_rules' let optInRules = defaultStringArray(dict[Key.optInRules.rawValue] ?? dict[Key.enabledRules.rawValue]) @@ -107,7 +107,7 @@ extension Configuration { // MARK: - Methods: Validations private static func validKeys(ruleList: RuleList) -> Set { - return validGlobalKeys.union(ruleList.allValidIdentifiers()) + validGlobalKeys.union(ruleList.allValidIdentifiers()) } private static func getIndentationLogIfInvalid(from dict: [String: Any]) -> IndentationStyle { @@ -136,12 +136,12 @@ extension Configuration { // Deprecation warning for rules let deprecatedRulesIdentifiers = ruleList.list.flatMap { identifier, rule -> [(String, String)] in - return rule.description.deprecatedAliases.map { ($0, identifier) } + rule.description.deprecatedAliases.map { ($0, identifier) } } let userProvidedRuleIDs = Set(disabledRules + optInRules + onlyRules) let deprecatedUsages = deprecatedRulesIdentifiers.filter { deprecatedIdentifier, _ in - return dict[deprecatedIdentifier] != nil || userProvidedRuleIDs.contains(deprecatedIdentifier) + dict[deprecatedIdentifier] != nil || userProvidedRuleIDs.contains(deprecatedIdentifier) } for (deprecatedIdentifier, identifier) in deprecatedUsages { diff --git a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift index 5d96d507a9..458761d646 100644 --- a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift @@ -38,12 +38,12 @@ public struct SourceKittenDictionary { /// Body length public var bodyLength: ByteCount? { - return (value["key.bodylength"] as? Int64).map(ByteCount.init) + (value["key.bodylength"] as? Int64).map(ByteCount.init) } /// Body offset. public var bodyOffset: ByteCount? { - return (value["key.bodyoffset"] as? Int64).map(ByteCount.init) + (value["key.bodyoffset"] as? Int64).map(ByteCount.init) } /// Body byte range. @@ -54,26 +54,26 @@ public struct SourceKittenDictionary { /// Kind. public var kind: String? { - return value["key.kind"] as? String + value["key.kind"] as? String } /// Length. public var length: ByteCount? { - return (value["key.length"] as? Int64).map(ByteCount.init) + (value["key.length"] as? Int64).map(ByteCount.init) } /// Name. public var name: String? { - return value["key.name"] as? String + value["key.name"] as? String } /// Name length. public var nameLength: ByteCount? { - return (value["key.namelength"] as? Int64).map(ByteCount.init) + (value["key.namelength"] as? Int64).map(ByteCount.init) } /// Name offset. public var nameOffset: ByteCount? { - return (value["key.nameoffset"] as? Int64).map(ByteCount.init) + (value["key.nameoffset"] as? Int64).map(ByteCount.init) } /// Byte range of name. @@ -84,7 +84,7 @@ public struct SourceKittenDictionary { /// Offset. public var offset: ByteCount? { - return (value["key.offset"] as? Int64).map(ByteCount.init) + (value["key.offset"] as? Int64).map(ByteCount.init) } /// Returns byte range starting from `offset` with `length` bytes @@ -95,42 +95,42 @@ public struct SourceKittenDictionary { /// Setter accessibility. public var setterAccessibility: String? { - return value["key.setter_accessibility"] as? String + value["key.setter_accessibility"] as? String } /// Type name. public var typeName: String? { - return value["key.typename"] as? String + value["key.typename"] as? String } /// Documentation length. public var docLength: ByteCount? { - return (value["key.doclength"] as? Int64).flatMap(ByteCount.init) + (value["key.doclength"] as? Int64).flatMap(ByteCount.init) } /// The attribute for this dictionary, as returned by SourceKit. public var attribute: String? { - return value["key.attribute"] as? String + value["key.attribute"] as? String } /// Module name in `@import` expressions. public var moduleName: String? { - return value["key.modulename"] as? String + value["key.modulename"] as? String } /// The line number for this declaration. public var line: Int64? { - return value["key.line"] as? Int64 + value["key.line"] as? Int64 } /// The column number for this declaration. public var column: Int64? { - return value["key.column"] as? Int64 + value["key.column"] as? Int64 } /// The `SwiftDeclarationAttributeKind` values associated with this dictionary. public var enclosedSwiftAttributes: [SwiftDeclarationAttributeKind] { - return swiftAttributes.compactMap { $0.attribute } + swiftAttributes.compactMap { $0.attribute } .compactMap(SwiftDeclarationAttributeKind.init(rawValue:)) } @@ -154,7 +154,7 @@ public struct SourceKittenDictionary { } public var enclosedVarParameters: [SourceKittenDictionary] { - return substructure.flatMap { subDict -> [SourceKittenDictionary] in + substructure.flatMap { subDict -> [SourceKittenDictionary] in if subDict.declarationKind == .varParameter { return [subDict] } @@ -168,7 +168,7 @@ public struct SourceKittenDictionary { } public var enclosedArguments: [SourceKittenDictionary] { - return substructure.flatMap { subDict -> [SourceKittenDictionary] in + substructure.flatMap { subDict -> [SourceKittenDictionary] in guard subDict.expressionKind == .argument else { return [] } @@ -244,8 +244,8 @@ public extension Dictionary where Key == Example { /// /// - returns: A new `Dictionary`. func removingViolationMarkers() -> [Key: Value] { - return Dictionary(uniqueKeysWithValues: map { key, value in - return (key.removingViolationMarkers(), value) + Dictionary(uniqueKeysWithValues: map { key, value in + (key.removingViolationMarkers(), value) }) } } diff --git a/Source/SwiftLintCore/Extensions/FileManager+SwiftLint.swift b/Source/SwiftLintCore/Extensions/FileManager+SwiftLint.swift index 4435ed037d..c5aad909a5 100644 --- a/Source/SwiftLintCore/Extensions/FileManager+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/FileManager+SwiftLint.swift @@ -47,7 +47,7 @@ extension FileManager: LintableFileManager { } public func modificationDate(forFileAtPath path: String) -> Date? { - return (try? attributesOfItem(atPath: path))?[.modificationDate] as? Date + (try? attributesOfItem(atPath: path))?[.modificationDate] as? Date } public func isFile(atPath path: String) -> Bool { diff --git a/Source/SwiftLintCore/Extensions/NSRange+SwiftLint.swift b/Source/SwiftLintCore/Extensions/NSRange+SwiftLint.swift index 69df673e93..cbe3d1e391 100644 --- a/Source/SwiftLintCore/Extensions/NSRange+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/NSRange+SwiftLint.swift @@ -2,7 +2,7 @@ import Foundation extension NSRange { func intersects(_ range: NSRange) -> Bool { - return NSIntersectionRange(self, range).length > 0 + NSIntersectionRange(self, range).length > 0 } func intersects(_ ranges: [NSRange]) -> Bool { diff --git a/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift b/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift index 1a0c7c94c0..95a39018fc 100644 --- a/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift @@ -57,17 +57,17 @@ public extension NSRegularExpression { func matches(in stringView: StringView, options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] { - return matches(in: stringView.string, options: options, range: stringView.range) + matches(in: stringView.string, options: options, range: stringView.range) } func matches(in stringView: StringView, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> [NSTextCheckingResult] { - return matches(in: stringView.string, options: options, range: range) + matches(in: stringView.string, options: options, range: range) } func matches(in file: SwiftLintFile, options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] { - return matches(in: file.stringView.string, options: options, range: file.stringView.range) + matches(in: file.stringView.string, options: options, range: file.stringView.range) } } diff --git a/Source/SwiftLintCore/Extensions/String+SwiftLint.swift b/Source/SwiftLintCore/Extensions/String+SwiftLint.swift index fc9ebac802..49839438b7 100644 --- a/Source/SwiftLintCore/Extensions/String+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/String+SwiftLint.swift @@ -15,11 +15,11 @@ public extension String { } func isUppercase() -> Bool { - return self == uppercased() + self == uppercased() } func isLowercase() -> Bool { - return self == lowercased() + self == lowercased() } private subscript (range: Range) -> String { @@ -63,14 +63,14 @@ public extension String { } var fullNSRange: NSRange { - return NSRange(location: 0, length: utf16.count) + NSRange(location: 0, length: utf16.count) } /// Returns a new string, converting the path to a canonical absolute path. /// /// - returns: A new `String`. func absolutePathStandardized() -> String { - return bridge().absolutePathRepresentation().bridge().standardizingPath + bridge().absolutePathRepresentation().bridge().standardizingPath } var isFile: Bool { @@ -88,7 +88,7 @@ public extension String { /// - Parameter character: Character to count /// - Returns: Number of times `character` occurs in `self` func countOccurrences(of character: Character) -> Int { - return self.reduce(0, { + self.reduce(0, { $1 == character ? $0 + 1 : $0 }) } diff --git a/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift b/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift index 94a0a3c8b8..26d2f2ef5b 100644 --- a/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftDeclarationAttributeKind+Swiftlint.swift @@ -2,7 +2,7 @@ import SourceKittenFramework public extension SwiftDeclarationAttributeKind { static var attributesRequiringFoundation: Set { - return [ + [ .objc, .objcName, .objcMembers, @@ -95,7 +95,7 @@ public extension SwiftDeclarationAttributeKind { } public var debugDescription: String { - return self.rawValue + self.rawValue } } } diff --git a/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift b/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift index 3676560514..a90867e184 100644 --- a/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift +++ b/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift @@ -22,18 +22,18 @@ private let responseCache = Cache { file -> [String: any SourceKitRepresentable] } } private let structureDictionaryCache = Cache { file in - return responseCache.get(file).map(Structure.init).map { SourceKittenDictionary($0.dictionary) } + responseCache.get(file).map(Structure.init).map { SourceKittenDictionary($0.dictionary) } } private let syntaxTreeCache = Cache { file -> SourceFileSyntax in - return Parser.parse(source: file.contents) + Parser.parse(source: file.contents) } private let foldedSyntaxTreeCache = Cache { file -> SourceFileSyntax? in - return OperatorTable.standardOperators + OperatorTable.standardOperators .foldAll(file.syntaxTree) { _ in } .as(SourceFileSyntax.self) } private let locationConverterCache = Cache { file -> SourceLocationConverter in - return SourceLocationConverter(fileName: file.path ?? "", tree: file.syntaxTree) + SourceLocationConverter(fileName: file.path ?? "", tree: file.syntaxTree) } private let commandsCache = Cache { file -> [Command] in guard file.contents.contains("swiftlint:") else { @@ -98,12 +98,12 @@ private class Cache { extension SwiftLintFile { fileprivate var cacheKey: FileCacheKey { - return id + id } public var sourcekitdFailed: Bool { get { - return responseCache.get(self) == nil + responseCache.get(self) == nil } set { if newValue { @@ -116,7 +116,7 @@ extension SwiftLintFile { internal var assertHandler: AssertHandler? { get { - return assertHandlerCache.get(self) + assertHandlerCache.get(self) } set { assertHandlerCache.set(key: cacheKey, value: newValue) diff --git a/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift b/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift index 41d8b10204..f833e94553 100644 --- a/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift +++ b/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift @@ -18,7 +18,7 @@ extension SwiftLintFile { let commands: [Command] if let restrictingRuleIdentifiers { commands = self.commands().filter { command in - return command.ruleIdentifiers.contains(where: restrictingRuleIdentifiers.contains) + command.ruleIdentifiers.contains(where: restrictingRuleIdentifiers.contains) } } else { commands = self.commands() @@ -94,7 +94,7 @@ extension SwiftLintFile { } public func match(pattern: String, with syntaxKinds: [SyntaxKind], range: NSRange? = nil) -> [NSRange] { - return match(pattern: pattern, range: range) + match(pattern: pattern, range: range) .filter { $0.1 == syntaxKinds } .map { $0.0 } } @@ -112,18 +112,18 @@ extension SwiftLintFile { public func matchesAndSyntaxKinds(matching pattern: String, range: NSRange? = nil) -> [(NSTextCheckingResult, [SyntaxKind])] { - return matchesAndTokens(matching: pattern, range: range).map { textCheckingResult, tokens in + matchesAndTokens(matching: pattern, range: range).map { textCheckingResult, tokens in (textCheckingResult, tokens.kinds) } } public func rangesAndTokens(matching pattern: String, range: NSRange? = nil) -> [(NSRange, [SwiftLintSyntaxToken])] { - return matchesAndTokens(matching: pattern, range: range).map { ($0.0.range, $0.1) } + matchesAndTokens(matching: pattern, range: range).map { ($0.0.range, $0.1) } } public func match(pattern: String, range: NSRange? = nil, captureGroup: Int = 0) -> [(NSRange, [SyntaxKind])] { - return matchesAndSyntaxKinds(matching: pattern, range: range).map { textCheckingResult, syntaxKinds in + matchesAndSyntaxKinds(matching: pattern, range: range).map { textCheckingResult, syntaxKinds in (textCheckingResult.range(at: captureGroup), syntaxKinds) } } @@ -203,7 +203,7 @@ extension SwiftLintFile { excludingSyntaxKinds syntaxKinds: Set, range: NSRange? = nil, captureGroup: Int = 0) -> [NSRange] { - return match(pattern: pattern, range: range, captureGroup: captureGroup) + match(pattern: pattern, range: range, captureGroup: captureGroup) .filter { syntaxKinds.isDisjoint(with: $0.1) } .map { $0.0 } } @@ -279,7 +279,7 @@ extension SwiftLintFile { } public func ruleEnabled(violatingRange: NSRange, for rule: some Rule) -> NSRange? { - return ruleEnabled(violatingRanges: [violatingRange], for: rule).first + ruleEnabled(violatingRanges: [violatingRange], for: rule).first } public func isACL(token: SwiftLintSyntaxToken) -> Bool { @@ -292,6 +292,6 @@ extension SwiftLintFile { } public func contents(for token: SwiftLintSyntaxToken) -> String? { - return stringView.substringWithByteRange(token.range) + stringView.substringWithByteRange(token.range) } } diff --git a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift index bd3c613739..521c6fcbc6 100644 --- a/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SwiftSyntax+SwiftLint.swift @@ -12,7 +12,7 @@ public extension SwiftLintSyntaxVisitor { } func walk(file: SwiftLintFile, handler: (Self) -> [T]) -> [T] { - return walk(tree: file.syntaxTree, handler: handler) + walk(tree: file.syntaxTree, handler: handler) } } diff --git a/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift b/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift index 9d35954e81..8099f0ca37 100644 --- a/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/SyntaxKind+SwiftLint.swift @@ -25,7 +25,7 @@ public extension SyntaxKind { /// Syntax kinds that don't have associated module info when getting their cursor info. static var kindsWithoutModuleInfo: Set { - return [ + [ .attributeBuiltin, .keyword, .number, diff --git a/Source/SwiftLintCore/Models/AccessControlLevel.swift b/Source/SwiftLintCore/Models/AccessControlLevel.swift index cade95837b..160956d0b8 100644 --- a/Source/SwiftLintCore/Models/AccessControlLevel.swift +++ b/Source/SwiftLintCore/Models/AccessControlLevel.swift @@ -50,7 +50,7 @@ public enum AccessControlLevel: String, CustomStringConvertible { /// Returns true if is `private` or `fileprivate` public var isPrivate: Bool { - return self == .private || self == .fileprivate + self == .private || self == .fileprivate } } @@ -67,6 +67,6 @@ extension AccessControlLevel: Comparable { } public static func < (lhs: AccessControlLevel, rhs: AccessControlLevel) -> Bool { - return lhs.priority < rhs.priority + lhs.priority < rhs.priority } } diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 72e2a7ccca..5e1e910dbb 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -306,7 +306,7 @@ extension Configuration: Hashable { } public static func == (lhs: Configuration, rhs: Configuration) -> Bool { - return lhs.includedPaths == rhs.includedPaths && + lhs.includedPaths == rhs.includedPaths && lhs.excludedPaths == rhs.excludedPaths && lhs.indentation == rhs.indentation && lhs.warningThreshold == rhs.warningThreshold && @@ -327,7 +327,7 @@ extension Configuration: Hashable { // MARK: - CustomStringConvertible extension Configuration: CustomStringConvertible { public var description: String { - return "Configuration: \n" + "Configuration: \n" + "- Indentation Style: \(indentation)\n" + "- Included Paths: \(includedPaths)\n" + "- Excluded Paths: \(excludedPaths)\n" diff --git a/Source/SwiftLintCore/Models/Correction.swift b/Source/SwiftLintCore/Models/Correction.swift index 44d9fa22d3..92d7fa1419 100644 --- a/Source/SwiftLintCore/Models/Correction.swift +++ b/Source/SwiftLintCore/Models/Correction.swift @@ -7,7 +7,7 @@ public struct Correction: Equatable, Sendable { /// The console-printable description for this correction. public var consoleDescription: String { - return "\(location.file ?? ""): Corrected \(ruleDescription.name)" + "\(location.file ?? ""): Corrected \(ruleDescription.name)" } /// Memberwise initializer. diff --git a/Source/SwiftLintCore/Models/Example.swift b/Source/SwiftLintCore/Models/Example.swift index bd4964fef1..977e7df02a 100644 --- a/Source/SwiftLintCore/Models/Example.swift +++ b/Source/SwiftLintCore/Models/Example.swift @@ -86,7 +86,7 @@ public extension Example { /// Returns a copy of the Example with all instances of the "↓" character removed. func removingViolationMarkers() -> Example { - return with(code: code.replacingOccurrences(of: "↓", with: "")) + with(code: code.replacingOccurrences(of: "↓", with: "")) } } @@ -127,7 +127,7 @@ extension Example: Hashable { public static func == (lhs: Example, rhs: Example) -> Bool { // Ignoring file/line metadata because two Examples could represent // the same idea, but captured at two different points in the code - return lhs.code == rhs.code + lhs.code == rhs.code } public func hash(into hasher: inout Hasher) { @@ -139,7 +139,7 @@ extension Example: Hashable { extension Example: Comparable { public static func < (lhs: Example, rhs: Example) -> Bool { - return lhs.code < rhs.code + lhs.code < rhs.code } } diff --git a/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift b/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift index af245f6d77..b5fabe7467 100644 --- a/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift +++ b/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift @@ -5,7 +5,7 @@ internal struct HashableConfigurationRuleWrapperWrapper: Hashable { lhs: HashableConfigurationRuleWrapperWrapper, rhs: HashableConfigurationRuleWrapperWrapper ) -> Bool { // Only use identifier for equality check (not taking config into account) - return type(of: lhs.configurationRuleWrapper.rule).description.identifier + type(of: lhs.configurationRuleWrapper.rule).description.identifier == type(of: rhs.configurationRuleWrapper.rule).description.identifier } diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index 3572200b28..eab0fe1ce3 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -24,10 +24,10 @@ private extension Rule { } let regionsDisablingCurrentRule = regions.filter { region in - return region.isRuleDisabled(self.init()) + region.isRuleDisabled(self.init()) } let regionsDisablingSuperfluousDisableRule = regions.filter { region in - return region.isRuleDisabled(superfluousDisableCommandRule) + region.isRuleDisabled(superfluousDisableCommandRule) } return regionsDisablingCurrentRule.compactMap { region -> StyleViolation? in @@ -40,7 +40,7 @@ private extension Rule { } let noViolationsInDisabledRegion = !allViolations.contains { violation in - return region.contains(violation.location) + region.contains(violation.location) } guard noViolationsInDisabledRegion else { return nil @@ -91,9 +91,9 @@ private extension Rule { } let (disabledViolationsAndRegions, enabledViolationsAndRegions) = violations.map { violation in - return (violation, regions.first { $0.contains(violation.location) }) + (violation, regions.first { $0.contains(violation.location) }) }.partitioned { _, region in - return region?.isRuleEnabled(self) ?? true + region?.isRuleEnabled(self) ?? true } let ruleIDs = Self.description.allIdentifiers + @@ -204,7 +204,7 @@ public struct CollectedLinter { /// /// - returns: All style violations found by this linter. public func styleViolations(using storage: RuleStorage) -> [StyleViolation] { - return getStyleViolations(using: storage).0 + getStyleViolations(using: storage).0 } /// Computes or retrieves style violations and the time spent executing each rule. @@ -214,7 +214,7 @@ public struct CollectedLinter { /// - returns: All style violations found by this linter, and the time spent executing each rule. public func styleViolationsAndRuleTimes(using storage: RuleStorage) -> ([StyleViolation], [(id: String, time: Double)]) { - return getStyleViolations(using: storage, benchmark: true) + getStyleViolations(using: storage, benchmark: true) } private func getStyleViolations(using storage: RuleStorage, @@ -348,7 +348,7 @@ public struct CollectedLinter { !region.disabledRuleIdentifiers.contains(.all) && !region.disabledRuleIdentifiers.contains(superfluousRuleIdentifier) }).map { id in - return StyleViolation( + StyleViolation( ruleDescription: type(of: superfluousDisableCommandRule).description, severity: superfluousDisableCommandRule.configuration.severity, location: region.start, diff --git a/Source/SwiftLintCore/Models/LinterCache.swift b/Source/SwiftLintCore/Models/LinterCache.swift index 4902185cc0..a1d6985ca9 100644 --- a/Source/SwiftLintCore/Models/LinterCache.swift +++ b/Source/SwiftLintCore/Models/LinterCache.swift @@ -13,7 +13,7 @@ private struct FileCacheEntry: Codable { private struct FileCache: Codable { var entries: [String: FileCacheEntry] - static var empty: FileCache { return Self(entries: [:]) } + static var empty: FileCache { Self(entries: [:]) } } /// A persisted cache for storing and retrieving linter results. @@ -115,7 +115,7 @@ public final class LinterCache { } internal func flushed() -> LinterCache { - return Self(cache: mergeCaches(), location: location, fileManager: fileManager, swiftVersion: swiftVersion) + Self(cache: mergeCaches(), location: location, fileManager: fileManager, swiftVersion: swiftVersion) } private func fileCache(cacheDescription: String) -> FileCache { diff --git a/Source/SwiftLintCore/Models/Location.swift b/Source/SwiftLintCore/Models/Location.swift index 0b12874209..9f9792361b 100644 --- a/Source/SwiftLintCore/Models/Location.swift +++ b/Source/SwiftLintCore/Models/Location.swift @@ -23,7 +23,7 @@ public struct Location: CustomStringConvertible, Comparable, Codable, Sendable { /// The file path for this location relative to the current working directory. public var relativeFile: String? { - return file?.replacingOccurrences(of: FileManager.default.currentDirectoryPath + "/", with: "") + file?.replacingOccurrences(of: FileManager.default.currentDirectoryPath + "/", with: "") } /// Creates a `Location` by specifying its properties directly. diff --git a/Source/SwiftLintCore/Models/Region.swift b/Source/SwiftLintCore/Models/Region.swift index 1553c31ecb..4a2606ed25 100644 --- a/Source/SwiftLintCore/Models/Region.swift +++ b/Source/SwiftLintCore/Models/Region.swift @@ -28,7 +28,7 @@ public struct Region: Equatable { /// /// - returns: True if the specific location is contained in this region. public func contains(_ location: Location) -> Bool { - return start <= location && end >= location + start <= location && end >= location } /// Whether the specified rule is enabled in this region. @@ -37,7 +37,7 @@ public struct Region: Equatable { /// /// - returns: True if the specified rule is enabled in this region. public func isRuleEnabled(_ rule: some Rule) -> Bool { - return !isRuleDisabled(rule) + !isRuleDisabled(rule) } /// Whether the specified rule is disabled in this region. @@ -46,7 +46,7 @@ public struct Region: Equatable { /// /// - returns: True if the specified rule is disabled in this region. public func isRuleDisabled(_ rule: some Rule) -> Bool { - return areRulesDisabled(ruleIDs: type(of: rule).description.allIdentifiers) + areRulesDisabled(ruleIDs: type(of: rule).description.allIdentifiers) } /// Whether the given rules are disabled in this region. diff --git a/Source/SwiftLintCore/Models/RuleDescription.swift b/Source/SwiftLintCore/Models/RuleDescription.swift index 56fbf3d525..d6276d9a6d 100644 --- a/Source/SwiftLintCore/Models/RuleDescription.swift +++ b/Source/SwiftLintCore/Models/RuleDescription.swift @@ -52,11 +52,11 @@ public struct RuleDescription: Equatable, Sendable { public let requiresFileOnDisk: Bool /// The console-printable string for this description. - public var consoleDescription: String { return "\(name) (\(identifier)): \(description)" } + public var consoleDescription: String { "\(name) (\(identifier)): \(description)" } /// All identifiers that have been used to uniquely identify this rule in past and current SwiftLint versions. public var allIdentifiers: [String] { - return Array(deprecatedAliases) + [identifier] + Array(deprecatedAliases) + [identifier] } /// Creates a `RuleDescription` by specifying all its properties directly. @@ -92,6 +92,6 @@ public struct RuleDescription: Equatable, Sendable { // MARK: Equatable public static func == (lhs: RuleDescription, rhs: RuleDescription) -> Bool { - return lhs.identifier == rhs.identifier + lhs.identifier == rhs.identifier } } diff --git a/Source/SwiftLintCore/Models/RuleList.swift b/Source/SwiftLintCore/Models/RuleList.swift index afe6865b14..e81533e9c8 100644 --- a/Source/SwiftLintCore/Models/RuleList.swift +++ b/Source/SwiftLintCore/Models/RuleList.swift @@ -73,11 +73,11 @@ public struct RuleList { } internal func identifier(for alias: String) -> String? { - return aliases[alias] + aliases[alias] } internal func allValidIdentifiers() -> [String] { - return list.flatMap { _, rule -> [String] in + list.flatMap { _, rule -> [String] in rule.description.allIdentifiers } } @@ -85,7 +85,7 @@ public struct RuleList { extension RuleList: Equatable { public static func == (lhs: RuleList, rhs: RuleList) -> Bool { - return lhs.list.map { $0.0 } == rhs.list.map { $0.0 } + lhs.list.map { $0.0 } == rhs.list.map { $0.0 } && lhs.list.map { $0.1.description } == rhs.list.map { $0.1.description } && lhs.aliases == rhs.aliases } diff --git a/Source/SwiftLintCore/Models/RuleRegistry.swift b/Source/SwiftLintCore/Models/RuleRegistry.swift index e58dabdfb4..3a823ea094 100644 --- a/Source/SwiftLintCore/Models/RuleRegistry.swift +++ b/Source/SwiftLintCore/Models/RuleRegistry.swift @@ -27,6 +27,6 @@ public final class RuleRegistry: @unchecked Sendable { /// /// - returns: The rule matching the specified ID, if one was found. public func rule(forID id: String) -> (any Rule.Type)? { - return list.list[id] + list.list[id] } } diff --git a/Source/SwiftLintCore/Models/RuleStorage.swift b/Source/SwiftLintCore/Models/RuleStorage.swift index caaa3db5e8..cf78980da9 100644 --- a/Source/SwiftLintCore/Models/RuleStorage.swift +++ b/Source/SwiftLintCore/Models/RuleStorage.swift @@ -32,7 +32,7 @@ public class RuleStorage: CustomStringConvertible { /// /// - returns: All file information for a given rule that was collected via `collect(...)`. func collectedInfo(for rule: R) -> [SwiftLintFile: R.FileInfo]? { - return access.sync { + access.sync { storage[ObjectIdentifier(R.self)] as? [SwiftLintFile: R.FileInfo] } } diff --git a/Source/SwiftLintCore/Models/StyleViolation.swift b/Source/SwiftLintCore/Models/StyleViolation.swift index 627f7460e9..7e0739c214 100644 --- a/Source/SwiftLintCore/Models/StyleViolation.swift +++ b/Source/SwiftLintCore/Models/StyleViolation.swift @@ -20,7 +20,7 @@ public struct StyleViolation: CustomStringConvertible, Codable, Hashable { /// A printable description for this violation. public var description: String { - return XcodeReporter.generateForSingleViolation(self) + XcodeReporter.generateForSingleViolation(self) } /// Creates a `StyleViolation` by specifying its properties directly. diff --git a/Source/SwiftLintCore/Models/SwiftLintFile.swift b/Source/SwiftLintCore/Models/SwiftLintFile.swift index 6d029d2ab6..7a42fb0936 100644 --- a/Source/SwiftLintCore/Models/SwiftLintFile.swift +++ b/Source/SwiftLintCore/Models/SwiftLintFile.swift @@ -47,22 +47,22 @@ public final class SwiftLintFile { /// The path on disk for this file. public var path: String? { - return file.path + file.path } /// The file's contents. public var contents: String { - return file.contents + file.contents } /// A string view into the contents of this file optimized for string manipulation operations. public var stringView: StringView { - return file.stringView + file.stringView } /// The parsed lines for this file's contents. public var lines: [Line] { - return file.lines + file.lines } /// Mark this file as used for testing purposes. diff --git a/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift b/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift index 13f122ea3d..5eb0878675 100644 --- a/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift +++ b/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift @@ -23,11 +23,11 @@ public struct SwiftLintSyntaxMap { /// - returns: The array of syntax tokens intersecting with byte range. public func tokens(inByteRange byteRange: ByteRange) -> [SwiftLintSyntaxToken] { func intersect(_ token: SwiftLintSyntaxToken) -> Bool { - return token.range.intersects(byteRange) + token.range.intersects(byteRange) } func intersectsOrAfter(_ token: SwiftLintSyntaxToken) -> Bool { - return token.offset + token.length > byteRange.location + token.offset + token.length > byteRange.location } guard let startIndex = tokens.firstIndexAssumingSorted(where: intersectsOrAfter) else { @@ -49,6 +49,6 @@ public struct SwiftLintSyntaxMap { /// /// - returns: The syntax kinds in the specified byte range. public func kinds(inByteRange byteRange: ByteRange) -> [SyntaxKind] { - return tokens(inByteRange: byteRange).compactMap { $0.kind } + tokens(inByteRange: byteRange).compactMap { $0.kind } } } diff --git a/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift b/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift index 9266e39f92..1ad8f353c2 100644 --- a/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift +++ b/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift @@ -18,23 +18,23 @@ public struct SwiftLintSyntaxToken { /// The byte range in a source file for this token. public var range: ByteRange { - return value.range + value.range } /// The starting byte offset in a source file for this token. public var offset: ByteCount { - return value.offset + value.offset } /// The length in bytes for this token. public var length: ByteCount { - return value.length + value.length } } public extension Array where Element == SwiftLintSyntaxToken { /// The kinds for these tokens. var kinds: [SyntaxKind] { - return compactMap { $0.kind } + compactMap { $0.kind } } } diff --git a/Source/SwiftLintCore/Models/SwiftVersion.swift b/Source/SwiftLintCore/Models/SwiftVersion.swift index fefb6cec0a..27bc80c658 100644 --- a/Source/SwiftLintCore/Models/SwiftVersion.swift +++ b/Source/SwiftLintCore/Models/SwiftVersion.swift @@ -95,14 +95,14 @@ public extension SwiftVersion { private extension Dictionary where Key == String { var versionMajor: Int? { - return (self["key.version_major"] as? Int64).flatMap({ Int($0) }) + (self["key.version_major"] as? Int64).flatMap({ Int($0) }) } var versionMinor: Int? { - return (self["key.version_minor"] as? Int64).flatMap({ Int($0) }) + (self["key.version_minor"] as? Int64).flatMap({ Int($0) }) } var versionPatch: Int? { - return (self["key.version_patch"] as? Int64).flatMap({ Int($0) }) + (self["key.version_patch"] as? Int64).flatMap({ Int($0) }) } } diff --git a/Source/SwiftLintCore/Models/ViolationSeverity.swift b/Source/SwiftLintCore/Models/ViolationSeverity.swift index 3905f78dec..9f74e1dd84 100644 --- a/Source/SwiftLintCore/Models/ViolationSeverity.swift +++ b/Source/SwiftLintCore/Models/ViolationSeverity.swift @@ -9,6 +9,6 @@ public enum ViolationSeverity: String, Comparable, Codable, InlinableOptionType // MARK: Comparable public static func < (lhs: ViolationSeverity, rhs: ViolationSeverity) -> Bool { - return lhs == .warning && rhs == .error + lhs == .warning && rhs == .error } } diff --git a/Source/SwiftLintCore/Models/YamlParser.swift b/Source/SwiftLintCore/Models/YamlParser.swift index c4238be19a..ab4af13f87 100644 --- a/Source/SwiftLintCore/Models/YamlParser.swift +++ b/Source/SwiftLintCore/Models/YamlParser.swift @@ -26,7 +26,7 @@ public struct YamlParser { private extension Constructor { static func swiftlintConstructor(env: [String: String]) -> Constructor { - return Constructor(customScalarMap(env: env)) + Constructor(customScalarMap(env: env)) } static func customScalarMap(env: [String: String]) -> ScalarMap { @@ -40,8 +40,8 @@ private extension Constructor { private extension String { static func constructExpandingEnvVars(env: [String: String]) -> (_ scalar: Node.Scalar) -> String? { - return { (scalar: Node.Scalar) -> String? in - return scalar.string.expandingEnvVars(env: env) + { (scalar: Node.Scalar) -> String? in + scalar.string.expandingEnvVars(env: env) } } diff --git a/Source/SwiftLintCore/Protocols/ASTRule.swift b/Source/SwiftLintCore/Protocols/ASTRule.swift index 0f64595ff9..ef367cba58 100644 --- a/Source/SwiftLintCore/Protocols/ASTRule.swift +++ b/Source/SwiftLintCore/Protocols/ASTRule.swift @@ -27,7 +27,7 @@ public protocol ASTRule: Rule { public extension ASTRule { func validate(file: SwiftLintFile) -> [StyleViolation] { - return validate(file: file, dictionary: file.structureDictionary) + validate(file: file, dictionary: file.structureDictionary) } /// Executes the rule on a file and a subset of its AST structure, returning any violations to the rule's @@ -38,7 +38,7 @@ public extension ASTRule { /// /// - returns: All style violations to the rule's expectations. func validate(file: SwiftLintFile, dictionary: SourceKittenDictionary) -> [StyleViolation] { - return dictionary.traverseDepthFirst { subDict in + dictionary.traverseDepthFirst { subDict in guard let kind = self.kind(from: subDict) else { return nil } return validate(file: file, kind: kind, dictionary: subDict) } @@ -47,18 +47,18 @@ public extension ASTRule { public extension ASTRule where KindType == SwiftDeclarationKind { func kind(from dictionary: SourceKittenDictionary) -> KindType? { - return dictionary.declarationKind + dictionary.declarationKind } } public extension ASTRule where KindType == SwiftExpressionKind { func kind(from dictionary: SourceKittenDictionary) -> KindType? { - return dictionary.expressionKind + dictionary.expressionKind } } public extension ASTRule where KindType == StatementKind { func kind(from dictionary: SourceKittenDictionary) -> KindType? { - return dictionary.statementKind + dictionary.statementKind } } diff --git a/Source/SwiftLintCore/Protocols/CollectingRule.swift b/Source/SwiftLintCore/Protocols/CollectingRule.swift index de9cd6e61f..619b96c28b 100644 --- a/Source/SwiftLintCore/Protocols/CollectingRule.swift +++ b/Source/SwiftLintCore/Protocols/CollectingRule.swift @@ -54,11 +54,11 @@ public extension CollectingRule { return validate(file: file, collectedInfo: info, compilerArguments: compilerArguments) } func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> FileInfo { - return collectInfo(for: file) + collectInfo(for: file) } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], compilerArguments: [String]) -> [StyleViolation] { - return validate(file: file, collectedInfo: collectedInfo) + validate(file: file, collectedInfo: collectedInfo) } func validate(file: SwiftLintFile) -> [StyleViolation] { queuedFatalError("Must call `validate(file:collectedInfo:)` for CollectingRule") @@ -116,7 +116,7 @@ package protocol CollectingCorrectableRule: CollectingRule, CorrectableRule { package extension CollectingCorrectableRule { func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], compilerArguments: [String]) -> [Correction] { - return correct(file: file, collectedInfo: collectedInfo) + correct(file: file, collectedInfo: collectedInfo) } func correct(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [Correction] { diff --git a/Source/SwiftLintCore/Protocols/Rule.swift b/Source/SwiftLintCore/Protocols/Rule.swift index ca48dc1ea9..85d97b794f 100644 --- a/Source/SwiftLintCore/Protocols/Rule.swift +++ b/Source/SwiftLintCore/Protocols/Rule.swift @@ -84,11 +84,11 @@ public extension Rule { func validate(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [StyleViolation] { - return validate(file: file, compilerArguments: compilerArguments) + validate(file: file, compilerArguments: compilerArguments) } func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] { - return validate(file: file) + validate(file: file) } func isEqualTo(_ rule: any Rule) -> Bool { @@ -153,10 +153,10 @@ public protocol CorrectableRule: Rule { public extension CorrectableRule { func correct(file: SwiftLintFile, compilerArguments: [String]) -> [Correction] { - return correct(file: file) + correct(file: file) } func correct(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [Correction] { - return correct(file: file, compilerArguments: compilerArguments) + correct(file: file, compilerArguments: compilerArguments) } } diff --git a/Source/SwiftLintCore/Reporters/CSVReporter.swift b/Source/SwiftLintCore/Reporters/CSVReporter.swift index ef95ddac62..023f32b68f 100644 --- a/Source/SwiftLintCore/Reporters/CSVReporter.swift +++ b/Source/SwiftLintCore/Reporters/CSVReporter.swift @@ -26,7 +26,7 @@ struct CSVReporter: Reporter { // MARK: - Private private static func csvRow(for violation: StyleViolation) -> String { - return [ + [ violation.location.file?.escapedForCSV() ?? "", violation.location.line?.description ?? "", violation.location.character?.description ?? "", diff --git a/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift b/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift index 46dd4d90ad..47327648c6 100644 --- a/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift +++ b/Source/SwiftLintCore/Reporters/CheckstyleReporter.swift @@ -8,7 +8,7 @@ struct CheckstyleReporter: Reporter { static let description = "Reports violations as Checkstyle XML." static func generateReport(_ violations: [StyleViolation]) -> String { - return [ + [ "\n", violations .group(by: { ($0.location.file ?? "").escapedForXML() }) @@ -21,7 +21,7 @@ struct CheckstyleReporter: Reporter { // MARK: - Private private static func generateForViolationFile(_ file: String, violations: [StyleViolation]) -> String { - return [ + [ "\n\t\n", violations.map(generateForSingleViolation).joined(), "\t", diff --git a/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift b/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift index 83e7fd23ed..90a622d2c1 100644 --- a/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift +++ b/Source/SwiftLintCore/Reporters/CodeClimateReporter.swift @@ -13,14 +13,14 @@ struct CodeClimateReporter: Reporter { static let description = "Reports violations as a JSON array in Code Climate format." static func generateReport(_ violations: [StyleViolation]) -> String { - return toJSON(violations.map(dictionary(for:))) + toJSON(violations.map(dictionary(for:))) .replacingOccurrences(of: "\\/", with: "/") } // MARK: - Private private static func dictionary(for violation: StyleViolation) -> [String: Any] { - return [ + [ "check_name": violation.ruleName, "description": violation.reason, "engine_name": "SwiftLint", diff --git a/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift b/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift index 9d61c07d7e..cbe31039fd 100644 --- a/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift +++ b/Source/SwiftLintCore/Reporters/GitHubActionsLoggingReporter.swift @@ -8,7 +8,7 @@ struct GitHubActionsLoggingReporter: Reporter { "machine for Actions can recognize as messages." static func generateReport(_ violations: [StyleViolation]) -> String { - return violations.map(generateForSingleViolation).joined(separator: "\n") + violations.map(generateForSingleViolation).joined(separator: "\n") } // MARK: - Private @@ -17,7 +17,7 @@ struct GitHubActionsLoggingReporter: Reporter { // swiftlint:disable:next line_length // https://help.github.com/en/github/automating-your-workflow-with-github-actions/development-tools-for-github-actions#logging-commands // ::(warning|error) file={relative_path_to_file},line={:line},col={:character}::{content} - return [ + [ "::\(violation.severity.rawValue) ", "file=\(violation.location.relativeFile ?? ""),", "line=\(violation.location.line ?? 1),", diff --git a/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift b/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift index a297ed3f75..df02194405 100644 --- a/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift +++ b/Source/SwiftLintCore/Reporters/GitLabJUnitReporter.swift @@ -7,7 +7,7 @@ struct GitLabJUnitReporter: Reporter { static let description = "Reports violations as JUnit XML supported by GitLab." static func generateReport(_ violations: [StyleViolation]) -> String { - return "\n" + + "\n" + violations.map({ violation -> String in let fileName = (violation.location.relativeFile ?? "").escapedForXML() let line = violation.location.line.map(String.init) diff --git a/Source/SwiftLintCore/Reporters/HTMLReporter.swift b/Source/SwiftLintCore/Reporters/HTMLReporter.swift index fcc1d65486..ceaf3042bb 100644 --- a/Source/SwiftLintCore/Reporters/HTMLReporter.swift +++ b/Source/SwiftLintCore/Reporters/HTMLReporter.swift @@ -15,8 +15,7 @@ struct HTMLReporter: Reporter { static let description = "Reports violations as HTML." static func generateReport(_ violations: [StyleViolation]) -> String { - return generateReport(violations, swiftlintVersion: Version.current.value, - dateString: formatter.string(from: Date())) + generateReport(violations, swiftlintVersion: Version.current.value, dateString: formatter.string(from: Date())) } // MARK: - Internal diff --git a/Source/SwiftLintCore/Reporters/JSONReporter.swift b/Source/SwiftLintCore/Reporters/JSONReporter.swift index 1c65725477..537c0f73c5 100644 --- a/Source/SwiftLintCore/Reporters/JSONReporter.swift +++ b/Source/SwiftLintCore/Reporters/JSONReporter.swift @@ -10,13 +10,13 @@ struct JSONReporter: Reporter { static let description = "Reports violations as a JSON array." static func generateReport(_ violations: [StyleViolation]) -> String { - return toJSON(violations.map(dictionary(for:))) + toJSON(violations.map(dictionary(for:))) } // MARK: - Private private static func dictionary(for violation: StyleViolation) -> [String: Any] { - return [ + [ "file": violation.location.file ?? NSNull() as Any, "line": violation.location.line ?? NSNull() as Any, "character": violation.location.character ?? NSNull() as Any, diff --git a/Source/SwiftLintCore/Reporters/MarkdownReporter.swift b/Source/SwiftLintCore/Reporters/MarkdownReporter.swift index e4fed75337..642f30faab 100644 --- a/Source/SwiftLintCore/Reporters/MarkdownReporter.swift +++ b/Source/SwiftLintCore/Reporters/MarkdownReporter.swift @@ -24,7 +24,7 @@ struct MarkdownReporter: Reporter { // MARK: - Private private static func markdownRow(for violation: StyleViolation) -> String { - return [ + [ violation.location.file?.escapedForMarkdown() ?? "", violation.location.line?.description ?? "", severity(for: violation.severity), diff --git a/Source/SwiftLintCore/Reporters/RelativePathReporter.swift b/Source/SwiftLintCore/Reporters/RelativePathReporter.swift index e8ee8df298..c61586e450 100644 --- a/Source/SwiftLintCore/Reporters/RelativePathReporter.swift +++ b/Source/SwiftLintCore/Reporters/RelativePathReporter.swift @@ -7,7 +7,7 @@ struct RelativePathReporter: Reporter { static let description = "Reports violations with relative paths." static func generateReport(_ violations: [StyleViolation]) -> String { - return violations.map(generateForSingleViolation).joined(separator: "\n") + violations.map(generateForSingleViolation).joined(separator: "\n") } /// Generates a report for a single violation. @@ -18,7 +18,7 @@ struct RelativePathReporter: Reporter { internal static func generateForSingleViolation(_ violation: StyleViolation) -> String { // {relative_path_to_file}{:line}{:character}: {error,warning}: {content} - return [ + [ "\(violation.location.relativeFile ?? "")", ":\(violation.location.line ?? 1)", ":\(violation.location.character ?? 1): ", diff --git a/Source/SwiftLintCore/Reporters/SARIFReporter.swift b/Source/SwiftLintCore/Reporters/SARIFReporter.swift index 4349941c28..42024e52a2 100644 --- a/Source/SwiftLintCore/Reporters/SARIFReporter.swift +++ b/Source/SwiftLintCore/Reporters/SARIFReporter.swift @@ -36,7 +36,7 @@ struct SARIFReporter: Reporter { // MARK: - Private private static func dictionary(for violation: StyleViolation) -> [String: Any] { - return [ + [ "level": violation.severity.rawValue, "ruleId": violation.ruleIdentifier, "message": [ diff --git a/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift b/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift index 03dec72f5c..3e014c9e13 100644 --- a/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift +++ b/Source/SwiftLintCore/Reporters/SonarQubeReporter.swift @@ -9,14 +9,14 @@ struct SonarQubeReporter: Reporter { static let description = "Reports violations in SonarQube import format." static func generateReport(_ violations: [StyleViolation]) -> String { - return toJSON(["issues": violations.map(dictionary(for:))]) + toJSON(["issues": violations.map(dictionary(for:))]) } // MARK: - Private // refer to https://docs.sonarqube.org/display/SONAR/Generic+Issue+Data private static func dictionary(for violation: StyleViolation) -> [String: Any] { - return [ + [ "engineId": "SwiftLint", "ruleId": violation.ruleIdentifier, "primaryLocation": [ diff --git a/Source/SwiftLintCore/Reporters/XcodeReporter.swift b/Source/SwiftLintCore/Reporters/XcodeReporter.swift index cff21a898a..a7a04913db 100644 --- a/Source/SwiftLintCore/Reporters/XcodeReporter.swift +++ b/Source/SwiftLintCore/Reporters/XcodeReporter.swift @@ -7,7 +7,7 @@ struct XcodeReporter: Reporter { static let description = "Reports violations in the format Xcode uses to display in the IDE. (default)" static func generateReport(_ violations: [StyleViolation]) -> String { - return violations.map(generateForSingleViolation).joined(separator: "\n") + violations.map(generateForSingleViolation).joined(separator: "\n") } /// Generates a report for a single violation. @@ -17,7 +17,7 @@ struct XcodeReporter: Reporter { /// - returns: The report for a single violation. internal static func generateForSingleViolation(_ violation: StyleViolation) -> String { // {full_path_to_file}{:line}{:character}: {error,warning}: {content} - return [ + [ "\(violation.location): ", "\(violation.severity.rawValue): ", "\(violation.ruleName) Violation: ", diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index b6e66089a0..4c21be0dd4 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -45,8 +45,8 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, /// The `RuleDescription` for the custom rule defined here. public var description: RuleDescription { - return RuleDescription(identifier: identifier, name: name ?? identifier, - description: "", kind: .style) + RuleDescription(identifier: identifier, name: name ?? identifier, + description: "", kind: .style) } /// Create a `RegexConfiguration` with the specified identifier, with other properties to be set later. diff --git a/Source/SwiftLintCore/Rules/CustomRules.swift b/Source/SwiftLintCore/Rules/CustomRules.swift index 8eca8e70b8..d6a3e4d9d0 100644 --- a/Source/SwiftLintCore/Rules/CustomRules.swift +++ b/Source/SwiftLintCore/Rules/CustomRules.swift @@ -38,7 +38,7 @@ struct CustomRulesConfiguration: RuleConfiguration, CacheDescriptionProvider { struct CustomRules: Rule, CacheDescriptionProvider { var cacheDescription: String { - return configuration.cacheDescription + configuration.cacheDescription } static let description = RuleDescription( @@ -92,6 +92,6 @@ struct CustomRules: Rule, CacheDescriptionProvider { private extension Region { func isRuleDisabled(customRuleIdentifier: String) -> Bool { - return disabledRuleIdentifiers.contains(RuleIdentifier(customRuleIdentifier)) + disabledRuleIdentifiers.contains(RuleIdentifier(customRuleIdentifier)) } } diff --git a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift index 947328916f..a46bc638dc 100644 --- a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift +++ b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift @@ -31,7 +31,7 @@ package struct SuperfluousDisableCommandRule: SourceKitFreeRule { package func validate(file: SwiftLintFile) -> [StyleViolation] { // This rule is implemented in Linter.swift - return [] + [] } func reason(for rule: (some Rule).Type) -> String { @@ -42,6 +42,6 @@ package struct SuperfluousDisableCommandRule: SourceKitFreeRule { } func reason(forNonExistentRule rule: String) -> String { - return "'\(rule)' is not a valid SwiftLint rule; remove it from the disable command" + "'\(rule)' is not a valid SwiftLint rule; remove it from the disable command" } } diff --git a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift b/Source/swiftlint/Commands/Common/RulesFilterOptions.swift index 0a409fb630..5589113aa8 100644 --- a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift +++ b/Source/swiftlint/Commands/Common/RulesFilterOptions.swift @@ -4,11 +4,11 @@ enum RuleEnablementOptions: String, EnumerableFlag { case enabled, disabled static func name(for value: RuleEnablementOptions) -> NameSpecification { - return .shortAndLong + .shortAndLong } static func help(for value: RuleEnablementOptions) -> ArgumentHelp? { - return "Only show \(value.rawValue) rules" + "Only show \(value.rawValue) rules" } } diff --git a/Source/swiftlint/Extensions/Configuration+CommandLine.swift b/Source/swiftlint/Extensions/Configuration+CommandLine.swift index d9422a4d42..886abae41c 100644 --- a/Source/swiftlint/Extensions/Configuration+CommandLine.swift +++ b/Source/swiftlint/Extensions/Configuration+CommandLine.swift @@ -41,7 +41,7 @@ private func scriptInputFiles() throws -> [SwiftLintFile] { } #if os(Linux) -private func autoreleasepool(block: () -> T) -> T { return block() } +private func autoreleasepool(block: () -> T) -> T { block() } #endif extension Configuration { diff --git a/Source/swiftlint/Helpers/Benchmark.swift b/Source/swiftlint/Helpers/Benchmark.swift index 18e111a0c5..b05755babb 100644 --- a/Source/swiftlint/Helpers/Benchmark.swift +++ b/Source/swiftlint/Helpers/Benchmark.swift @@ -31,7 +31,7 @@ struct Benchmark { let entriesKeyValues: [(String, Double)] = entriesDict.sorted { $0.1 < $1.1 } let lines: [String] = entriesKeyValues.map { id, time -> String in // swiftlint:disable:next legacy_objc_type - return "\(numberFormatter.string(from: NSNumber(value: time))!): \(id)" + "\(numberFormatter.string(from: NSNumber(value: time))!): \(id)" } let string: String = lines.joined(separator: "\n") + "\n" let url = URL(fileURLWithPath: "benchmark_\(name)_\(timestamp).txt", isDirectory: false) diff --git a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift index ffd8e13747..d9b1c05545 100644 --- a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift +++ b/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift @@ -59,7 +59,7 @@ private func partiallyFilter(arguments args: [String]) -> ([String], Bool) { extension Array where Element == String { /// Return the full list of compiler arguments, replacing any response files with their contents. fileprivate var expandingResponseFiles: [String] { - return flatMap { arg -> [String] in + flatMap { arg -> [String] in guard arg.starts(with: "@") else { return [arg] } diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift index d1bbbb47fc..26bbe9e0ed 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -152,7 +152,7 @@ struct LintOrAnalyzeCommand { private static func printStatus(violations: [StyleViolation], files: [SwiftLintFile], serious: Int, verb: String) { let pluralSuffix = { (collection: [Any]) -> String in - return collection.count != 1 ? "s" : "" + collection.count != 1 ? "s" : "" } queuedPrintError( "Done \(verb)! Found \(violations.count) violation\(pluralSuffix(violations)), " + @@ -253,7 +253,7 @@ struct LintOrAnalyzeCommand { } let pluralSuffix = { (collection: [Any]) -> String in - return collection.count != 1 ? "s" : "" + collection.count != 1 ? "s" : "" } queuedPrintError("Done correcting \(files.count) file\(pluralSuffix(files))!") } diff --git a/Source/swiftlint/Helpers/LintableFilesVisitor.swift b/Source/swiftlint/Helpers/LintableFilesVisitor.swift index b13993ddc7..284ccaf2d4 100644 --- a/Source/swiftlint/Helpers/LintableFilesVisitor.swift +++ b/Source/swiftlint/Helpers/LintableFilesVisitor.swift @@ -7,11 +7,11 @@ typealias Arguments = [String] class CompilerInvocations { static func buildLog(compilerInvocations: [[String]]) -> CompilerInvocations { - return ArrayCompilerInvocations(invocations: compilerInvocations) + ArrayCompilerInvocations(invocations: compilerInvocations) } static func compilationDatabase(compileCommands: [File: Arguments]) -> CompilerInvocations { - return CompilationDatabaseInvocations(compileCommands: compileCommands) + CompilationDatabaseInvocations(compileCommands: compileCommands) } /// Default implementation @@ -31,8 +31,8 @@ class CompilerInvocations { } override func arguments(forFile path: String?) -> Arguments { - return path.flatMap { path in - return invocationsByArgument[path]?.first + path.flatMap { path in + invocationsByArgument[path]?.first } ?? [] } } @@ -45,8 +45,8 @@ class CompilerInvocations { } override func arguments(forFile path: String?) -> Arguments { - return path.flatMap { path in - return compileCommands[path] ?? + path.flatMap { path in + compileCommands[path] ?? compileCommands[path.path(relativeTo: FileManager.default.currentDirectoryPath)] } ?? [] } @@ -59,7 +59,7 @@ enum LintOrAnalyzeModeWithCompilerArguments { } private func resolveParamsFiles(args: [String]) -> [String] { - return args.reduce(into: []) { (allArgs: inout [String], arg: String) in + args.reduce(into: []) { (allArgs: inout [String], arg: String) in if arg.hasPrefix("@"), let contents = try? String(contentsOfFile: String(arg.dropFirst())) { allArgs.append(contentsOf: resolveParamsFiles(args: contents.split(separator: "\n").map(String.init))) } else { diff --git a/Tests/CLITests/RulesFilterTests.swift b/Tests/CLITests/RulesFilterTests.swift index eb99810373..b9c42efa96 100644 --- a/Tests/CLITests/RulesFilterTests.swift +++ b/Tests/CLITests/RulesFilterTests.swift @@ -141,7 +141,7 @@ private struct RuleMock1: Rule { init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { - return [] + [] } } @@ -156,7 +156,7 @@ private struct RuleMock2: Rule { init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { - return [] + [] } } @@ -171,7 +171,7 @@ private struct CorrectableRuleMock: CorrectableRule { init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { - return [] + [] } func correct(file: SwiftLintFile) -> [Correction] { diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index 67316b3613..a4e345af7f 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -152,7 +152,7 @@ private struct StaticStringImitator { } var staticString: StaticString { - return unsafeBitCast(self, to: StaticString.self) + unsafeBitCast(self, to: StaticString.self) } } } diff --git a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift index 0a154dea0c..bef00d1fe6 100644 --- a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift @@ -8,7 +8,7 @@ final class CollectingRuleTests: SwiftLintTestCase { var configuration = SeverityConfiguration(.warning) func collectInfo(for file: SwiftLintFile) -> Int { - return 42 + 42 } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Int]) -> [StyleViolation] { XCTAssertEqual(collectedInfo[file], 42) @@ -29,7 +29,7 @@ final class CollectingRuleTests: SwiftLintTestCase { var configuration = SeverityConfiguration(.warning) func collectInfo(for file: SwiftLintFile) -> String { - return file.contents + file.contents } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String]) -> [StyleViolation] { let values = collectedInfo.values @@ -54,7 +54,7 @@ final class CollectingRuleTests: SwiftLintTestCase { var configuration = SeverityConfiguration(.warning) func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> [String] { - return compilerArguments + compilerArguments } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: [String]], compilerArguments: [String]) -> [StyleViolation] { @@ -76,7 +76,7 @@ final class CollectingRuleTests: SwiftLintTestCase { var configuration = SeverityConfiguration(.warning) func collectInfo(for file: SwiftLintFile) -> String { - return file.contents + file.contents } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String]) -> [StyleViolation] { @@ -108,7 +108,7 @@ final class CollectingRuleTests: SwiftLintTestCase { var configuration = SeverityConfiguration(.warning) func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> String { - return file.contents + file.contents } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String], compilerArguments: [String]) @@ -143,10 +143,10 @@ extension MockCollectingRule { @RuleConfigurationDescriptionBuilder var configurationDescription: some Documentable { RuleConfigurationOption.noOptions } static var description: RuleDescription { - return RuleDescription(identifier: "test_rule", name: "", description: "", kind: .lint) + RuleDescription(identifier: "test_rule", name: "", description: "", kind: .lint) } static var configuration: Configuration? { - return Configuration(rulesMode: .only([description.identifier]), ruleList: RuleList(rules: self)) + Configuration(rulesMode: .only([description.identifier]), ruleList: RuleList(rules: self)) } init(configuration: Any) throws { self.init() } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index bca39db30e..50711a1e9f 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -6,7 +6,7 @@ import XCTest private extension Configuration { func contains(rule: T.Type) -> Bool { - return rules.contains { $0 is T } + rules.contains { $0 is T } } } @@ -32,7 +32,7 @@ extension ConfigurationTests { // MARK: - Merging Aspects func testWarningThresholdMerging() { func configuration(forWarningThreshold warningThreshold: Int?) -> Configuration { - return Configuration( + Configuration( warningThreshold: warningThreshold, reporter: XcodeReporter.identifier ) diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 858673608c..4ac7254023 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -251,7 +251,7 @@ final class ConfigurationTests: SwiftLintTestCase { } func modificationDate(forFileAtPath path: String) -> Date? { - return nil + nil } func isFile(atPath path: String) -> Bool { diff --git a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift index 194f8312ca..448886f60f 100644 --- a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift @@ -251,6 +251,6 @@ final class CustomRulesTests: SwiftLintTestCase { } private func getTestTextFile() -> SwiftLintFile { - return SwiftLintFile(path: "\(testResourcesPath)/test.txt")! + SwiftLintFile(path: "\(testResourcesPath)/test.txt")! } } diff --git a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift index 8a013c63bb..06f890bdea 100644 --- a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift @@ -141,7 +141,7 @@ final class ExpiringTodoRuleTests: SwiftLintTestCase { } private func violations(_ example: Example) -> [StyleViolation] { - return SwiftLintFrameworkTests.violations(example, config: config) + SwiftLintFrameworkTests.violations(example, config: config) } private func dateString(for status: ExpiringTodoRule.ExpiryViolationLevel) -> String { @@ -198,6 +198,6 @@ final class ExpiringTodoRuleTests: SwiftLintTestCase { fileprivate extension Configuration { var ruleConfiguration: ExpiringTodoConfiguration { // swiftlint:disable:next force_cast - return (rules.first(where: { $0 is ExpiringTodoRule }) as! ExpiringTodoRule).configuration + (rules.first(where: { $0 is ExpiringTodoRule }) as! ExpiringTodoRule).configuration } } diff --git a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift index 1f97099a70..04e9a6cbab 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift @@ -10,7 +10,7 @@ private func funcWithBody(_ body: String, } private func violatingFuncWithBody(_ body: String, file: StaticString = #filePath, line: UInt = #line) -> Example { - return funcWithBody(body, violates: true, file: file, line: line) + funcWithBody(body, violates: true, file: file, line: line) } final class FunctionBodyLengthRuleTests: SwiftLintTestCase { diff --git a/Tests/SwiftLintFrameworkTests/GlobTests.swift b/Tests/SwiftLintFrameworkTests/GlobTests.swift index 2cb5fb1a45..0f94aaddc2 100644 --- a/Tests/SwiftLintFrameworkTests/GlobTests.swift +++ b/Tests/SwiftLintFrameworkTests/GlobTests.swift @@ -3,7 +3,7 @@ import XCTest final class GlobTests: SwiftLintTestCase { private var mockPath: String { - return testResourcesPath.stringByAppendingPathComponent("ProjectMock") + testResourcesPath.stringByAppendingPathComponent("ProjectMock") } func testNonExistingDirectory() { diff --git a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift index 18fde17fb3..3bdb252d14 100644 --- a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift +++ b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift @@ -11,7 +11,7 @@ private struct CacheTestHelper { private var fileManager: TestFileManager { // swiftlint:disable:next force_cast - return cache.fileManager as! TestFileManager + cache.fileManager as! TestFileManager } fileprivate init(dict: [String: Any], cache: LinterCache) { @@ -36,7 +36,7 @@ private struct CacheTestHelper { } fileprivate func makeConfig(dict: [String: Any]) -> Configuration { - return try! Configuration(dict: dict, ruleList: ruleList) // swiftlint:disable:this force_try + try! Configuration(dict: dict, ruleList: ruleList) // swiftlint:disable:this force_try } fileprivate func touch(file: String) { @@ -48,19 +48,19 @@ private struct CacheTestHelper { } fileprivate func fileCount() -> Int { - return fileManager.stubbedModificationDateByPath.count + fileManager.stubbedModificationDateByPath.count } } private class TestFileManager: LintableFileManager { fileprivate func filesToLint(inPath: String, rootDirectory: String? = nil) -> [String] { - return [] + [] } fileprivate var stubbedModificationDateByPath = [String: Date]() fileprivate func modificationDate(forFileAtPath path: String) -> Date? { - return stubbedModificationDateByPath[path] + stubbedModificationDateByPath[path] } fileprivate func isFile(atPath path: String) -> Bool { @@ -74,7 +74,7 @@ final class LinterCacheTests: SwiftLintTestCase { private var cache = LinterCache(fileManager: TestFileManager()) private func makeCacheTestHelper(dict: [String: Any]) -> CacheTestHelper { - return CacheTestHelper(dict: dict, cache: cache) + CacheTestHelper(dict: dict, cache: cache) } private func cacheAndValidate(violations: [StyleViolation], forFile: String, configuration: Configuration, diff --git a/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift b/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift index 61e5e7767e..bfdb9ba375 100644 --- a/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ObjectLiteralRuleTests.swift @@ -21,7 +21,7 @@ final class ObjectLiteralRuleTests: SwiftLintTestCase { } private var allTriggeringExamples: [Example] { - return imageLiteralTriggeringExamples + colorLiteralTriggeringExamples + imageLiteralTriggeringExamples + colorLiteralTriggeringExamples } // MARK: - Test Methods diff --git a/Tests/SwiftLintFrameworkTests/ReporterTests.swift b/Tests/SwiftLintFrameworkTests/ReporterTests.swift index 48cd296309..94b16edb6a 100644 --- a/Tests/SwiftLintFrameworkTests/ReporterTests.swift +++ b/Tests/SwiftLintFrameworkTests/ReporterTests.swift @@ -12,7 +12,7 @@ final class ReporterTests: SwiftLintTestCase { } private func stringFromFile(_ filename: String) -> String { - return SwiftLintFile(path: "\(testResourcesPath)/\(filename)")!.contents + SwiftLintFile(path: "\(testResourcesPath)/\(filename)")!.contents } private func generateViolations() -> [StyleViolation] { diff --git a/Tests/SwiftLintFrameworkTests/RuleTests.swift b/Tests/SwiftLintFrameworkTests/RuleTests.swift index 45a28015f9..a87dca6e0b 100644 --- a/Tests/SwiftLintFrameworkTests/RuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleTests.swift @@ -16,7 +16,7 @@ struct RuleWithLevelsMock: Rule { try self.configuration.apply(configuration: configuration) } - func validate(file: SwiftLintFile) -> [StyleViolation] { return [] } + func validate(file: SwiftLintFile) -> [StyleViolation] { [] } } final class RuleTests: SwiftLintTestCase { @@ -30,7 +30,7 @@ final class RuleTests: SwiftLintTestCase { init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { - return [] + [] } } @@ -44,7 +44,7 @@ final class RuleTests: SwiftLintTestCase { init(configuration: Any) throws { self.init() } func validate(file: SwiftLintFile) -> [StyleViolation] { - return [] + [] } } @@ -61,7 +61,7 @@ final class RuleTests: SwiftLintTestCase { try self.configuration.apply(configuration: configuration) } - func validate(file: SwiftLintFile) -> [StyleViolation] { return [] } + func validate(file: SwiftLintFile) -> [StyleViolation] { [] } } func testRuleIsEqualTo() { diff --git a/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift b/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift index 4afc8cbd63..a001de08d4 100644 --- a/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift +++ b/Tests/SwiftLintFrameworkTests/YamlSwiftLintTests.swift @@ -39,6 +39,6 @@ final class YamlSwiftLintTests: SwiftLintTestCase { } private func getTestYaml() throws -> String { - return try String(contentsOfFile: "\(testResourcesPath)/test.yml", encoding: .utf8) + try String(contentsOfFile: "\(testResourcesPath)/test.yml", encoding: .utf8) } } diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index bf3e0c544a..c79a9d5bf6 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -43,7 +43,7 @@ private extension SwiftLintFile { public extension String { func stringByAppendingPathComponent(_ pathComponent: String) -> String { - return bridge().appendingPathComponent(pathComponent) + bridge().appendingPathComponent(pathComponent) } } @@ -82,12 +82,12 @@ public func violations(_ example: Example, config inputConfig: Configuration = C public extension Collection where Element == String { func violations(config: Configuration = Configuration.default, requiresFileOnDisk: Bool = false) -> [StyleViolation] { - return map { SwiftLintFile.testFile(withContents: $0, persistToDisk: requiresFileOnDisk) } + map { SwiftLintFile.testFile(withContents: $0, persistToDisk: requiresFileOnDisk) } .violations(config: config, requiresFileOnDisk: requiresFileOnDisk) } func corrections(config: Configuration = Configuration.default, requiresFileOnDisk: Bool = false) -> [Correction] { - return map { SwiftLintFile.testFile(withContents: $0, persistToDisk: requiresFileOnDisk) } + map { SwiftLintFile.testFile(withContents: $0, persistToDisk: requiresFileOnDisk) } .corrections(config: config, requiresFileOnDisk: requiresFileOnDisk) } } @@ -123,7 +123,7 @@ public extension Collection where Element: SwiftLintFile { private extension Collection where Element == StyleViolation { func withoutFiles() -> [StyleViolation] { - return map { violation in + map { violation in let locationWithoutFile = Location(file: nil, line: violation.location.line, character: violation.location.character) return violation.with(location: locationWithoutFile) @@ -133,7 +133,7 @@ private extension Collection where Element == StyleViolation { private extension Collection where Element == Correction { func withoutFiles() -> [Correction] { - return map { correction in + map { correction in let locationWithoutFile = Location(file: nil, line: correction.location.line, character: correction.location.character) return Correction(ruleDescription: correction.ruleDescription, location: locationWithoutFile) @@ -146,7 +146,7 @@ public extension Collection where Element == Example { /// /// - returns: A new `Array`. func removingViolationMarkers() -> [Element] { - return map { $0.removingViolationMarkers() } + map { $0.removingViolationMarkers() } } } @@ -260,7 +260,7 @@ private extension Configuration { private extension String { func toStringLiteral() -> String { - return "\"" + replacingOccurrences(of: "\n", with: "\\n") + "\"" + "\"" + replacingOccurrences(of: "\n", with: "\\n") + "\"" } } @@ -307,11 +307,11 @@ private func testCorrection(_ correction: (Example, Example), } private func addEmoji(_ example: Example) -> Example { - return example.with(code: "/* 👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦 */\n\(example.code)") + example.with(code: "/* 👨‍👩‍👧‍👦👨‍👩‍👧‍👦👨‍👩‍👧‍👦 */\n\(example.code)") } private func addShebang(_ example: Example) -> Example { - return example.with(code: "#!/usr/bin/env swift\n\(example.code)") + example.with(code: "#!/usr/bin/env swift\n\(example.code)") } public extension XCTestCase { @@ -372,7 +372,7 @@ public extension XCTestCase { requiresFileOnDisk: ruleDescription.requiresFileOnDisk) } func makeViolations(_ example: Example) -> [StyleViolation] { - return violations(example, config: config, requiresFileOnDisk: ruleDescription.requiresFileOnDisk) + violations(example, config: config, requiresFileOnDisk: ruleDescription.requiresFileOnDisk) } let ruleDescription = ruleDescription.focused() @@ -574,6 +574,6 @@ private struct FocusedRuleDescription { private extension RuleDescription { func focused() -> FocusedRuleDescription { - return FocusedRuleDescription(rule: self) + FocusedRuleDescription(rule: self) } } From c6a7dd2ecde1e9b1d38572751a46b7e9bd3e5e4f Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 10 Jul 2024 13:24:09 +0100 Subject: [PATCH 108/265] Fix implicit return rewriting (#5661) --- CHANGELOG.md | 7 ++++++- .../Style/ImplicitReturnRuleExamples.swift | 19 +++++++++++++++++++ .../SwiftSyntaxCorrectableRule.swift | 13 ++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba52a01c10..e74c5086d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,7 +73,7 @@ `unneeded_synthesized_initializer` rule. [SimplyDanny](https://github.com/SimplyDanny) [#5153](https://github.com/realm/SwiftLint/issues/5153) - + * Make `vertical_whitespace_between_cases` rule work for cases ending with a string literal. [ilendemli](https://github.com/ilendemli) @@ -90,6 +90,11 @@ [Martin Redington](https://github.com/mildm8nnered) [#5606](https://github.com/realm/SwiftLint/issues/5606) +* Fix rewriting for `implicit_return` rule when violations are + nested within each other. + [Martin Redington](https://github.com/mildm8nnered) + [#5660](https://github.com/realm/SwiftLint/issues/5660) + ## 0.55.1: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift index 64c4466ba4..df92fb92da 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRuleExamples.swift @@ -333,6 +333,24 @@ struct ImplicitReturnRuleExamples { ] } + struct MixedExamples { + static let corrections = [ + Example(""" + func foo() -> Int { + ↓return [1, 2].first(where: { + ↓return true + }) + } + """): Example(""" + func foo() -> Int { + [1, 2].first(where: { + true + }) + } + """), + ] + } + static let nonTriggeringExamples = ClosureExamples.nonTriggeringExamples + FunctionExamples.nonTriggeringExamples + @@ -354,6 +372,7 @@ struct ImplicitReturnRuleExamples { GetterExamples.corrections, InitializerExamples.corrections, SubscriptExamples.corrections, + MixedExamples.corrections, ] .reduce(into: [:]) { result, element in result.merge(element) { _, _ in diff --git a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift index 2192ab0665..ea5c8bdf32 100644 --- a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift +++ b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift @@ -1,3 +1,4 @@ +import Foundation import SwiftSyntax /// A SwiftLint CorrectableRule that performs its corrections using a SwiftSyntax `SyntaxRewriter`. @@ -43,14 +44,20 @@ public extension SwiftSyntaxCorrectableRule { if violationCorrections.isEmpty { return [] } + typealias CorrectionRange = (range: NSRange, correction: String) let correctionRanges = violationCorrections .compactMap { correction in file.stringView.NSRange(start: correction.start, end: correction.end).map { range in - (range: range, correction: correction.replacement) + CorrectionRange(range: range, correction: correction.replacement) } } - .filter { file.ruleEnabled(violatingRange: $0.range, for: self) != nil } - .reversed() + .filter { (correctionRange: CorrectionRange) in + file.ruleEnabled(violatingRange: correctionRange.range, for: self) != nil + } + .sorted { (lhs: CorrectionRange, rhs: CorrectionRange) -> Bool in + lhs.range.location > rhs.range.location + } + var corrections = [Correction]() var contents = file.contents for range in correctionRanges { From 21b7e5ed6bf4c6fc8df2106a3788204b858eb8e9 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 10 Jul 2024 18:58:27 +0100 Subject: [PATCH 109/265] Enabled `prefer_self_in_static_references`, and fixed all current violations (#5662) --- .swiftlint.yml | 1 - .../ExtensionAccessModifierRule.swift | 2 +- .../Rules/Idiomatic/SyntacticSugarRule.swift | 2 +- .../Rules/Lint/CaptureVariableRule.swift | 4 ++-- .../Rules/Lint/UnusedDeclarationRule.swift | 6 +++--- .../Extensions/Configuration+RulesMode.swift | 4 ++-- .../Extensions/Dictionary+SwiftLint.swift | 18 +++++++++--------- Source/SwiftLintCore/Models/Baseline.swift | 2 +- Source/SwiftLintCore/Models/Command.swift | 4 ++-- .../SwiftLintCore/Models/Configuration.swift | 4 ++-- ...shableConfigurationRuleWrapperWrapper.swift | 2 +- Source/SwiftLintCore/Models/Issue.swift | 2 +- Source/SwiftLintCore/Models/LinterCache.swift | 2 +- Source/SwiftLintCore/Models/Location.swift | 2 +- .../Models/RuleConfigurationDescription.swift | 8 ++++---- .../SwiftLintCore/Models/RuleDescription.swift | 2 +- .../Models/SeverityConfiguration.swift | 2 +- .../SwiftLintCore/Models/StyleViolation.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- .../Models/ViolationSeverity.swift | 2 +- .../Commands/Common/RulesFilterOptions.swift | 4 ++-- .../Helpers/LintOrAnalyzeArguments.swift | 2 +- .../Helpers/LintableFilesVisitor.swift | 2 +- .../Helpers/SwiftPMCompilationDB.swift | 2 +- 24 files changed, 42 insertions(+), 43 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index b4f528c7cd..77134d490d 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -39,7 +39,6 @@ disabled_rules: - no_magic_numbers - one_declaration_per_file - prefer_nimble - - prefer_self_in_static_references - prefixed_toplevel_constant - required_deinit - sorted_enum_cases diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift index 107190ee69..3fdee1d48e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExtensionAccessModifierRule.swift @@ -176,7 +176,7 @@ private extension ExtensionAccessModifierRule { case implicit case explicit(TokenKind) - static func from(tokenKind: TokenKind?) -> ACL { + static func from(tokenKind: TokenKind?) -> Self { switch tokenKind { case nil: return .implicit diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift index 0f5c7ae179..2ae8d41499 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift @@ -107,7 +107,7 @@ private struct SyntacticSugarRuleViolation { let correction: Correction - var children: [SyntacticSugarRuleViolation] = [] + var children: [Self] = [] } private final class SyntacticSugarRuleVisitor: SyntaxVisitor { diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift index 2ae3409899..11450314bb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift @@ -154,11 +154,11 @@ struct CaptureVariableRule: AnalyzerRule, CollectingRule { var configuration = SeverityConfiguration(.warning) - func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> CaptureVariableRule.FileInfo { + func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> Self.FileInfo { file.declaredVariables(compilerArguments: compilerArguments) } - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: CaptureVariableRule.FileInfo], + func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Self.FileInfo], compilerArguments: [String]) -> [StyleViolation] { file.captureListVariables(compilerArguments: compilerArguments) .filter { capturedVariable in collectedInfo.values.contains { $0.contains(capturedVariable.usr) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index 6b0d3ede37..ef585e169e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -6,7 +6,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { var referenced: Set var declared: Set - fileprivate static var empty: FileUSRs { Self(referenced: [], declared: []) } + fileprivate static var empty: Self { Self(referenced: [], declared: []) } } struct DeclaredUSR: Hashable { @@ -28,7 +28,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { requiresFileOnDisk: true ) - func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> UnusedDeclarationRule.FileUSRs { + func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> Self.FileUSRs { guard compilerArguments.isNotEmpty else { Issue.missingCompilerArguments(path: file.path, ruleID: Self.description.identifier).print() return .empty @@ -54,7 +54,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { ) } - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: UnusedDeclarationRule.FileUSRs], + func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Self.FileUSRs], compilerArguments: [String]) -> [StyleViolation] { let allReferencedUSRs = collectedInfo.values.reduce(into: Set()) { $0.formUnion($1.referenced) } return violationOffsets(declaredUSRs: collectedInfo[file]?.declared ?? [], diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift index 71de532588..2d03e037f8 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift @@ -87,7 +87,7 @@ public extension Configuration { } } - internal func applied(aliasResolver: (String) -> String) -> RulesMode { + internal func applied(aliasResolver: (String) -> String) -> Self { switch self { case let .default(disabled, optIn): return .default( @@ -103,7 +103,7 @@ public extension Configuration { } } - internal func activateCustomRuleIdentifiers(allRulesWrapped: [ConfigurationRuleWrapper]) -> RulesMode { + internal func activateCustomRuleIdentifiers(allRulesWrapped: [ConfigurationRuleWrapper]) -> Self { // In the only mode, if the custom rules rule is enabled, all custom rules are also enabled implicitly // This method makes the implicitly explicit switch self { diff --git a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift index 458761d646..a685b55777 100644 --- a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift @@ -6,7 +6,7 @@ public struct SourceKittenDictionary { /// The underlying SourceKitten dictionary. public let value: [String: any SourceKitRepresentable] /// The cached substructure for this dictionary. Empty if there is no substructure. - public let substructure: [SourceKittenDictionary] + public let substructure: [Self] /// The kind of Swift expression represented by this dictionary, if it is an expression. public let expressionKind: SwiftExpressionKind? @@ -135,26 +135,26 @@ public struct SourceKittenDictionary { } /// The fully preserved SourceKitten dictionaries for all the attributes associated with this dictionary. - public var swiftAttributes: [SourceKittenDictionary] { + public var swiftAttributes: [Self] { let array = value["key.attributes"] as? [any SourceKitRepresentable] ?? [] return array.compactMap { $0 as? [String: any SourceKitRepresentable] } .map(Self.init) } - public var elements: [SourceKittenDictionary] { + public var elements: [Self] { let elements = value["key.elements"] as? [any SourceKitRepresentable] ?? [] return elements.compactMap { $0 as? [String: any SourceKitRepresentable] } .map(Self.init) } - public var entities: [SourceKittenDictionary] { + public var entities: [Self] { let entities = value["key.entities"] as? [any SourceKitRepresentable] ?? [] return entities.compactMap { $0 as? [String: any SourceKitRepresentable] } .map(Self.init) } - public var enclosedVarParameters: [SourceKittenDictionary] { - substructure.flatMap { subDict -> [SourceKittenDictionary] in + public var enclosedVarParameters: [Self] { + substructure.flatMap { subDict -> [Self] in if subDict.declarationKind == .varParameter { return [subDict] } @@ -167,8 +167,8 @@ public struct SourceKittenDictionary { } } - public var enclosedArguments: [SourceKittenDictionary] { - substructure.flatMap { subDict -> [SourceKittenDictionary] in + public var enclosedArguments: [Self] { + substructure.flatMap { subDict -> [Self] in guard subDict.expressionKind == .argument else { return [] } @@ -182,7 +182,7 @@ public struct SourceKittenDictionary { return array.compactMap { ($0 as? [String: String]).flatMap { $0["key.name"] } } } - public var secondarySymbols: [SourceKittenDictionary] { + public var secondarySymbols: [Self] { let array = value["key.secondary_symbols"] as? [any SourceKitRepresentable] ?? [] return array.compactMap { $0 as? [String: any SourceKitRepresentable] } .map(Self.init) diff --git a/Source/SwiftLintCore/Models/Baseline.swift b/Source/SwiftLintCore/Models/Baseline.swift index 0df4326df6..145a15439c 100644 --- a/Source/SwiftLintCore/Models/Baseline.swift +++ b/Source/SwiftLintCore/Models/Baseline.swift @@ -134,7 +134,7 @@ public struct Baseline: Equatable { /// The violations are filtered using the same algorithm as the `filter` method above. /// /// - parameter otherBaseline: The other `Baseline`. - public func compare(_ otherBaseline: Baseline) -> [StyleViolation] { + public func compare(_ otherBaseline: Self) -> [StyleViolation] { otherBaseline.baseline.flatMap { relativePath, otherBaselineViolations -> Set in if let baselineViolations = baseline[relativePath] { return filter(relativePathViolations: otherBaselineViolations, baselineViolations: baselineViolations) diff --git a/Source/SwiftLintCore/Models/Command.swift b/Source/SwiftLintCore/Models/Command.swift index 0a7675a2c4..e485200958 100644 --- a/Source/SwiftLintCore/Models/Command.swift +++ b/Source/SwiftLintCore/Models/Command.swift @@ -13,7 +13,7 @@ public struct Command: Equatable { /// - returns: The inverse action that can cancel out the current action, restoring the SwifttLint engine's /// state prior to the current action. - internal func inverse() -> Action { + internal func inverse() -> Self { switch self { case .enable: return .disable case .disable: return .enable @@ -143,7 +143,7 @@ public struct Command: Equatable { /// If the command doesn't have a modifier, it is returned as-is. /// /// - returns: The expanded commands. - internal func expand() -> [Command] { + internal func expand() -> [Self] { guard let modifier else { return [self] } diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 5e1e910dbb..32ff40e3bc 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -5,7 +5,7 @@ import SourceKittenFramework public struct Configuration { // MARK: - Properties: Static /// The default Configuration resulting from an empty configuration file. - public static var `default`: Configuration { + public static var `default`: Self { // This is realized via a getter to account for differences of the current working directory Self() } @@ -105,7 +105,7 @@ public struct Configuration { /// Creates a Configuration by copying an existing configuration. /// /// - parameter copying: The existing configuration to copy. - internal init(copying configuration: Configuration) { + internal init(copying configuration: Self) { rulesWrapper = configuration.rulesWrapper fileGraph = configuration.fileGraph includedPaths = configuration.includedPaths diff --git a/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift b/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift index b5fabe7467..05ff17312e 100644 --- a/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift +++ b/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift @@ -2,7 +2,7 @@ internal struct HashableConfigurationRuleWrapperWrapper: Hashable { let configurationRuleWrapper: ConfigurationRuleWrapper static func == ( - lhs: HashableConfigurationRuleWrapperWrapper, rhs: HashableConfigurationRuleWrapperWrapper + lhs: Self, rhs: Self ) -> Bool { // Only use identifier for equality check (not taking config into account) type(of: lhs.configurationRuleWrapper.rule).description.identifier diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 0fb24acf0c..bdb9fbfe94 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -100,7 +100,7 @@ public enum Issue: LocalizedError, Equatable { /// /// - returns: A `SwiftLintError.genericWarning` containing the message of the `error` argument. static func wrap(error: some Error) -> Self { - error as? Issue ?? Self.genericWarning(error.localizedDescription) + error as? Self ?? Self.genericWarning(error.localizedDescription) } /// Make this issue an error. diff --git a/Source/SwiftLintCore/Models/LinterCache.swift b/Source/SwiftLintCore/Models/LinterCache.swift index a1d6985ca9..75a4097216 100644 --- a/Source/SwiftLintCore/Models/LinterCache.swift +++ b/Source/SwiftLintCore/Models/LinterCache.swift @@ -13,7 +13,7 @@ private struct FileCacheEntry: Codable { private struct FileCache: Codable { var entries: [String: FileCacheEntry] - static var empty: FileCache { Self(entries: [:]) } + static var empty: Self { Self(entries: [:]) } } /// A persisted cache for storing and retrieving linter results. diff --git a/Source/SwiftLintCore/Models/Location.swift b/Source/SwiftLintCore/Models/Location.swift index 9f9792361b..4bb174207c 100644 --- a/Source/SwiftLintCore/Models/Location.swift +++ b/Source/SwiftLintCore/Models/Location.swift @@ -80,7 +80,7 @@ public struct Location: CustomStringConvertible, Comparable, Codable, Sendable { // MARK: Comparable - public static func < (lhs: Location, rhs: Location) -> Bool { + public static func < (lhs: Self, rhs: Self) -> Bool { if lhs.file != rhs.file { return lhs.file < rhs.file } diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index 11ce3b518b..b903556634 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -53,7 +53,7 @@ public struct RuleConfigurationDescription: Equatable { return Self(options: customDescription.options, exclusiveOptions: exclusiveOptions) } let options: [RuleConfigurationOption] = Mirror(reflecting: configuration).children - .compactMap { child -> RuleConfigurationDescription? in + .compactMap { child -> Self? in // Property wrappers have names prefixed by an underscore. guard let codingKey = child.label, codingKey.starts(with: "_") else { return nil @@ -182,7 +182,7 @@ public enum OptionType: Equatable { /// Special option for a ``ViolationSeverity``. case severity(ViolationSeverity) /// A list of options. - case list([OptionType]) + case list([Self]) /// An option which is another set of configuration options to be nested in the serialized output. case nested(RuleConfigurationDescription) } @@ -438,7 +438,7 @@ public struct ConfigurationElement Bool { + public static func == (lhs: Self, rhs: Self) -> Bool { lhs.wrappedValue == rhs.wrappedValue && lhs.key == rhs.key } } diff --git a/Source/SwiftLintCore/Models/RuleDescription.swift b/Source/SwiftLintCore/Models/RuleDescription.swift index d6276d9a6d..9d94fc37de 100644 --- a/Source/SwiftLintCore/Models/RuleDescription.swift +++ b/Source/SwiftLintCore/Models/RuleDescription.swift @@ -91,7 +91,7 @@ public struct RuleDescription: Equatable, Sendable { // MARK: Equatable - public static func == (lhs: RuleDescription, rhs: RuleDescription) -> Bool { + public static func == (lhs: Self, rhs: Self) -> Bool { lhs.identifier == rhs.identifier } } diff --git a/Source/SwiftLintCore/Models/SeverityConfiguration.swift b/Source/SwiftLintCore/Models/SeverityConfiguration.swift index 3dfea575c9..83336a37e7 100644 --- a/Source/SwiftLintCore/Models/SeverityConfiguration.swift +++ b/Source/SwiftLintCore/Models/SeverityConfiguration.swift @@ -8,7 +8,7 @@ public struct SeverityConfiguration: SeverityBasedRuleConfiguratio @ConfigurationElement(key: "severity") var severity = ViolationSeverity.warning - public var severityConfiguration: SeverityConfiguration { + public var severityConfiguration: Self { self } diff --git a/Source/SwiftLintCore/Models/StyleViolation.swift b/Source/SwiftLintCore/Models/StyleViolation.swift index 7e0739c214..96a0aecabc 100644 --- a/Source/SwiftLintCore/Models/StyleViolation.swift +++ b/Source/SwiftLintCore/Models/StyleViolation.swift @@ -53,7 +53,7 @@ public struct StyleViolation: CustomStringConvertible, Codable, Hashable { /// Returns the same violation, but with the `severity` that is passed in /// - Parameter severity: the new severity to use in the modified violation - public func with(severity: ViolationSeverity) -> StyleViolation { + public func with(severity: ViolationSeverity) -> Self { var new = self new.severity = severity return new @@ -61,7 +61,7 @@ public struct StyleViolation: CustomStringConvertible, Codable, Hashable { /// Returns the same violation, but with the `location` that is passed in /// - Parameter location: the new location to use in the modified violation - public func with(location: Location) -> StyleViolation { + public func with(location: Location) -> Self { var new = self new.location = location return new diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index 3180438493..ed7b6cd984 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -9,7 +9,7 @@ public struct Version: VersionComparable { } /// The current SwiftLint version. - public static let current = Version(value: "0.55.1") + public static let current = Self(value: "0.55.1") /// Public initializer. /// diff --git a/Source/SwiftLintCore/Models/ViolationSeverity.swift b/Source/SwiftLintCore/Models/ViolationSeverity.swift index 9f74e1dd84..deef926ffa 100644 --- a/Source/SwiftLintCore/Models/ViolationSeverity.swift +++ b/Source/SwiftLintCore/Models/ViolationSeverity.swift @@ -8,7 +8,7 @@ public enum ViolationSeverity: String, Comparable, Codable, InlinableOptionType // MARK: Comparable - public static func < (lhs: ViolationSeverity, rhs: ViolationSeverity) -> Bool { + public static func < (lhs: Self, rhs: Self) -> Bool { lhs == .warning && rhs == .error } } diff --git a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift b/Source/swiftlint/Commands/Common/RulesFilterOptions.swift index 5589113aa8..c2bb7188fb 100644 --- a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift +++ b/Source/swiftlint/Commands/Common/RulesFilterOptions.swift @@ -3,11 +3,11 @@ import ArgumentParser enum RuleEnablementOptions: String, EnumerableFlag { case enabled, disabled - static func name(for value: RuleEnablementOptions) -> NameSpecification { + static func name(for value: Self) -> NameSpecification { .shortAndLong } - static func help(for value: RuleEnablementOptions) -> ArgumentHelp? { + static func help(for value: Self) -> ArgumentHelp? { "Only show \(value.rawValue) rules" } } diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift index e1a2e987cc..b04b6c70d8 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -3,7 +3,7 @@ import ArgumentParser enum LeniencyOptions: String, EnumerableFlag { case strict, lenient - static func help(for value: LeniencyOptions) -> ArgumentHelp? { + static func help(for value: Self) -> ArgumentHelp? { switch value { case .strict: return "Upgrades warnings to serious violations (errors)." diff --git a/Source/swiftlint/Helpers/LintableFilesVisitor.swift b/Source/swiftlint/Helpers/LintableFilesVisitor.swift index 284ccaf2d4..30cbd7fca0 100644 --- a/Source/swiftlint/Helpers/LintableFilesVisitor.swift +++ b/Source/swiftlint/Helpers/LintableFilesVisitor.swift @@ -114,7 +114,7 @@ struct LintableFilesVisitor { cache: LinterCache?, allowZeroLintableFiles: Bool, block: @escaping (CollectedLinter) async -> Void) - throws -> LintableFilesVisitor { + throws -> Self { try Signposts.record(name: "LintableFilesVisitor.Create") { let compilerInvocations: CompilerInvocations? if options.mode == .lint { diff --git a/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift b/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift index 6faa7c29be..238985f167 100644 --- a/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift +++ b/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift @@ -28,7 +28,7 @@ struct SwiftPMCompilationDB: Codable { static func parse(yaml: Data) throws -> [File: Arguments] { let decoder = YAMLDecoder() - let compilationDB: SwiftPMCompilationDB + let compilationDB: Self if ProcessInfo.processInfo.environment["TEST_SRCDIR"] != nil { // Running tests From e48bdb7adfd5a62aacfbbea9d33108e0cad805bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 14 Jul 2024 11:31:29 +0200 Subject: [PATCH 110/265] Add new `unused_parameter` rule (#5668) --- .swiftlint.yml | 3 +- CHANGELOG.md | 5 + .../Models/BuiltInRules.swift | 1 + .../Rules/Lint/UnusedParameterRule.swift | 209 ++++++++++++++++++ .../RedundantSelfInClosureRuleExamples.swift | 13 ++ Source/SwiftLintCore/Helpers/Stack.swift | 6 + .../DeclaredIdentifiersTrackingVisitor.swift | 120 ++++++++-- Tests/GeneratedTests/GeneratedTests.swift | 6 + .../default_rule_configurations.yml | 2 + 9 files changed, 346 insertions(+), 19 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 77134d490d..3e71cda9d0 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -48,6 +48,7 @@ disabled_rules: - trailing_closure - type_contents_order - unused_capture_list + - unused_parameter - vertical_whitespace_between_cases # Configurations @@ -62,7 +63,7 @@ balanced_xctest_lifecycle: &unit_test_configuration - XCTestCase closure_body_length: warning: 50 - error: 100 + error: 100 empty_xctest_method: *unit_test_configuration file_name: excluded: diff --git a/CHANGELOG.md b/CHANGELOG.md index e74c5086d4..47adf64674 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,11 @@ [Ueeek](https://github.com/Ueeek) [#5615](https://github.com/realm/SwiftLint/issues/5615) +* Add new `unused_parameter` rule that triggers on function/initializer/subscript + parameters that are not used inside of the function/initializer/subscript. + [SimplyDanny](https://github.com/SimplyDanny) + [#2120](https://github.com/realm/SwiftLint/issues/2120) + * Add modified configurations to examples in rule documentation. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index d30f9779f6..4766e60c8f 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -226,6 +226,7 @@ public let builtInRules: [any Rule.Type] = [ UnusedEnumeratedRule.self, UnusedImportRule.self, UnusedOptionalBindingRule.self, + UnusedParameterRule.self, UnusedSetterValueRule.self, ValidIBInspectableRule.self, VerticalParameterAlignmentOnCallRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift new file mode 100644 index 0000000000..f13b9806a9 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift @@ -0,0 +1,209 @@ +import SwiftLintCore +import SwiftSyntax + +@SwiftSyntaxRule +struct UnusedParameterRule: SwiftSyntaxCorrectableRule, OptInRule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "unused_parameter", + name: "Unused Parameter", + description: """ + Other than unused local variable declarations, unused function/initializer/subscript parameters are not \ + marked by the Swift compiler. Since unused parameters are code smells, they should either be removed \ + or replaced/shadowed by a wildcard '_' to indicate that they are being deliberately disregarded. + """, + kind: .lint, + nonTriggeringExamples: [ + Example(""" + func f(a: Int) { + _ = a + } + """), + Example(""" + func f(case: Int) { + _ = `case` + } + """), + Example(""" + func f(a _: Int) {} + """), + Example(""" + func f(_: Int) {} + """), + Example(""" + func f(a: Int, b c: String) { + func g() { + _ = a + _ = c + } + } + """), + Example(""" + func f(a: Int, c: Int) -> Int { + struct S { + let b = 1 + func f(a: Int, b: Int = 2) -> Int { a + b } + } + return a + c + } + """), + Example(""" + func f(a: Int?) { + if let a {} + } + """), + Example(""" + func f(a: Int) { + let a = a + return a + } + """), + Example(""" + func f(`operator`: Int) -> Int { `operator` } + """), + ], + triggeringExamples: [ + Example(""" + func f(↓a: Int) {} + """), + Example(""" + func f(↓a: Int, b ↓c: String) {} + """), + Example(""" + func f(↓a: Int, b ↓c: String) { + func g(a: Int, ↓b: Double) { + _ = a + } + } + """), + Example(""" + struct S { + let a: Int + + init(a: Int, ↓b: Int) { + func f(↓a: Int, b: Int) -> Int { b } + self.a = f(a: a, b: 0) + } + } + """), + Example(""" + struct S { + subscript(a: Int, ↓b: Int) { + func f(↓a: Int, b: Int) -> Int { b } + return f(a: a, b: 0) + } + } + """), + Example(""" + func f(↓a: Int, ↓b: Int, c: Int) -> Int { + struct S { + let b = 1 + func f(a: Int, ↓c: Int = 2) -> Int { a + b } + } + return S().f(a: c) + } + """), + Example(""" + func f(↓a: Int, c: String) { + let a = 1 + return a + c + } + """), + ], + corrections: [ + Example(""" + func f(a: Int) {} + """): Example(""" + func f(a _: Int) {} + """), + Example(""" + func f(a b: Int) {} + """): Example(""" + func f(a _: Int) {} + """), + Example(""" + func f(_ a: Int) {} + """): Example(""" + func f(_: Int) {} + """), + ] + ) +} + +// MARK: Visitor + +private extension UnusedParameterRule { + final class Visitor: DeclaredIdentifiersTrackingVisitor { + private var referencedDeclarations = Set() + + override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] } + + // MARK: Violation checking + + override func visitPost(_ node: CodeBlockItemListSyntax) { + let declarations = scope.peek() ?? [] + for declaration in declarations.reversed() where !referencedDeclarations.contains(declaration) { + // Violation + guard case let .parameter(name) = declaration else { + continue + } + let violation = ReasonedRuleViolation( + position: name.positionAfterSkippingLeadingTrivia, + reason: "Parameter '\(name.text)' is unused; consider removing or replacing it with '_'", + severity: configuration.severity + ) + violations.append(violation) + + // Correction + guard let previousToken = name.previousToken(viewMode: .sourceAccurate) else { + continue + } + let startPosReplacement = + if previousToken.tokenKind == .wildcard { + (previousToken.positionAfterSkippingLeadingTrivia, "_") + } else if case .identifier = previousToken.tokenKind { + (name.positionAfterSkippingLeadingTrivia, "_") + } else { + (name.positionAfterSkippingLeadingTrivia, name.text + " _") + } + let correction = ViolationCorrection( + start: startPosReplacement.0, + end: name.endPositionBeforeTrailingTrivia, + replacement: startPosReplacement.1 + ) + violationCorrections.append(correction) + } + super.visitPost(node) + } + + // MARK: Reference collection + + override func visitPost(_ node: DeclReferenceExprSyntax) { + if node.keyPathInParent != \MemberAccessExprSyntax.declName { + addReference(node.baseName.text) + } + } + + override func visitPost(_ node: OptionalBindingConditionSyntax) { + if node.initializer == nil, let id = node.pattern.as(IdentifierPatternSyntax.self)?.identifier.text { + addReference(id) + } + } + + // MARK: Private methods + + private func addReference(_ id: String) { + for declarations in scope.reversed() { + if declarations.onlyElement == .lookupBoundary { + return + } + for declaration in declarations.reversed() where declaration.declares(id: id) { + if referencedDeclarations.insert(declaration).inserted { + return + } + } + } + } + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift index 71b14b5384..40b271ef2a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift @@ -80,6 +80,19 @@ struct RedundantSelfInClosureRuleExamples { } } """), + Example(""" + class C { + var a = 0 + init(_ a: Int) { + self.a = a + f { [weak self] in + guard let self else { return } + self.a = 1 + } + } + func f(_: () -> Void) {} + } + """, excludeFromDocumentation: true), ] static let triggeringExamples = [ diff --git a/Source/SwiftLintCore/Helpers/Stack.swift b/Source/SwiftLintCore/Helpers/Stack.swift index d69fb6cdac..794919bf26 100644 --- a/Source/SwiftLintCore/Helpers/Stack.swift +++ b/Source/SwiftLintCore/Helpers/Stack.swift @@ -49,6 +49,12 @@ public struct Stack { } } +extension Stack: Sequence { + public func makeIterator() -> [Element].Iterator { + elements.makeIterator() + } +} + extension Stack: CustomDebugStringConvertible where Element: CustomDebugStringConvertible { public var debugDescription: String { let intermediateElements = count > 1 ? elements[1 ..< count - 1] : [] diff --git a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift index 8c47c1f9bf..7b6f2ff89d 100644 --- a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift +++ b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift @@ -1,10 +1,54 @@ +import Foundation import SwiftSyntax +/// An identifier declaration. +public enum IdentifierDeclaration: Hashable { + /// Parameter declaration with a name token. + case parameter(name: TokenSyntax) + /// Local variable declaration with a name token. + case localVariable(name: TokenSyntax) + /// A variable that is implicitly added by the compiler (e.g. `error` in `catch` clauses). + case implicitVariable(name: String) + /// A variable hidden from scope because its name is a wildcard `_`. + case wildcard + /// Special case that marks a type boundary at which name lookup stops. + case lookupBoundary + + /// The name of the declared identifier (e.g. in `let a = 1` this is `a`). + fileprivate var name: String { + switch self { + case let .parameter(name): name.text + case let .localVariable(name): name.text + case let .implicitVariable(name): name + case .wildcard: "_" + case .lookupBoundary: "" + } + } + + /// Check whether self declares a variable given by name. + /// + /// - Parameters: + /// - id: Name of the variable. + /// - disregardBackticks: If `true`, normalize all names before comparison by removing all backticks. This is the + /// default since backticks only disambiguate, but don't contribute to name resolution. + public func declares(id: String, disregardBackticks: Bool = true) -> Bool { + if self == .wildcard || id == "_" { + // Insignificant names cannot refer to each other. + return false + } + if disregardBackticks { + let backticks = CharacterSet(charactersIn: "`") + return id.trimmingCharacters(in: backticks) == name.trimmingCharacters(in: backticks) + } + return id == name + } +} + /// A specialized `ViolationsSyntaxVisitor` that tracks declared identifiers per scope while traversing the AST. open class DeclaredIdentifiersTrackingVisitor: ViolationsSyntaxVisitor { /// A type that remembers the declared identifiers (in order) up to the current position in the code. - public typealias Scope = Stack> + public typealias Scope = Stack<[IdentifierDeclaration]> /// The hierarchical stack of identifiers declared up to the current position in the code. public var scope: Scope @@ -23,16 +67,18 @@ open class DeclaredIdentifiersTrackingVisitor: /// Indicate whether a given identifier is in scope. /// - /// - parameter identifier: An identifier. + /// - Parameters: + /// - identifier: An identifier. + /// - Returns: `true` if the identifier was declared previously. public func hasSeenDeclaration(for identifier: String) -> Bool { - scope.contains { $0.contains(identifier) } + scope.contains { $0.contains { $0.name == identifier } } } override open func visit(_ node: CodeBlockItemListSyntax) -> SyntaxVisitorContinueKind { + scope.openChildScope() guard let parent = node.parent, !parent.is(SourceFileSyntax.self), let grandParent = parent.parent else { return .visitChildren } - scope.openChildScope() if let ifStmt = grandParent.as(IfExprSyntax.self), parent.keyPathInParent != \IfExprSyntax.elseBody { collectIdentifiers(from: ifStmt.conditions) } else if let whileStmt = grandParent.as(WhileStmtSyntax.self) { @@ -41,6 +87,10 @@ open class DeclaredIdentifiersTrackingVisitor: collectIdentifiers(from: pattern) } else if let parameters = grandParent.as(FunctionDeclSyntax.self)?.signature.parameterClause.parameters { collectIdentifiers(from: parameters) + } else if let parameters = grandParent.as(InitializerDeclSyntax.self)?.signature.parameterClause.parameters { + collectIdentifiers(from: parameters) + } else if let parameters = grandParent.as(SubscriptDeclSyntax.self)?.parameterClause.parameters { + collectIdentifiers(from: parameters) } else if let closureParameters = parent.as(ClosureExprSyntax.self)?.signature?.parameterClause { collectIdentifiers(from: closureParameters) } else if let switchCase = parent.as(SwitchCaseSyntax.self)?.label.as(SwitchCaseLabelSyntax.self) { @@ -67,16 +117,42 @@ open class DeclaredIdentifiersTrackingVisitor: collectIdentifiers(from: node.conditions) } + // MARK: Type declaration boundaries + + override open func visit(_ node: MemberBlockSyntax) -> SyntaxVisitorContinueKind { + if node.belongsToTypeDefinableInFunction { + scope.push([.lookupBoundary]) + } + return .visitChildren + } + + override open func visitPost(_ node: MemberBlockSyntax) { + if node.belongsToTypeDefinableInFunction { + scope.pop() + } + } + + // MARK: Private methods + private func collectIdentifiers(from parameters: FunctionParameterListSyntax) { - parameters.forEach { scope.addToCurrentScope(($0.secondName ?? $0.firstName).text) } + for param in parameters { + let name = param.secondName ?? param.firstName + scope.addToCurrentScope(.parameter(name: name)) + } } private func collectIdentifiers(from closureParameters: ClosureSignatureSyntax.ParameterClause) { switch closureParameters { case let .parameterClause(parameters): - parameters.parameters.forEach { scope.addToCurrentScope(($0.secondName ?? $0.firstName).text) } + for param in parameters.parameters { + let name = param.secondName ?? param.firstName + scope.addToCurrentScope(.parameter(name: name)) + } case let .simpleInput(parameters): - parameters.forEach { scope.addToCurrentScope($0.name.text) } + for param in parameters { + let name = param.name + scope.addToCurrentScope(.parameter(name: name)) + } } } @@ -98,21 +174,20 @@ open class DeclaredIdentifiersTrackingVisitor: .map { patternExpr -> any PatternSyntaxProtocol in patternExpr.pattern.as(ValueBindingPatternSyntax.self)?.pattern ?? patternExpr.pattern } - .compactMap { pattern -> IdentifierPatternSyntax? in - pattern.as(IdentifierPatternSyntax.self) + .forEach { + collectIdentifiers(from: PatternSyntax(fromProtocol: $0)) } - .forEach { scope.addToCurrentScope($0.identifier.text) } } private func collectIdentifiers(from catchClause: CatchClauseSyntax) { let items = catchClause.catchItems - if items.isNotEmpty { + if items.isEmpty { + // A catch clause without explicit catch items has an implicit `error` variable in scope. + scope.addToCurrentScope(.implicitVariable(name: "error")) + } else { items .compactMap { $0.pattern?.as(ValueBindingPatternSyntax.self)?.pattern } .forEach(collectIdentifiers(from:)) - } else { - // A catch clause without explicit catch items has an implicit `error` variable in scope. - scope.addToCurrentScope("error") } } @@ -123,18 +198,27 @@ open class DeclaredIdentifiersTrackingVisitor: } private func collectIdentifiers(from pattern: PatternSyntax) { - if let name = pattern.as(IdentifierPatternSyntax.self)?.identifier.text { - scope.addToCurrentScope(name) + if let id = pattern.as(IdentifierPatternSyntax.self)?.identifier { + scope.addToCurrentScope(.localVariable(name: id)) } } } private extension DeclaredIdentifiersTrackingVisitor.Scope { - mutating func addToCurrentScope(_ identifier: String) { - modifyLast { $0.insert(identifier) } + mutating func addToCurrentScope(_ decl: IdentifierDeclaration) { + modifyLast { $0.append(decl.name == "_" ? .wildcard : decl) } } mutating func openChildScope() { push([]) } } + +private extension MemberBlockSyntax { + var belongsToTypeDefinableInFunction: Bool { + if let parent { + return [.actorDecl, .classDecl, .enumDecl, .structDecl].contains(parent.kind) + } + return false + } +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 3234b3f02b..8eb59eed05 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -1345,6 +1345,12 @@ final class UnusedOptionalBindingRuleGeneratedTests: SwiftLintTestCase { } } +final class UnusedParameterRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(UnusedParameterRule.description) + } +} + final class UnusedSetterValueRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnusedSetterValueRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index c87aa691cb..653b753cf5 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -603,6 +603,8 @@ unused_import: unused_optional_binding: severity: warning ignore_optional_try: false +unused_parameter: + severity: warning unused_setter_value: severity: warning valid_ibinspectable: From 67b1aaa2116e8a052614263e8d55b67781dfeb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 14 Jul 2024 11:38:16 +0200 Subject: [PATCH 111/265] Trigger `missing_docs` rule on declaration-introducing keyword (#5671) --- .../Rules/Lint/MissingDocsRule.swift | 20 +++++++------------ .../Rules/Lint/MissingDocsRuleExamples.swift | 16 +++++++-------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift index 2ae715b229..28b8fb3ce0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift @@ -73,15 +73,13 @@ private extension MissingDocsRule { } let acl = enumAcl ?? .internal if let parameter = configuration.parameters.first(where: { $0.value == acl }) { - node.elements.forEach { - violations.append( - ReasonedRuleViolation( - position: $0.name.positionAfterSkippingLeadingTrivia, - reason: "\(acl) declarations should be documented", - severity: parameter.severity - ) + violations.append( + ReasonedRuleViolation( + position: node.caseKeyword.positionAfterSkippingLeadingTrivia, + reason: "\(acl) declarations should be documented", + severity: parameter.severity ) - } + ) } } @@ -191,7 +189,7 @@ private extension MissingDocsRule { if let parameter = configuration.parameters.first(where: { $0.value == acl }) { violations.append( ReasonedRuleViolation( - position: (node.modifiers.staticOrClass ?? token).positionAfterSkippingLeadingTrivia, + position: token.positionAfterSkippingLeadingTrivia, reason: "\(acl) declarations should be documented", severity: parameter.severity ) @@ -237,10 +235,6 @@ private extension DeclModifierListSyntax { var accessibility: AccessControlLevel? { filter { $0.detail == nil }.compactMap { AccessControlLevel(description: $0.name.text) }.first } - - var staticOrClass: TokenSyntax? { - first { $0.name.text == "static" || $0.name.text == "class" }?.name - } } private enum AccessControlBehavior { diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift index bb35f01ef0..0fd4ada975 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRuleExamples.swift @@ -94,14 +94,14 @@ struct MissingDocsRuleExamples { Example(""" /// a doc public class C { - public ↓static let i = 1 + public static ↓let i = 1 } """), // `excludes_extensions` only excludes the extension declaration itself; not its children. Example(""" public extension A { public ↓func f() {} - ↓static var i: Int { 1 } + static ↓var i: Int { 1 } ↓struct S { func f() {} } @@ -112,7 +112,7 @@ struct MissingDocsRuleExamples { func f() {} } ↓enum E { - case ↓a + ↓case a func f() {} } } @@ -129,7 +129,7 @@ struct MissingDocsRuleExamples { Example(""" extension E { public ↓struct S { - public ↓static let i = 1 + public static ↓let i = 1 } } """), @@ -170,7 +170,7 @@ struct MissingDocsRuleExamples { """), Example(""" public ↓enum E { - case ↓A + ↓case A, B func f() {} init(_ i: Int) { self = .A } } @@ -178,7 +178,7 @@ struct MissingDocsRuleExamples { Example(""" open ↓class C { public ↓enum E { - case ↓A + ↓case A func f() {} init(_ i: Int) { self = .A } } @@ -190,7 +190,7 @@ struct MissingDocsRuleExamples { public struct S {} public extension S { ↓enum E { - case ↓A + ↓case A } } """), @@ -199,7 +199,7 @@ struct MissingDocsRuleExamples { fileprivate enum E { static let source = "" } - ↓static var a: Int { 1 } + static ↓var a: Int { 1 } } """, excludeFromDocumentation: true), Example(""" From cc4b569c5491b33963f3e0f435e7722f9311b77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 14 Jul 2024 17:20:50 +0200 Subject: [PATCH 112/265] Enable `unused_parameter` rule and fix all violations (#5673) --- .swiftlint.yml | 1 - .../Idiomatic/DuplicateImportsRule.swift | 2 +- .../Rules/Idiomatic/ExplicitACLRule.swift | 14 ++++---- .../Idiomatic/ExplicitTopLevelACLRule.swift | 4 +-- .../Idiomatic/NoGroupingExtensionRule.swift | 10 +++--- .../RedundantOptionalInitializationRule.swift | 2 +- .../Idiomatic/StaticOverFinalClassRule.swift | 2 +- .../Idiomatic/UnavailableFunctionRule.swift | 6 ++-- .../UnneededSynthesizedInitializerRule.swift | 2 +- .../Idiomatic/UnusedEnumeratedRule.swift | 2 +- .../Rules/Lint/CommentSpacingRule.swift | 2 +- ...cardedNotificationCenterObserverRule.swift | 12 +++---- .../Rules/Lint/MissingDocsRule.swift | 16 ++++----- .../NotificationCenterDetachmentRule.swift | 2 +- .../Rules/Lint/PeriodSpacingRule.swift | 2 +- .../PrivateSwiftUIStatePropertyRule.swift | 6 ++-- .../Rules/Lint/RequiredDeinitRule.swift | 2 +- .../Lint/TestCaseAccessibilityRule.swift | 2 +- .../Lint/UnhandledThrowingTaskRule.swift | 2 +- .../Rules/Lint/UnusedDeclarationRule.swift | 2 +- .../Metrics/CyclomaticComplexityRule.swift | 20 +++++------ .../Rules/Metrics/NestingRule.swift | 14 ++++---- .../UnusedImportConfiguration.swift | 2 +- .../Rules/Style/ColonRule.swift | 2 +- .../Rules/Style/CommaInheritanceRule.swift | 2 +- .../Rules/Style/InclusiveLanguageRule.swift | 2 +- .../Rules/Style/ModifierOrderRule.swift | 2 +- .../NonOverridableClassDeclarationRule.swift | 2 +- .../PreferSelfInStaticReferencesRule.swift | 36 +++++++++---------- .../Style/PrefixedTopLevelConstantRule.swift | 4 +-- .../Style/RedundantSelfInClosureRule.swift | 20 +++++------ .../Rules/Style/ShorthandArgumentRule.swift | 2 +- .../Rules/Style/TrailingClosureRule.swift | 2 +- .../NSRegularExpression+SwiftLint.swift | 2 +- Source/SwiftLintCore/Models/Linter.swift | 2 -- .../Models/RuleConfigurationDescription.swift | 6 ++-- Source/SwiftLintCore/Models/RuleStorage.swift | 4 +-- .../Protocols/CollectingRule.swift | 26 +++++++------- Source/SwiftLintCore/Protocols/Rule.swift | 14 ++++---- .../SwiftSyntaxCorrectableRule.swift | 2 +- .../Rules/SuperfluousDisableCommandRule.swift | 2 +- .../DeclaredIdentifiersTrackingVisitor.swift | 2 +- .../RuleConfigurationMacros.swift | 6 ++-- .../SwiftLintCoreMacros/SwiftSyntaxRule.swift | 4 +-- .../Commands/Common/RulesFilterOptions.swift | 2 +- .../Helpers/LintableFilesVisitor.swift | 2 +- Tests/CLITests/RulesFilterTests.swift | 14 ++++---- .../CollectingRuleTests.swift | 12 +++---- .../ConfigurationTests+Mock.swift | 4 +-- .../ConfigurationTests+MultipleConfigs.swift | 2 +- .../ConfigurationTests.swift | 4 +-- .../LinterCacheTests.swift | 4 +-- .../RuleConfigurationDescriptionTests.swift | 6 ++-- Tests/SwiftLintFrameworkTests/RuleTests.swift | 12 +++---- 54 files changed, 166 insertions(+), 169 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 3e71cda9d0..f2adc863b1 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -48,7 +48,6 @@ disabled_rules: - trailing_closure - type_contents_order - unused_capture_list - - unused_parameter - vertical_whitespace_between_cases # Configurations diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift index 87a41dfee2..190e8e0b6d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift @@ -31,7 +31,7 @@ struct DuplicateImportsRule: SwiftSyntaxCorrectableRule { } } - func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor { + func makeVisitor(file _: SwiftLintFile) -> ViolationsSyntaxVisitor { queuedFatalError("Unreachable: `validate(file:)` will be used instead") } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift index fa2891d567..0cf148a8fc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitACLRule.swift @@ -131,7 +131,7 @@ private extension ExplicitACLRule { return node.modifiers.containsPrivateOrFileprivate() ? .skipChildren : .visitChildren } - override func visitPost(_ node: ActorDeclSyntax) { + override func visitPost(_: ActorDeclSyntax) { declScope.pop() } @@ -141,15 +141,15 @@ private extension ExplicitACLRule { return node.modifiers.containsPrivateOrFileprivate() ? .skipChildren : .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { declScope.pop() } - override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } - override func visit(_ node: CodeBlockSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: CodeBlockSyntax) -> SyntaxVisitorContinueKind { .skipChildren } @@ -158,7 +158,7 @@ private extension ExplicitACLRule { return node.modifiers.containsPrivateOrFileprivate() ? .skipChildren : .visitChildren } - override func visitPost(_ node: ExtensionDeclSyntax) { + override func visitPost(_: ExtensionDeclSyntax) { declScope.pop() } @@ -168,7 +168,7 @@ private extension ExplicitACLRule { return node.modifiers.containsPrivateOrFileprivate() ? .skipChildren : .visitChildren } - override func visitPost(_ node: EnumDeclSyntax) { + override func visitPost(_: EnumDeclSyntax) { declScope.pop() } @@ -190,7 +190,7 @@ private extension ExplicitACLRule { return node.modifiers.containsPrivateOrFileprivate() ? .skipChildren : .visitChildren } - override func visitPost(_ node: StructDeclSyntax) { + override func visitPost(_: StructDeclSyntax) { declScope.pop() } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift index e5295b3e96..a1f5a64487 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift @@ -66,11 +66,11 @@ private extension ExplicitTopLevelACLRule { collectViolations(decl: node, token: node.bindingSpecifier) } - override func visit(_ node: CodeBlockSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: CodeBlockSyntax) -> SyntaxVisitorContinueKind { .skipChildren } - override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift index 78665318cb..60c5ebcdcb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoGroupingExtensionRule.swift @@ -64,7 +64,7 @@ private extension NoGroupingExtensionRule { return .visitChildren } - override func visitPost(_ node: ActorDeclSyntax) { + override func visitPost(_: ActorDeclSyntax) { typeScope.removeLast() } @@ -73,7 +73,7 @@ private extension NoGroupingExtensionRule { return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { typeScope.removeLast() } @@ -82,7 +82,7 @@ private extension NoGroupingExtensionRule { return .visitChildren } - override func visitPost(_ node: EnumDeclSyntax) { + override func visitPost(_: EnumDeclSyntax) { typeScope.removeLast() } @@ -91,7 +91,7 @@ private extension NoGroupingExtensionRule { return .visitChildren } - override func visitPost(_ node: StructDeclSyntax) { + override func visitPost(_: StructDeclSyntax) { typeScope.removeLast() } @@ -110,7 +110,7 @@ private extension NoGroupingExtensionRule { return .visitChildren } - override func visitPost(_ node: ExtensionDeclSyntax) { + override func visitPost(_: ExtensionDeclSyntax) { typeScope.removeLast() } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift index a936b35c53..6937a51dc8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantOptionalInitializationRule.swift @@ -119,7 +119,7 @@ private extension RedundantOptionalInitializationRule { } final class Rewriter: ViolationsSyntaxRewriter { - override func visitAny(_ node: Syntax) -> Syntax? { nil } + override func visitAny(_: Syntax) -> Syntax? { nil } override func visit(_ node: VariableDeclSyntax) -> DeclSyntax { guard node.bindingSpecifier.tokenKind == .keyword(.var), diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift index c054fc1c66..b0cf8be5f1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/StaticOverFinalClassRule.swift @@ -86,7 +86,7 @@ private extension StaticOverFinalClassRule { return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { classContexts.pop() } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift index 2e41d94d3c..ca5959a666 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnavailableFunctionRule.swift @@ -157,15 +157,15 @@ private extension CodeBlockSyntax? { private final class ReturnFinderVisitor: SyntaxVisitor { private(set) var containsReturn = false - override func visitPost(_ node: ReturnStmtSyntax) { + override func visitPost(_: ReturnStmtSyntax) { containsReturn = true } - override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } - override func visit(_ node: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: FunctionCallExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift index eb5e9b657a..d64e30da22 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift @@ -49,7 +49,7 @@ private extension UnneededSynthesizedInitializerRule { final class Rewriter: ViolationsSyntaxRewriter { private var unneededInitializers: [InitializerDeclSyntax] = [] - override func visitAny(_ node: Syntax) -> Syntax? { nil } + override func visitAny(_: Syntax) -> Syntax? { nil } override func visit(_ node: StructDeclSyntax) -> DeclSyntax { unneededInitializers = node.unneededInitializers.filter { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift index f125473ce4..da2c628ba9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnusedEnumeratedRule.swift @@ -175,7 +175,7 @@ private extension UnusedEnumeratedRule { return .visitChildren } - override func visitPost(_ node: ClosureExprSyntax) { + override func visitPost(_: ClosureExprSyntax) { if let closure = closures.pop(), (closure.zeroPosition != nil) != (closure.onePosition != nil) { addViolation( zeroPosition: closure.onePosition, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift index 6a6ab516f2..5b5f549bfe 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift @@ -158,7 +158,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { } } - func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { + func substitution(for violationRange: NSRange, in _: SwiftLintFile) -> (NSRange, String)? { (violationRange, " ") } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift index 2b7d0a6d82..97bcde86ad 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift @@ -105,12 +105,12 @@ private extension DiscardedNotificationCenterObserverRule { final class Visitor: ViolationsSyntaxVisitor { var scopes = Stack() - override func visit(_ node: SourceFileSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: SourceFileSyntax) -> SyntaxVisitorContinueKind { scopes.push(.file) return .visitChildren } - override func visitPost(_ node: SourceFileSyntax) { + override func visitPost(_: SourceFileSyntax) { scopes.pop() } @@ -119,7 +119,7 @@ private extension DiscardedNotificationCenterObserverRule { return .visitChildren } - override func visitPost(_ node: FunctionDeclSyntax) { + override func visitPost(_: FunctionDeclSyntax) { scopes.pop() } @@ -130,7 +130,7 @@ private extension DiscardedNotificationCenterObserverRule { return .visitChildren } - override func visitPost(_ node: AccessorBlockSyntax) { + override func visitPost(_: AccessorBlockSyntax) { scopes.pop() } @@ -143,7 +143,7 @@ private extension DiscardedNotificationCenterObserverRule { return .visitChildren } - override func visitPost(_ node: AccessorDeclSyntax) { + override func visitPost(_: AccessorDeclSyntax) { scopes.pop() } @@ -152,7 +152,7 @@ private extension DiscardedNotificationCenterObserverRule { return .visitChildren } - override func visitPost(_ node: ClosureExprSyntax) { + override func visitPost(_: ClosureExprSyntax) { scopes.pop() } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift index 28b8fb3ce0..ed0cd61822 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/MissingDocsRule.swift @@ -33,7 +33,7 @@ private extension MissingDocsRule { return .visitChildren } - override func visitPost(_ node: ActorDeclSyntax) { + override func visitPost(_: ActorDeclSyntax) { aclScope.pop() } @@ -55,15 +55,15 @@ private extension MissingDocsRule { return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { aclScope.pop() } - override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } - override func visit(_ node: CodeBlockSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: CodeBlockSyntax) -> SyntaxVisitorContinueKind { .skipChildren } @@ -97,7 +97,7 @@ private extension MissingDocsRule { return .visitChildren } - override func visitPost(_ node: EnumDeclSyntax) { + override func visitPost(_: EnumDeclSyntax) { aclScope.pop() } @@ -112,7 +112,7 @@ private extension MissingDocsRule { return .visitChildren } - override func visitPost(_ node: ExtensionDeclSyntax) { + override func visitPost(_: ExtensionDeclSyntax) { aclScope.pop() } @@ -142,7 +142,7 @@ private extension MissingDocsRule { return .visitChildren } - override func visitPost(_ node: ProtocolDeclSyntax) { + override func visitPost(_: ProtocolDeclSyntax) { aclScope.pop() } @@ -160,7 +160,7 @@ private extension MissingDocsRule { return .visitChildren } - override func visitPost(_ node: StructDeclSyntax) { + override func visitPost(_: StructDeclSyntax) { aclScope.pop() } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRule.swift index dea3e74c33..9849ba9b5d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NotificationCenterDetachmentRule.swift @@ -28,7 +28,7 @@ private extension NotificationCenterDetachmentRule { violations.append(node.positionAfterSkippingLeadingTrivia) } - override func visit(_ node: DeinitializerDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: DeinitializerDeclSyntax) -> SyntaxVisitorContinueKind { .skipChildren } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift index 80263d702e..249d67c53e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PeriodSpacingRule.swift @@ -86,7 +86,7 @@ struct PeriodSpacingRule: SourceKitFreeRule, OptInRule, SubstitutionCorrectableR } } - func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { + func substitution(for violationRange: NSRange, in _: SwiftLintFile) -> (NSRange, String)? { (violationRange, "") } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift index 2bba7313a4..a9cc469784 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/PrivateSwiftUIStatePropertyRule.swift @@ -41,7 +41,7 @@ private extension PrivateSwiftUIStatePropertyRule { return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { swiftUITypeScopes.pop() } @@ -50,7 +50,7 @@ private extension PrivateSwiftUIStatePropertyRule { return .visitChildren } - override func visitPost(_ node: StructDeclSyntax) { + override func visitPost(_: StructDeclSyntax) { swiftUITypeScopes.pop() } @@ -59,7 +59,7 @@ private extension PrivateSwiftUIStatePropertyRule { return .visitChildren } - override func visitPost(_ node: ActorDeclSyntax) { + override func visitPost(_: ActorDeclSyntax) { swiftUITypeScopes.pop() } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift index 06d827dad6..5308a04d39 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/RequiredDeinitRule.swift @@ -83,7 +83,7 @@ private extension RequiredDeinitRule { override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all } - override func visitPost(_ node: DeinitializerDeclSyntax) { + override func visitPost(_: DeinitializerDeclSyntax) { hasDeinit = true } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRule.swift index fc2963960c..f68829834d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TestCaseAccessibilityRule.swift @@ -23,7 +23,7 @@ struct TestCaseAccessibilityRule: OptInRule, SubstitutionCorrectableRule { } } - func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { + func substitution(for violationRange: NSRange, in _: SwiftLintFile) -> (NSRange, String)? { (violationRange, "private ") } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift index bc9c7f6894..a0cf64a5b0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnhandledThrowingTaskRule.swift @@ -308,7 +308,7 @@ private final class ThrowsVisitor: SyntaxVisitor { } } - override func visitPost(_ node: ThrowStmtSyntax) { + override func visitPost(_: ThrowStmtSyntax) { doesThrow = true } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index ef585e169e..fe9fd6f6fb 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -55,7 +55,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Self.FileUSRs], - compilerArguments: [String]) -> [StyleViolation] { + compilerArguments _: [String]) -> [StyleViolation] { let allReferencedUSRs = collectedInfo.values.reduce(into: Set()) { $0.formUnion($1.referenced) } return violationOffsets(declaredUSRs: collectedInfo[file]?.declared ?? [], allReferencedUSRs: allReferencedUSRs) diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift index 73295f80d8..7768b05b39 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/CyclomaticComplexityRule.swift @@ -121,48 +121,48 @@ private extension CyclomaticComplexityRule { super.init(viewMode: .sourceAccurate) } - override func visitPost(_ node: ForStmtSyntax) { + override func visitPost(_: ForStmtSyntax) { complexity += 1 } - override func visitPost(_ node: IfExprSyntax) { + override func visitPost(_: IfExprSyntax) { complexity += 1 } - override func visitPost(_ node: GuardStmtSyntax) { + override func visitPost(_: GuardStmtSyntax) { complexity += 1 } - override func visitPost(_ node: RepeatStmtSyntax) { + override func visitPost(_: RepeatStmtSyntax) { complexity += 1 } - override func visitPost(_ node: WhileStmtSyntax) { + override func visitPost(_: WhileStmtSyntax) { complexity += 1 } - override func visitPost(_ node: CatchClauseSyntax) { + override func visitPost(_: CatchClauseSyntax) { complexity += 1 } - override func visitPost(_ node: SwitchCaseSyntax) { + override func visitPost(_: SwitchCaseSyntax) { if !ignoresCaseStatements { complexity += 1 } } - override func visitPost(_ node: FallThroughStmtSyntax) { + override func visitPost(_: FallThroughStmtSyntax) { // Switch complexity is reduced by `fallthrough` cases if !ignoresCaseStatements { complexity -= 1 } } - override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { .skipChildren } - override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { .skipChildren } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift index 2e9b95662e..7eb1af8163 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRule.swift @@ -50,7 +50,7 @@ private extension NestingRule { return .visitChildren } - override func visitPost(_ node: ActorDeclSyntax) { + override func visitPost(_: ActorDeclSyntax) { levels.pop() } @@ -59,7 +59,7 @@ private extension NestingRule { return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { levels.pop() } @@ -68,7 +68,7 @@ private extension NestingRule { return .visitChildren } - override func visitPost(_ node: EnumDeclSyntax) { + override func visitPost(_: EnumDeclSyntax) { levels.pop() } @@ -77,7 +77,7 @@ private extension NestingRule { return .visitChildren } - override func visitPost(_ node: ExtensionDeclSyntax) { + override func visitPost(_: ExtensionDeclSyntax) { levels.pop() } @@ -86,7 +86,7 @@ private extension NestingRule { return .visitChildren } - override func visitPost(_ node: FunctionDeclSyntax) { + override func visitPost(_: FunctionDeclSyntax) { levels.pop() } @@ -95,7 +95,7 @@ private extension NestingRule { return .visitChildren } - override func visitPost(_ node: ProtocolDeclSyntax) { + override func visitPost(_: ProtocolDeclSyntax) { levels.pop() } @@ -104,7 +104,7 @@ private extension NestingRule { return .visitChildren } - override func visitPost(_ node: StructDeclSyntax) { + override func visitPost(_: StructDeclSyntax) { levels.pop() } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift index 5e9f2eec69..eaa8571e19 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift @@ -8,7 +8,7 @@ struct TransitiveModuleConfiguration: Equatable, AcceptableByConfi /// The set of modules that can be transitively imported by `importedModule`. let transitivelyImportedModules: [String] - init(fromAny configuration: Any, context ruleID: String) throws { + init(fromAny configuration: Any, context _: String) throws { guard let configurationDict = configuration as? [String: Any], Set(configurationDict.keys) == ["module", "allowed_transitive_imports"], let importedModule = configurationDict["module"] as? String, diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ColonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ColonRule.swift index 3d382b6e2e..aaf84fe061 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ColonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ColonRule.swift @@ -84,7 +84,7 @@ struct ColonRule: SubstitutionCorrectableRule, SourceKitFreeRule { } } - func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { + func substitution(for violationRange: NSRange, in _: SwiftLintFile) -> (NSRange, String)? { (violationRange, ": ") } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift index 35e4d094ab..30af47edc1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/CommaInheritanceRule.swift @@ -70,7 +70,7 @@ struct CommaInheritanceRule: OptInRule, SubstitutionCorrectableRule, // MARK: - SubstitutionCorrectableRule - func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? { + func substitution(for violationRange: NSRange, in _: SwiftLintFile) -> (NSRange, String)? { (violationRange, ", ") } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRule.swift index e817d48d4b..28dc3a7fc8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/InclusiveLanguageRule.swift @@ -101,7 +101,7 @@ private extension InclusiveLanguageRule { } } - override func visit(_ node: StringLiteralExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: StringLiteralExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift index 729ab435f3..cf88b1aaa5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift @@ -14,7 +14,7 @@ struct ModifierOrderRule: ASTRule, OptInRule, CorrectableRule { ) func validate(file: SwiftLintFile, - kind: SwiftDeclarationKind, + kind _: SwiftDeclarationKind, dictionary: SourceKittenDictionary) -> [StyleViolation] { guard let offset = dictionary.offset else { return [] diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift index 0bdfa09821..31355fa784 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift @@ -108,7 +108,7 @@ private extension NonOverridableClassDeclarationRule { return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { _ = finalClassScope.pop() } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift index 8823caddba..0bae82b4bd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift @@ -44,11 +44,11 @@ private extension PreferSelfInStaticReferencesRule { return .skipChildren } - override func visitPost(_ node: ActorDeclSyntax) { + override func visitPost(_: ActorDeclSyntax) { parentDeclScopes.pop() } - override func visit(_ node: AttributeSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: AttributeSyntax) -> SyntaxVisitorContinueKind { if case .skipReferences = variableDeclScopes.peek() { return .skipChildren } @@ -60,16 +60,16 @@ private extension PreferSelfInStaticReferencesRule { return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { parentDeclScopes.pop() } - override func visit(_ node: CodeBlockItemListSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: CodeBlockItemListSyntax) -> SyntaxVisitorContinueKind { variableDeclScopes.push(.handleReferences) return .visitChildren } - override func visitPost(_ node: CodeBlockItemListSyntax) { + override func visitPost(_: CodeBlockItemListSyntax) { variableDeclScopes.pop() } @@ -78,16 +78,16 @@ private extension PreferSelfInStaticReferencesRule { return .visitChildren } - override func visitPost(_ node: EnumDeclSyntax) { + override func visitPost(_: EnumDeclSyntax) { parentDeclScopes.pop() } - override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { parentDeclScopes.push(.skipReferences) return .visitChildren } - override func visitPost(_ node: ExtensionDeclSyntax) { + override func visitPost(_: ExtensionDeclSyntax) { parentDeclScopes.pop() } @@ -111,14 +111,14 @@ private extension PreferSelfInStaticReferencesRule { addViolation(on: node.baseName) } - override func visit(_ node: InitializerClauseSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: InitializerClauseSyntax) -> SyntaxVisitorContinueKind { if case .skipReferences = variableDeclScopes.peek() { return .skipChildren } return .visitChildren } - override func visit(_ node: MemberBlockSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: MemberBlockSyntax) -> SyntaxVisitorContinueKind { if case .likeClass = parentDeclScopes.peek() { variableDeclScopes.push(.skipReferences) } else { @@ -127,7 +127,7 @@ private extension PreferSelfInStaticReferencesRule { return .visitChildren } - override func visitPost(_ node: MemberBlockSyntax) { + override func visitPost(_: MemberBlockSyntax) { variableDeclScopes.pop() } @@ -138,23 +138,23 @@ private extension PreferSelfInStaticReferencesRule { return .skipChildren } - override func visit(_ node: FunctionParameterClauseSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: FunctionParameterClauseSyntax) -> SyntaxVisitorContinueKind { if case .likeStruct = parentDeclScopes.peek() { return .visitChildren } return .skipChildren } - override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { parentDeclScopes.push(.skipReferences) return .skipChildren } - override func visitPost(_ node: ProtocolDeclSyntax) { + override func visitPost(_: ProtocolDeclSyntax) { parentDeclScopes.pop() } - override func visit(_ node: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ReturnClauseSyntax) -> SyntaxVisitorContinueKind { if case .likeStruct = parentDeclScopes.peek() { return .visitChildren } @@ -166,11 +166,11 @@ private extension PreferSelfInStaticReferencesRule { return .visitChildren } - override func visitPost(_ node: StructDeclSyntax) { + override func visitPost(_: StructDeclSyntax) { parentDeclScopes.pop() } - override func visit(_ node: GenericArgumentListSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: GenericArgumentListSyntax) -> SyntaxVisitorContinueKind { if case .likeClass = parentDeclScopes.peek() { return .skipChildren } @@ -191,7 +191,7 @@ private extension PreferSelfInStaticReferencesRule { } } - override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { if case .likeClass = parentDeclScopes.peek() { return .skipChildren } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift index 4dda360e68..74e10f47f1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/PrefixedTopLevelConstantRule.swift @@ -106,11 +106,11 @@ private extension PrefixedTopLevelConstantRule { } } - override func visit(_ node: CodeBlockSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: CodeBlockSyntax) -> SyntaxVisitorContinueKind { .skipChildren } - override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift index 78f7db239b..f4ec12f337 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift @@ -39,21 +39,21 @@ private extension RedundantSelfInClosureRule { override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] } - override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ActorDeclSyntax) -> SyntaxVisitorContinueKind { typeDeclarations.push(.likeClass) return .visitChildren } - override func visitPost(_ node: ActorDeclSyntax) { + override func visitPost(_: ActorDeclSyntax) { typeDeclarations.pop() } - override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClassDeclSyntax) -> SyntaxVisitorContinueKind { typeDeclarations.push(.likeClass) return .visitChildren } - override func visitPost(_ node: ClassDeclSyntax) { + override func visitPost(_: ClassDeclSyntax) { typeDeclarations.pop() } @@ -85,12 +85,12 @@ private extension RedundantSelfInClosureRule { selfCaptures.pop() } - override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: EnumDeclSyntax) -> SyntaxVisitorContinueKind { typeDeclarations.push(.likeStruct) return .visitChildren } - override func visitPost(_ node: EnumDeclSyntax) { + override func visitPost(_: EnumDeclSyntax) { typeDeclarations.pop() } @@ -103,16 +103,16 @@ private extension RedundantSelfInClosureRule { return .visitChildren } - override func visitPost(_ node: FunctionCallExprSyntax) { + override func visitPost(_: FunctionCallExprSyntax) { functionCalls.pop() } - override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: StructDeclSyntax) -> SyntaxVisitorContinueKind { typeDeclarations.push(.likeStruct) return .visitChildren } - override func visitPost(_ node: StructDeclSyntax) { + override func visitPost(_: StructDeclSyntax) { typeDeclarations.pop() } } @@ -147,7 +147,7 @@ private class ExplicitSelfVisitor: DeclaredIde } } - override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { // Will be handled separately by the parent visitor. .skipChildren } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift index 144de8f757..5783bd6013 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift @@ -145,7 +145,7 @@ private final class ShorthandArgumentCollector: SyntaxVisitor { } } - override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { .skipChildren } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift index b124dae2ce..99d462a613 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift @@ -119,7 +119,7 @@ private extension TrailingClosureRule { } } - override func visit(_ node: ConditionElementListSyntax) -> SyntaxVisitorContinueKind { + override func visit(_: ConditionElementListSyntax) -> SyntaxVisitorContinueKind { .skipChildren } diff --git a/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift b/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift index 95a39018fc..cd06e8b0b8 100644 --- a/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift @@ -7,7 +7,7 @@ private let regexCacheLock = NSLock() public struct RegularExpression: Hashable, Comparable, ExpressibleByStringLiteral { public let regex: NSRegularExpression - public init(pattern: String, options: NSRegularExpression.Options? = nil) throws { + public init(pattern: String, options _: NSRegularExpression.Options? = nil) throws { regex = try .cached(pattern: pattern) } public init(stringLiteral value: String) { diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index eab0fe1ce3..00f3a21277 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -59,7 +59,6 @@ private extension Rule { // swiftlint:disable:next function_parameter_count func lint(file: SwiftLintFile, regions: [Region], benchmark: Bool, storage: RuleStorage, - configuration: Configuration, superfluousDisableCommandRule: SuperfluousDisableCommandRule?, compilerArguments: [String]) -> LintResult? { // We shouldn't lint if the current Swift version is not supported by the rule @@ -235,7 +234,6 @@ public struct CollectedLinter { let validationResults = rules.parallelCompactMap { $0.lint(file: file, regions: regions, benchmark: benchmark, storage: storage, - configuration: configuration, superfluousDisableCommandRule: superfluousDisableCommandRule, compilerArguments: compilerArguments) } diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index b903556634..b793f94188 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -405,7 +405,7 @@ public protocol InlinableOptionType: AcceptableByConfigurationElement {} /// levels: warning: 1 /// error: 2 /// ``` -/// 3. As mentioned in the beginning, the implict key inference meachnism can be overruled by specifying a `key` as in: +/// 3. As mentioned in the beginning, the implicit key inference mechanism can be overruled by specifying a `key` as in: /// ```swift /// @ConfigurationElement(key: "foo") /// var levels = SeverityLevelsConfiguration(warning: 1, error: 2) @@ -657,13 +657,13 @@ public extension AcceptableByConfigurationElement where Self: RuleConfiguration return RuleConfigurationDescription(options: [key => asOption()]) } - mutating func apply(_ value: Any?, ruleID: String) throws { + mutating func apply(_ value: Any?, ruleID _: String) throws { if let value { try apply(configuration: value) } } - init(fromAny value: Any, context ruleID: String) throws { + init(fromAny _: Any, context _: String) throws { throw Issue.genericError("Do not call this initializer") } } diff --git a/Source/SwiftLintCore/Models/RuleStorage.swift b/Source/SwiftLintCore/Models/RuleStorage.swift index cf78980da9..ad9aa5f974 100644 --- a/Source/SwiftLintCore/Models/RuleStorage.swift +++ b/Source/SwiftLintCore/Models/RuleStorage.swift @@ -19,7 +19,7 @@ public class RuleStorage: CustomStringConvertible { /// - parameter info: The file information to store. /// - parameter file: The file for which this information pertains to. /// - parameter rule: The SwiftLint rule that generated this info. - func collect(info: R.FileInfo, for file: SwiftLintFile, in rule: R) { + func collect(info: R.FileInfo, for file: SwiftLintFile, in _: R) { let key = ObjectIdentifier(R.self) access.sync(flags: .barrier) { storage[key, default: [:]][file] = info @@ -31,7 +31,7 @@ public class RuleStorage: CustomStringConvertible { /// - parameter rule: The rule whose collected information should be retrieved. /// /// - returns: All file information for a given rule that was collected via `collect(...)`. - func collectedInfo(for rule: R) -> [SwiftLintFile: R.FileInfo]? { + func collectedInfo(for _: R) -> [SwiftLintFile: R.FileInfo]? { access.sync { storage[ObjectIdentifier(R.self)] as? [SwiftLintFile: R.FileInfo] } diff --git a/Source/SwiftLintCore/Protocols/CollectingRule.swift b/Source/SwiftLintCore/Protocols/CollectingRule.swift index 619b96c28b..1d6ae737fb 100644 --- a/Source/SwiftLintCore/Protocols/CollectingRule.swift +++ b/Source/SwiftLintCore/Protocols/CollectingRule.swift @@ -53,33 +53,33 @@ public extension CollectingRule { } return validate(file: file, collectedInfo: info, compilerArguments: compilerArguments) } - func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> FileInfo { + func collectInfo(for file: SwiftLintFile, compilerArguments _: [String]) -> FileInfo { collectInfo(for: file) } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], - compilerArguments: [String]) -> [StyleViolation] { + compilerArguments _: [String]) -> [StyleViolation] { validate(file: file, collectedInfo: collectedInfo) } - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { queuedFatalError("Must call `validate(file:collectedInfo:)` for CollectingRule") } - func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] { + func validate(file _: SwiftLintFile, compilerArguments _: [String]) -> [StyleViolation] { queuedFatalError("Must call `validate(file:collectedInfo:compilerArguments:)` for CollectingRule") } } public extension CollectingRule where Self: AnalyzerRule { - func collectInfo(for file: SwiftLintFile) -> FileInfo { + func collectInfo(for _: SwiftLintFile) -> FileInfo { queuedFatalError( "Must call `collect(infoFor:compilerArguments:)` for AnalyzerRule & CollectingRule" ) } - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { queuedFatalError( "Must call `validate(file:collectedInfo:compilerArguments:)` for AnalyzerRule & CollectingRule" ) } - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo]) -> [StyleViolation] { + func validate(file _: SwiftLintFile, collectedInfo _: [SwiftLintFile: FileInfo]) -> [StyleViolation] { queuedFatalError( "Must call `validate(file:collectedInfo:compilerArguments:)` for AnalyzerRule & CollectingRule" ) @@ -115,7 +115,7 @@ package protocol CollectingCorrectableRule: CollectingRule, CorrectableRule { package extension CollectingCorrectableRule { func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], - compilerArguments: [String]) -> [Correction] { + compilerArguments _: [String]) -> [Correction] { correct(file: file, collectedInfo: collectedInfo) } @@ -126,23 +126,23 @@ package extension CollectingCorrectableRule { return correct(file: file, collectedInfo: info, compilerArguments: compilerArguments) } - func correct(file: SwiftLintFile) -> [Correction] { + func correct(file _: SwiftLintFile) -> [Correction] { queuedFatalError("Must call `correct(file:collectedInfo:)` for AnalyzerRule") } - func correct(file: SwiftLintFile, compilerArguments: [String]) -> [Correction] { + func correct(file _: SwiftLintFile, compilerArguments _: [String]) -> [Correction] { queuedFatalError("Must call `correct(file:collectedInfo:compilerArguments:)` for AnalyzerRule") } } package extension CollectingCorrectableRule where Self: AnalyzerRule { - func correct(file: SwiftLintFile) -> [Correction] { + func correct(file _: SwiftLintFile) -> [Correction] { queuedFatalError("Must call `correct(file:collectedInfo:compilerArguments:)` for AnalyzerRule") } - func correct(file: SwiftLintFile, compilerArguments: [String]) -> [Correction] { + func correct(file _: SwiftLintFile, compilerArguments _: [String]) -> [Correction] { queuedFatalError("Must call `correct(file:collectedInfo:compilerArguments:)` for AnalyzerRule") } - func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo]) -> [Correction] { + func correct(file _: SwiftLintFile, collectedInfo _: [SwiftLintFile: FileInfo]) -> [Correction] { queuedFatalError("Must call `correct(file:collectedInfo:compilerArguments:)` for AnalyzerRule") } } diff --git a/Source/SwiftLintCore/Protocols/Rule.swift b/Source/SwiftLintCore/Protocols/Rule.swift index 85d97b794f..685e1ef859 100644 --- a/Source/SwiftLintCore/Protocols/Rule.swift +++ b/Source/SwiftLintCore/Protocols/Rule.swift @@ -82,12 +82,12 @@ public extension Rule { try self.configuration.apply(configuration: configuration) } - func validate(file: SwiftLintFile, using storage: RuleStorage, + func validate(file: SwiftLintFile, using _: RuleStorage, compilerArguments: [String]) -> [StyleViolation] { validate(file: file, compilerArguments: compilerArguments) } - func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] { + func validate(file: SwiftLintFile, compilerArguments _: [String]) -> [StyleViolation] { validate(file: file) } @@ -98,7 +98,7 @@ public extension Rule { return false } - func collectInfo(for file: SwiftLintFile, into storage: RuleStorage, compilerArguments: [String]) { + func collectInfo(for _: SwiftLintFile, into _: RuleStorage, compilerArguments _: [String]) { // no-op: only CollectingRules mutate their storage } @@ -152,10 +152,10 @@ public protocol CorrectableRule: Rule { } public extension CorrectableRule { - func correct(file: SwiftLintFile, compilerArguments: [String]) -> [Correction] { + func correct(file: SwiftLintFile, compilerArguments _: [String]) -> [Correction] { correct(file: file) } - func correct(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [Correction] { + func correct(file: SwiftLintFile, using _: RuleStorage, compilerArguments: [String]) -> [Correction] { correct(file: file, compilerArguments: compilerArguments) } } @@ -209,14 +209,14 @@ public protocol SourceKitFreeRule: Rule {} public protocol AnalyzerRule: OptInRule {} public extension AnalyzerRule { - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { queuedFatalError("Must call `validate(file:compilerArguments:)` for AnalyzerRule") } } /// :nodoc: public extension AnalyzerRule where Self: CorrectableRule { - func correct(file: SwiftLintFile) -> [Correction] { + func correct(file _: SwiftLintFile) -> [Correction] { queuedFatalError("Must call `correct(file:compilerArguments:)` for AnalyzerRule") } } diff --git a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift index ea5c8bdf32..2ae76d303d 100644 --- a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift +++ b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift @@ -13,7 +13,7 @@ public protocol SwiftSyntaxCorrectableRule: SwiftSyntaxRule, CorrectableRule { } public extension SwiftSyntaxCorrectableRule { - func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { + func makeRewriter(file _: SwiftLintFile) -> ViolationsSyntaxRewriter? { nil } diff --git a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift index a46bc638dc..0551575d87 100644 --- a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift +++ b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift @@ -29,7 +29,7 @@ package struct SuperfluousDisableCommandRule: SourceKitFreeRule { ] ) - package func validate(file: SwiftLintFile) -> [StyleViolation] { + package func validate(file _: SwiftLintFile) -> [StyleViolation] { // This rule is implemented in Linter.swift [] } diff --git a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift index 7b6f2ff89d..76b8938809 100644 --- a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift +++ b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift @@ -101,7 +101,7 @@ open class DeclaredIdentifiersTrackingVisitor: return .visitChildren } - override open func visitPost(_ node: CodeBlockItemListSyntax) { + override open func visitPost(_: CodeBlockItemListSyntax) { scope.pop() } diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index 09b0263dcb..c505caad51 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -6,7 +6,7 @@ import SwiftSyntaxMacros enum AutoApply: MemberMacro { // swiftlint:disable:next function_body_length static func expansion( - of node: AttributeSyntax, + of _: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { @@ -90,10 +90,10 @@ enum AutoApply: MemberMacro { enum MakeAcceptableByConfigurationElement: ExtensionMacro { static func expansion( - of node: AttributeSyntax, + of _: AttributeSyntax, attachedTo declaration: some DeclGroupSyntax, providingExtensionsOf type: some TypeSyntaxProtocol, - conformingTo protocols: [TypeSyntax], + conformingTo _: [TypeSyntax], in context: some MacroExpansionContext ) throws -> [ExtensionDeclSyntax] { guard let enumDecl = declaration.as(EnumDeclSyntax.self) else { diff --git a/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift b/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift index aed202e684..454ff194a2 100644 --- a/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift +++ b/Source/SwiftLintCoreMacros/SwiftSyntaxRule.swift @@ -5,9 +5,9 @@ import SwiftSyntaxMacros enum SwiftSyntaxRule: ExtensionMacro { static func expansion( of node: AttributeSyntax, - attachedTo declaration: some DeclGroupSyntax, + attachedTo _: some DeclGroupSyntax, providingExtensionsOf type: some TypeSyntaxProtocol, - conformingTo protocols: [TypeSyntax], + conformingTo _: [TypeSyntax], in context: some MacroExpansionContext ) throws -> [ExtensionDeclSyntax] { [ diff --git a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift b/Source/swiftlint/Commands/Common/RulesFilterOptions.swift index c2bb7188fb..e4bfe4fb47 100644 --- a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift +++ b/Source/swiftlint/Commands/Common/RulesFilterOptions.swift @@ -3,7 +3,7 @@ import ArgumentParser enum RuleEnablementOptions: String, EnumerableFlag { case enabled, disabled - static func name(for value: Self) -> NameSpecification { + static func name(for _: Self) -> NameSpecification { .shortAndLong } diff --git a/Source/swiftlint/Helpers/LintableFilesVisitor.swift b/Source/swiftlint/Helpers/LintableFilesVisitor.swift index 30cbd7fca0..a9dd7d3ace 100644 --- a/Source/swiftlint/Helpers/LintableFilesVisitor.swift +++ b/Source/swiftlint/Helpers/LintableFilesVisitor.swift @@ -15,7 +15,7 @@ class CompilerInvocations { } /// Default implementation - func arguments(forFile path: String?) -> Arguments { [] } + func arguments(forFile _: String?) -> Arguments { [] } // MARK: - Private diff --git a/Tests/CLITests/RulesFilterTests.swift b/Tests/CLITests/RulesFilterTests.swift index b9c42efa96..e3546c0810 100644 --- a/Tests/CLITests/RulesFilterTests.swift +++ b/Tests/CLITests/RulesFilterTests.swift @@ -138,9 +138,9 @@ private struct RuleMock1: Rule { description: "", kind: .style) init() { /* conformance for test */ } - init(configuration: Any) throws { self.init() } + init(configuration _: Any) throws { self.init() } - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } } @@ -153,9 +153,9 @@ private struct RuleMock2: Rule { description: "", kind: .style) init() { /* conformance for test */ } - init(configuration: Any) throws { self.init() } + init(configuration _: Any) throws { self.init() } - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } } @@ -168,13 +168,13 @@ private struct CorrectableRuleMock: CorrectableRule { description: "", kind: .style) init() { /* conformance for test */ } - init(configuration: Any) throws { self.init() } + init(configuration _: Any) throws { self.init() } - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } - func correct(file: SwiftLintFile) -> [Correction] { + func correct(file _: SwiftLintFile) -> [Correction] { [] } } diff --git a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift index bef00d1fe6..83ab869e2f 100644 --- a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift @@ -7,7 +7,7 @@ final class CollectingRuleTests: SwiftLintTestCase { struct Spec: MockCollectingRule { var configuration = SeverityConfiguration(.warning) - func collectInfo(for file: SwiftLintFile) -> Int { + func collectInfo(for _: SwiftLintFile) -> Int { 42 } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Int]) -> [StyleViolation] { @@ -53,7 +53,7 @@ final class CollectingRuleTests: SwiftLintTestCase { struct Spec: MockCollectingRule, AnalyzerRule { var configuration = SeverityConfiguration(.warning) - func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> [String] { + func collectInfo(for _: SwiftLintFile, compilerArguments: [String]) -> [String] { compilerArguments } func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: [String]], compilerArguments: [String]) @@ -107,11 +107,11 @@ final class CollectingRuleTests: SwiftLintTestCase { struct AnalyzerSpec: MockCollectingRule, AnalyzerRule, CollectingCorrectableRule { var configuration = SeverityConfiguration(.warning) - func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> String { + func collectInfo(for file: SwiftLintFile, compilerArguments _: [String]) -> String { file.contents } - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String], compilerArguments: [String]) + func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String], compilerArguments _: [String]) -> [StyleViolation] { if collectedInfo[file] == "baz" { return [ @@ -125,7 +125,7 @@ final class CollectingRuleTests: SwiftLintTestCase { } func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String], - compilerArguments: [String]) -> [Correction] { + compilerArguments _: [String]) -> [Correction] { collectedInfo[file] == "baz" ? [Correction(ruleDescription: Spec.description, location: Location(file: file, byteOffset: 2))] : [] @@ -149,5 +149,5 @@ extension MockCollectingRule { Configuration(rulesMode: .only([description.identifier]), ruleList: RuleList(rules: self)) } - init(configuration: Any) throws { self.init() } + init(configuration _: Any) throws { self.init() } } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift index 3bb99e7cee..5b530a3d13 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+Mock.swift @@ -91,7 +91,7 @@ struct RuleMock: Rule { description: "", kind: .style) init() { /* conformance for test */ } - init(configuration: Any) throws { self.init() } + init(configuration _: Any) throws { self.init() } - func validate(file: SwiftLintFile) -> [StyleViolation] { [] } + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index 50711a1e9f..4351b19786 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -5,7 +5,7 @@ import XCTest // swiftlint:disable file_length private extension Configuration { - func contains(rule: T.Type) -> Bool { + func contains(rule _: T.Type) -> Bool { rules.contains { $0 is T } } } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 4ac7254023..8cfdf77cc2 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -234,7 +234,7 @@ final class ConfigurationTests: SwiftLintTestCase { } private class TestFileManager: LintableFileManager { - func filesToLint(inPath path: String, rootDirectory: String? = nil) -> [String] { + func filesToLint(inPath path: String, rootDirectory _: String? = nil) -> [String] { var filesToLint: [String] = [] switch path { case "directory": filesToLint = [ @@ -250,7 +250,7 @@ final class ConfigurationTests: SwiftLintTestCase { return filesToLint.absolutePathsStandardized() } - func modificationDate(forFileAtPath path: String) -> Date? { + func modificationDate(forFileAtPath _: String) -> Date? { nil } diff --git a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift index 3bdb252d14..311e145e36 100644 --- a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift +++ b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift @@ -53,7 +53,7 @@ private struct CacheTestHelper { } private class TestFileManager: LintableFileManager { - fileprivate func filesToLint(inPath: String, rootDirectory: String? = nil) -> [String] { + fileprivate func filesToLint(inPath _: String, rootDirectory _: String? = nil) -> [String] { [] } @@ -63,7 +63,7 @@ private class TestFileManager: LintableFileManager { stubbedModificationDateByPath[path] } - fileprivate func isFile(atPath path: String) -> Bool { + fileprivate func isFile(atPath _: String) -> Bool { false } } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index 99678587e4..6419d39950 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -40,7 +40,7 @@ final class RuleConfigurationDescriptionTests: XCTestCase { @ConfigurationElement(key: "levels") var nestedSeverityLevels = SeverityLevelsConfiguration(warning: 3, error: 2) - func isEqualTo(_ ruleConfiguration: some RuleConfiguration) -> Bool { false } + func isEqualTo(_: some RuleConfiguration) -> Bool { false } } // swiftlint:disable:next function_body_length @@ -221,9 +221,9 @@ final class RuleConfigurationDescriptionTests: XCTestCase { @ConfigurationElement(key: "invisible") var invisible = true - mutating func apply(configuration: Any) throws { /* conformance for test */ } + mutating func apply(configuration _: Any) throws { /* conformance for test */ } - func isEqualTo(_ ruleConfiguration: some RuleConfiguration) -> Bool { false } + func isEqualTo(_: some RuleConfiguration) -> Bool { false } } let description = RuleConfigurationDescription.from(configuration: Config()) diff --git a/Tests/SwiftLintFrameworkTests/RuleTests.swift b/Tests/SwiftLintFrameworkTests/RuleTests.swift index a87dca6e0b..a6b0182936 100644 --- a/Tests/SwiftLintFrameworkTests/RuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleTests.swift @@ -16,7 +16,7 @@ struct RuleWithLevelsMock: Rule { try self.configuration.apply(configuration: configuration) } - func validate(file: SwiftLintFile) -> [StyleViolation] { [] } + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } } final class RuleTests: SwiftLintTestCase { @@ -27,9 +27,9 @@ final class RuleTests: SwiftLintTestCase { description: "", kind: .style) init() { /* conformance for test */ } - init(configuration: Any) throws { self.init() } + init(configuration _: Any) throws { self.init() } - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } } @@ -41,9 +41,9 @@ final class RuleTests: SwiftLintTestCase { description: "", kind: .style) init() { /* conformance for test */ } - init(configuration: Any) throws { self.init() } + init(configuration _: Any) throws { self.init() } - func validate(file: SwiftLintFile) -> [StyleViolation] { + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } } @@ -61,7 +61,7 @@ final class RuleTests: SwiftLintTestCase { try self.configuration.apply(configuration: configuration) } - func validate(file: SwiftLintFile) -> [StyleViolation] { [] } + func validate(file _: SwiftLintFile) -> [StyleViolation] { [] } } func testRuleIsEqualTo() { From b1234e38a54291ba1a15849fef3f69abb23712e1 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Mon, 15 Jul 2024 23:52:52 +0100 Subject: [PATCH 113/265] Add `--only-rule` command line option (#5666) --- CHANGELOG.md | 7 +++++++ .../Extensions/Configuration+FileGraph.swift | 5 +++++ .../Extensions/Configuration+Parsing.swift | 16 ++++++++++------ .../Extensions/Configuration+RulesMode.swift | 3 +++ Source/SwiftLintCore/Models/Configuration.swift | 2 ++ Source/swiftlint/Commands/Analyze.swift | 3 +++ Source/swiftlint/Commands/Lint.swift | 3 +++ .../Extensions/Configuration+CommandLine.swift | 1 + .../swiftlint/Helpers/LintOrAnalyzeCommand.swift | 1 + .../ConfigurationTests.swift | 10 ++++++++++ 10 files changed, 45 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47adf64674..d11a491ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,13 @@ [Ian Leitch](https://github.com/ileitch) [#5613](https://github.com/realm/SwiftLint/issues/5613) +* Add new `--only-rule` command line option for the `lint` and `analyze`, + subcommands that overrides configuration file rule enablement and + disablement, in particular to facilitate running `--fix` for single rules + without having to temporarily edit the configuration file. + [Martin Redington](https://github.com/mildm8nnered) + [#5666](https://github.com/realm/SwiftLint/issues/5666) + #### Bug Fixes * Fix a few false positives and negatives by updating the parser to support diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift index 0b125a3068..4c151e8ab3 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift @@ -41,6 +41,7 @@ package extension Configuration { // MARK: - Methods internal mutating func resultingConfiguration( enableAllRules: Bool, + onlyRule: String?, cachePath: String? ) throws -> Configuration { // Build if needed @@ -51,6 +52,7 @@ package extension Configuration { return try merged( configurationData: try validate(), enableAllRules: enableAllRules, + onlyRule: onlyRule, cachePath: cachePath ) } @@ -248,6 +250,7 @@ package extension Configuration { private func merged( configurationData: [(configurationDict: [String: Any], rootDirectory: String)], enableAllRules: Bool, + onlyRule: String?, cachePath: String? ) throws -> Configuration { // Split into first & remainder; use empty dict for first if the array is empty @@ -258,6 +261,7 @@ package extension Configuration { var firstConfiguration = try Configuration( dict: firstConfigurationData.configurationDict, enableAllRules: enableAllRules, + onlyRule: onlyRule, cachePath: cachePath ) @@ -276,6 +280,7 @@ package extension Configuration { parentConfiguration: $0, dict: $1.configurationDict, enableAllRules: enableAllRules, + onlyRule: onlyRule, cachePath: cachePath ) childConfiguration.fileGraph = Self(rootDirectory: $1.rootDirectory) diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 9f6b91acb5..7c0ed67331 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -42,6 +42,7 @@ extension Configuration { dict: [String: Any], ruleList: RuleList = RuleRegistry.shared.list, enableAllRules: Bool = false, + onlyRule: String? = nil, cachePath: String? = nil ) throws { func defaultStringArray(_ object: Any?) -> [String] { [String].array(of: object) ?? [] } @@ -73,18 +74,21 @@ extension Configuration { let rulesMode = try RulesMode( enableAllRules: enableAllRules, + onlyRule: onlyRule, onlyRules: onlyRules, optInRules: optInRules, disabledRules: disabledRules, analyzerRules: analyzerRules ) - Self.validateConfiguredRulesAreEnabled( - parentConfiguration: parentConfiguration, - configurationDictionary: dict, - ruleList: ruleList, - rulesMode: rulesMode - ) + if onlyRule == nil { + Self.validateConfiguredRulesAreEnabled( + parentConfiguration: parentConfiguration, + configurationDictionary: dict, + ruleList: ruleList, + rulesMode: rulesMode + ) + } self.init( rulesMode: rulesMode, diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift index 2d03e037f8..f7d0e6b7ad 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift @@ -31,6 +31,7 @@ public extension Configuration { internal init( enableAllRules: Bool, + onlyRule: String?, onlyRules: [String], optInRules: [String], disabledRules: [String], @@ -48,6 +49,8 @@ public extension Configuration { if enableAllRules { self = .allEnabled + } else if let onlyRule { + self = .only(Set([onlyRule])) } else if onlyRules.isNotEmpty { if disabledRules.isNotEmpty || optInRules.isNotEmpty { throw Issue.genericWarning( diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 32ff40e3bc..35a86abfe5 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -210,6 +210,7 @@ public struct Configuration { public init( configurationFiles: [String], // No default value here to avoid ambiguous Configuration() initializer enableAllRules: Bool = false, + onlyRule: String? = nil, cachePath: String? = nil, ignoreParentAndChildConfigs: Bool = false, mockedNetworkResults: [String: String] = [:], @@ -247,6 +248,7 @@ public struct Configuration { ) let resultingConfiguration = try fileGraph.resultingConfiguration( enableAllRules: enableAllRules, + onlyRule: onlyRule, cachePath: cachePath ) diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index 6b5e70e794..1a9b254bce 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -13,6 +13,8 @@ extension SwiftLint { var compilerLogPath: String? @Option(help: "The path of a compilation database to use when running AnalyzerRules.") var compileCommands: String? + @Option(help: "Run only the specified rule, ignoring `only_rules`, `opt_in_rules` and `disabled_rules`.") + var onlyRule: String? @Argument(help: pathsArgumentDescription(for: .analyze)) var paths = [String]() @@ -40,6 +42,7 @@ extension SwiftLint { cachePath: nil, ignoreCache: true, enableAllRules: false, + onlyRule: onlyRule, autocorrect: common.fix, format: common.format, compilerLogPath: compilerLogPath, diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index fc6e392ca1..b0e5cdd1ad 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -19,6 +19,8 @@ extension SwiftLint { var noCache = false @Flag(help: "Run all rules, even opt-in and disabled ones, ignoring `only_rules`.") var enableAllRules = false + @Option(help: "Run only the specified rule, ignoring `only_rules`, `opt_in_rules` and `disabled_rules`.") + var onlyRule: String? @Argument(help: pathsArgumentDescription(for: .lint)) var paths = [String]() @@ -52,6 +54,7 @@ extension SwiftLint { cachePath: cachePath, ignoreCache: noCache, enableAllRules: enableAllRules, + onlyRule: onlyRule, autocorrect: common.fix, format: common.format, compilerLogPath: nil, diff --git a/Source/swiftlint/Extensions/Configuration+CommandLine.swift b/Source/swiftlint/Extensions/Configuration+CommandLine.swift index 886abae41c..c1dc248e82 100644 --- a/Source/swiftlint/Extensions/Configuration+CommandLine.swift +++ b/Source/swiftlint/Extensions/Configuration+CommandLine.swift @@ -266,6 +266,7 @@ extension Configuration { self.init( configurationFiles: options.configurationFiles, enableAllRules: options.enableAllRules, + onlyRule: options.onlyRule, cachePath: options.cachePath ) } diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift index 26bbe9e0ed..af94107f54 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -281,6 +281,7 @@ struct LintOrAnalyzeOptions { let cachePath: String? let ignoreCache: Bool let enableAllRules: Bool + let onlyRule: String? let autocorrect: Bool let format: Bool let compilerLogPath: String? diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 8cfdf77cc2..27d67e8561 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -87,6 +87,16 @@ final class ConfigurationTests: SwiftLintTestCase { XCTAssertEqual(configuration.rules.count, RuleRegistry.shared.list.list.count) } + func testOnlyRule() throws { + let configuration = try Configuration( + dict: [:], + onlyRule: "nesting", + cachePath: nil + ) + + XCTAssertEqual(configuration.rules.count, 1) + } + func testOnlyRules() throws { let only = ["nesting", "todo"] From e54f9394fc3410e30ac823eb3139217fa44938ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 16 Jul 2024 19:56:49 +0200 Subject: [PATCH 114/265] Support Swift version 5.10.1 (#5676) --- Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift index 33f3a71c0d..179849adaa 100644 --- a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift +++ b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift @@ -5,6 +5,8 @@ final class SwiftVersionTests: SwiftLintTestCase { func testDetectSwiftVersion() { #if compiler(>=6.0.0) let version = "6.0.0" +#elseif compiler(>=5.10.1) + let version = "5.10.1" #elseif compiler(>=5.10.0) let version = "5.10.0" #elseif compiler(>=5.9.2) From 2442e10f13ae74946c7dc36056ac613490979b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 16 Jul 2024 19:57:05 +0200 Subject: [PATCH 115/265] Avoid needless indentation in examples (#5675) --- .../ShorthandOptionalBindingRule.swift | 42 +++--- .../Rules/Lint/ArrayInitRule.swift | 8 +- .../Rules/Lint/DuplicateConditionsRule.swift | 122 ++++++++-------- ...DuplicatedKeyInDictionaryLiteralRule.swift | 18 +-- .../Rules/Lint/TypesafeArrayInitRule.swift | 12 +- .../Lint/UnownedVariableCaptureRule.swift | 8 +- .../Rules/Metrics/NestingRuleExamples.swift | 82 +++++------ .../Rules/Style/DirectReturnRule.swift | 108 +++++++------- .../Rules/Style/EmptyEnumArgumentsRule.swift | 24 ++-- .../Rules/Style/LetVarWhitespaceRule.swift | 66 ++++----- .../Style/MultilineLiteralBracketsRule.swift | 6 +- .../OperatorUsageWhitespaceRuleExamples.swift | 32 ++--- ...erSelfInStaticReferencesRuleExamples.swift | 106 +++++++------- .../RedundantSelfInClosureRuleExamples.swift | 64 ++++----- .../Rules/Style/ShorthandArgumentRule.swift | 18 +-- .../Rules/Style/SuperfluousElseRule.swift | 132 +++++++++--------- .../Style/TypeContentsOrderRuleExamples.swift | 48 +++---- .../VerticalWhitespaceBetweenCasesRule.swift | 132 +++++++++--------- 18 files changed, 514 insertions(+), 514 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift index 5daf74cbba..98a1187298 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ShorthandOptionalBindingRule.swift @@ -19,12 +19,12 @@ struct ShorthandOptionalBindingRule: OptInRule { if let i = i as? Foo {} guard let `self` = self else {} while var i { i = nil } - """), + """), Example(""" if let i, var i = a, j > 0 {} - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -33,49 +33,49 @@ struct ShorthandOptionalBindingRule: OptInRule { if ↓var `self` = `self` {} if i > 0, ↓let j = j {} if ↓let i = i, ↓var j = j {} - """), + """), Example(""" if ↓let i = i, ↓var j = j, j > 0 {} - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" guard ↓let i = i else {} guard ↓let self = self else {} guard ↓var `self` = `self` else {} guard i > 0, ↓let j = j else {} guard ↓let i = i, ↓var j = j else {} - """), + """), Example(""" while ↓var i = i { i = nil } - """), + """), ], corrections: [ Example(""" if ↓let i = i {} - """): Example(""" - if let i {} - """), + """): Example(""" + if let i {} + """), Example(""" if ↓let self = self {} - """): Example(""" - if let self {} - """), + """): Example(""" + if let self {} + """), Example(""" if ↓var `self` = `self` {} - """): Example(""" - if var `self` {} - """), + """): Example(""" + if var `self` {} + """), Example(""" guard ↓let i = i, ↓var j = j , ↓let k =k else {} - """): Example(""" - guard let i, var j , let k else {} - """), + """): Example(""" + guard let i, var j , let k else {} + """), Example(""" while j > 0, ↓var i = i { i = nil } - """): Example(""" - while j > 0, var i { i = nil } - """), + """): Example(""" + while j > 0, var i { i = nil } + """), ], deprecatedAliases: ["if_let_shadowing"] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift index 2b0e0ef2d3..088c3a878b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift @@ -29,22 +29,22 @@ struct ArrayInitRule: OptInRule { foo.↓map { elem in elem } - """), + """), Example(""" foo.↓map { elem in return elem } - """), + """), Example(""" foo.↓map { (elem: String) in elem } - """), + """), Example(""" foo.↓map { elem -> String in elem } - """), + """), Example("foo.↓map { $0 /* a comment */ }"), Example("foo.↓map { /* a comment */ $0 }"), ] diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift index 8c3f10974a..b947c024f3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift @@ -12,147 +12,147 @@ struct DuplicateConditionsRule: Rule { nonTriggeringExamples: [ Example(""" if x < 5 { - foo() + foo() } else if y == "s" { - bar() + bar() } - """), + """), Example(""" if x < 5 { - foo() + foo() } if x < 5 { - bar() + bar() } - """), + """), Example(""" if x < 5, y == "s" { - foo() + foo() } else if x < 5 { - bar() + bar() } - """), + """), Example(""" switch x { case \"a\": - foo() - bar() + foo() + bar() } - """), + """), Example(""" switch x { case \"a\" where y == "s": - foo() + foo() case \"a\" where y == "t": - bar() + bar() } - """), + """), Example(""" if let x = maybeAbc { - foo() + foo() } else if let x = maybePqr { - bar() + bar() } - """), + """), Example(""" if let x = maybeAbc, let z = x.maybeY { - foo() + foo() } else if let x = maybePqr, let z = x.maybeY { - bar() + bar() } - """), + """), Example(""" if case .p = x { - foo() + foo() } else if case .q = x { - bar() + bar() } - """), + """), Example(""" if true { - if true { foo() } + if true { foo() } } - """), + """), ], triggeringExamples: [ Example(""" if ↓x < 5 { - foo() + foo() } else if y == "s" { - bar() + bar() } else if ↓x < 5 { - baz() + baz() } - """), + """), Example(""" if z { - if ↓x < 5 { - foo() - } else if y == "s" { - bar() - } else if ↓x < 5 { - baz() - } + if ↓x < 5 { + foo() + } else if y == "s" { + bar() + } else if ↓x < 5 { + baz() + } } - """), + """), Example(""" if ↓x < 5, y == "s" { - foo() + foo() } else if x < 10 { - bar() + bar() } else if ↓y == "s", x < 5 { - baz() + baz() } - """), + """), Example(""" switch x { case ↓\"a\", \"b\": - foo() + foo() case \"c\", ↓\"a\": - bar() + bar() } - """), + """), Example(""" switch x { case ↓\"a\" where y == "s": - foo() + foo() case ↓\"a\" where y == "s": - bar() + bar() } - """), + """), Example(""" if ↓let xyz = maybeXyz { - foo() + foo() } else if ↓let xyz = maybeXyz { - bar() + bar() } - """), + """), Example(""" if ↓let x = maybeAbc, let z = x.maybeY { - foo() + foo() } else if ↓let x = maybeAbc, let z = x.maybeY { - bar() + bar() } - """), + """), Example(""" if ↓#available(macOS 10.15, *) { - foo() + foo() } else if ↓#available(macOS 10.15, *) { - bar() + bar() } - """), + """), Example(""" if ↓case .p = x { - foo() + foo() } else if ↓case .p = x { - bar() + bar() } - """), + """), Example(""" if ↓x < 5 {} else if ↓x < 5 {} else if ↓x < 5 {} - """), + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift index 3307ac36cf..d44220f214 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicatedKeyInDictionaryLiteralRule.swift @@ -15,31 +15,31 @@ struct DuplicatedKeyInDictionaryLiteralRule: Rule { 1: "1", 2: "2" ] - """), + """), Example(""" [ "1": 1, "2": 2 ] - """), + """), Example(""" [ foo: "1", bar: "2" ] - """), + """), Example(""" [ UUID(): "1", UUID(): "2" ] - """), + """), Example(""" [ #line: "1", #line: "2" ] - """), + """), ], triggeringExamples: [ Example(""" @@ -48,14 +48,14 @@ struct DuplicatedKeyInDictionaryLiteralRule: Rule { 2: "2", ↓1: "one" ] - """), + """), Example(""" [ "1": 1, "2": 2, ↓"2": 2 ] - """), + """), Example(""" [ foo: "1", @@ -64,7 +64,7 @@ struct DuplicatedKeyInDictionaryLiteralRule: Rule { ↓foo: "4", zaz: "5" ] - """), + """), Example(""" [ .one: "1", @@ -74,7 +74,7 @@ struct DuplicatedKeyInDictionaryLiteralRule: Rule { .four: "4", .five: "5" ] - """), + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift index 7e977c51c5..129cbd66cc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift @@ -14,7 +14,7 @@ struct TypesafeArrayInitRule: AnalyzerRule { enum MyError: Error {} let myResult: Result = .success("") let result: Result = myResult.map { $0 } - """), + """), Example(""" struct IntArray { let elements = [1, 2, 3] @@ -24,28 +24,28 @@ struct TypesafeArrayInitRule: AnalyzerRule { } let ints = IntArray() let intsCopy = ints.map { $0 } - """), + """), ], triggeringExamples: [ Example(""" func f(s: Seq) -> [Seq.Element] { s.↓map({ $0 }) } - """), + """), Example(""" func f(array: [Int]) -> [Int] { array.↓map { $0 } } - """), + """), Example(""" let myInts = [1, 2, 3].↓map { return $0 } - """), + """), Example(""" struct Generator: Sequence, IteratorProtocol { func next() -> Int? { nil } } let array = Generator().↓map { i in i } - """), + """), ], requiresFileOnDisk: true ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift index 062bb87935..a5af1c0b5c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnownedVariableCaptureRule.swift @@ -19,10 +19,10 @@ struct UnownedVariableCaptureRule: OptInRule { Example(""" final class First {} final class Second { - unowned var value: First - init(value: First) { - self.value = value - } + unowned var value: First + init(value: First) { + self.value = value + } } """), ], diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift index d2934ed470..d94c196068 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/NestingRuleExamples.swift @@ -17,7 +17,7 @@ internal struct NestingRuleExamples { \(type) Example_0 { \(type) Example_1 {} } - """), + """), /* all variableKinds of SwiftDeclarationKind (except .varParameter which is a function parameter) @@ -30,7 +30,7 @@ internal struct NestingRuleExamples { } return 5 } - """), + """), // didSet is not present in file structure although there is such a swift declaration kind .init(""" @@ -41,14 +41,14 @@ internal struct NestingRuleExamples { } } } - """), + """), // extensions are counted as a type level .init(""" extension Example_0 { \(type) Example_1 {} } - """), + """), ] } @@ -60,7 +60,7 @@ internal struct NestingRuleExamples { func f_2() {} } } - """), + """), /* all variableKinds of SwiftDeclarationKind (except .varParameter which is a function parameter) @@ -75,7 +75,7 @@ internal struct NestingRuleExamples { } return 5 } - """), + """), // didSet is not present in file structure although there is such a swift declaration kind .init(""" @@ -88,7 +88,7 @@ internal struct NestingRuleExamples { } } } - """), + """), // extensions are counted as a type level .init(""" @@ -99,17 +99,17 @@ internal struct NestingRuleExamples { } } } - """), + """), ] private static let nonTriggeringProtocolExamples = detectingTypes.flatMap { type in [ Example(""" - \(type) Example_0 { - protocol Example_1 {} - } - """), + \(type) Example_0 { + protocol Example_1 {} + } + """), Example(""" var example: Int { \(type) Example_0 { @@ -117,7 +117,7 @@ internal struct NestingRuleExamples { } return 5 } - """), + """), Example(""" var example: Int = 5 { didSet { @@ -126,12 +126,12 @@ internal struct NestingRuleExamples { } } } - """), + """), Example(""" extension Example_0 { protocol Example_1 {} } - """), + """), ] } @@ -152,7 +152,7 @@ internal struct NestingRuleExamples { } } } - """), + """), // closure var example .init(""" @@ -166,7 +166,7 @@ internal struct NestingRuleExamples { } } } - """), + """), // function closure parameter example .init(""" @@ -180,7 +180,7 @@ internal struct NestingRuleExamples { } } }) - """), + """), ] } @@ -199,7 +199,7 @@ internal struct NestingRuleExamples { protocol P {} } } - """), + """), // default maximum nesting level for both type and function within closures and statements .init(""" @@ -225,7 +225,7 @@ internal struct NestingRuleExamples { } } } - """), + """), ] } } @@ -247,7 +247,7 @@ extension NestingRuleExamples { ↓\(type) Example_2 {} } } - """), + """), /* all variableKinds of SwiftDeclarationKind (except .varParameter which is a function parameter) @@ -262,7 +262,7 @@ extension NestingRuleExamples { } return 5 } - """), + """), // didSet is not present in file structure although there is such a swift declaration kind .init(""" @@ -275,7 +275,7 @@ extension NestingRuleExamples { } } } - """), + """), // extensions are counted as a type level, violation of default maximum type nesting level .init(""" @@ -284,7 +284,7 @@ extension NestingRuleExamples { ↓\(type) Example_2 {} } } - """), + """), ] } @@ -298,7 +298,7 @@ extension NestingRuleExamples { } } } - """), + """), /* all variableKinds of SwiftDeclarationKind (except .varParameter which is a function parameter) @@ -315,7 +315,7 @@ extension NestingRuleExamples { } return 5 } - """), + """), // didSet is not present in file structure although there is such a swift declaration kind .init(""" @@ -330,7 +330,7 @@ extension NestingRuleExamples { } } } - """), + """), // extensions are counted as a type level, violation of default maximum function nesting level .init(""" @@ -343,7 +343,7 @@ extension NestingRuleExamples { } } } - """), + """), ] private static let triggeringClosureAndStatementExamples = @@ -367,7 +367,7 @@ extension NestingRuleExamples { } } } - """), + """), // closure var example .init(""" @@ -385,7 +385,7 @@ extension NestingRuleExamples { } } } - """), + """), // function closure parameter example .init(""" @@ -401,7 +401,7 @@ extension NestingRuleExamples { } } }) - """), + """), ] } @@ -409,12 +409,12 @@ extension NestingRuleExamples { detectingTypes.flatMap { type in [ Example(""" - \(type) Example_0 { - \(type) Example_1 { - ↓protocol Example_2 {} + \(type) Example_0 { + \(type) Example_1 { + ↓protocol Example_2 {} + } } - } - """), + """), Example(""" var example: Int { \(type) Example_0 { @@ -424,7 +424,7 @@ extension NestingRuleExamples { } return 5 } - """), + """), Example(""" var example: Int = 5 { didSet { @@ -435,14 +435,14 @@ extension NestingRuleExamples { } } } - """), + """), Example(""" extension Example_0 { \(type) Example_1 { ↓protocol Example_2 {} } } - """), + """), ] } @@ -464,7 +464,7 @@ extension NestingRuleExamples { } } } - """), + """), // violation of default maximum nesting level for both type and function within closures and statements .init(""" @@ -496,7 +496,7 @@ extension NestingRuleExamples { } } } - """), + """), ] } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift index 952e844083..591b7e1d6a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/DirectReturnRule.swift @@ -16,7 +16,7 @@ struct DirectReturnRule: OptInRule { let a = 1 return b } - """), + """), Example(""" struct S { var a: Int { @@ -25,14 +25,14 @@ struct DirectReturnRule: OptInRule { return b } } - """), + """), Example(""" func f() -> Int { let b = 2 f() return b } - """), + """), Example(""" func f() -> Int { { i in @@ -40,7 +40,7 @@ struct DirectReturnRule: OptInRule { return i }(1) } - """), + """), ], triggeringExamples: [ Example(""" @@ -48,7 +48,7 @@ struct DirectReturnRule: OptInRule { let ↓b = 2 return b } - """), + """), Example(""" struct S { var a: Int { @@ -57,13 +57,13 @@ struct DirectReturnRule: OptInRule { return b } } - """), + """), Example(""" func f() -> Bool { let a = 1, ↓b = true return b } - """), + """), Example(""" func f() -> Int { { _ in @@ -71,7 +71,7 @@ struct DirectReturnRule: OptInRule { return b }(1) } - """), + """), Example(""" func f(i: Int) -> Int { if i > 1 { @@ -82,7 +82,7 @@ struct DirectReturnRule: OptInRule { return b } } - """), + """), ], corrections: [ Example(""" @@ -90,11 +90,11 @@ struct DirectReturnRule: OptInRule { let b = 2 return b } - """): Example(""" - func f() -> Int { - return 2 - } - """), + """): Example(""" + func f() -> Int { + return 2 + } + """), Example(""" struct S { var a: Int { @@ -106,28 +106,28 @@ struct DirectReturnRule: OptInRule { } func f() -> Int { 1 } } - """): Example(""" - struct S { - var a: Int { - // comment - return 2 > 1 - ? f() - : 1_000 + """): Example(""" + struct S { + var a: Int { + // comment + return 2 > 1 + ? f() + : 1_000 + } + func f() -> Int { 1 } } - func f() -> Int { 1 } - } - """), + """), Example(""" func f() -> Bool { let a = 1, b = true return b } - """): Example(""" - func f() -> Bool { - let a = 1 - return true - } - """), + """): Example(""" + func f() -> Bool { + let a = 1 + return true + } + """), Example(""" func f() -> Int { { _ in @@ -137,45 +137,45 @@ struct DirectReturnRule: OptInRule { return b }(1) } - """): Example(""" - func f() -> Int { - { _ in - // A comment - // Another comment - return 2 - }(1) - } - """), + """): Example(""" + func f() -> Int { + { _ in + // A comment + // Another comment + return 2 + }(1) + } + """), Example(""" func f() -> UIView { let view = instantiateView() as! UIView // swiftlint:disable:this force_cast return view } - """): Example(""" - func f() -> UIView { - return instantiateView() as! UIView // swiftlint:disable:this force_cast - } - """), + """): Example(""" + func f() -> UIView { + return instantiateView() as! UIView // swiftlint:disable:this force_cast + } + """), Example(""" func f() -> UIView { let view = instantiateView() as! UIView // swiftlint:disable:this force_cast return view // return the view } - """): Example(""" - func f() -> UIView { - return instantiateView() as! UIView // swiftlint:disable:this force_cast // return the view - } - """), + """): Example(""" + func f() -> UIView { + return instantiateView() as! UIView // swiftlint:disable:this force_cast // return the view + } + """), Example(""" func f() -> Bool { let b : Bool = true return b } - """): Example(""" - func f() -> Bool { - return true as Bool - } - """), + """): Example(""" + func f() -> Bool { + return true as Bool + } + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift index 765e1c9c70..95c017cd8d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift @@ -49,15 +49,15 @@ struct EmptyEnumArgumentsRule: Rule { Example("guard foo == .bar() else { return }"), Example(""" if case .appStore = self.appInstaller, !UIDevice.isSimulator() { - viewController.present(self, animated: false) + viewController.present(self, animated: false) } else { - UIApplication.shared.open(self.appInstaller.url) + UIApplication.shared.open(self.appInstaller.url) } """), Example(""" let updatedUserNotificationSettings = deepLink.filter { nav in - guard case .settings(.notifications(_, nil)) = nav else { return false } - return true + guard case .settings(.notifications(_, nil)) = nav else { return false } + return true } """), ], @@ -75,15 +75,15 @@ struct EmptyEnumArgumentsRule: Rule { Example("guard case .bar↓() = foo else {\n}"), Example(""" if case .appStore↓(_) = self.appInstaller, !UIDevice.isSimulator() { - viewController.present(self, animated: false) + viewController.present(self, animated: false) } else { - UIApplication.shared.open(self.appInstaller.url) + UIApplication.shared.open(self.appInstaller.url) } """), Example(""" let updatedUserNotificationSettings = deepLink.filter { nav in - guard case .settings(.notifications↓(_, _)) = nav else { return false } - return true + guard case .settings(.notifications↓(_, _)) = nav else { return false } + return true } """), ], @@ -99,14 +99,14 @@ struct EmptyEnumArgumentsRule: Rule { Example("guard case .bar↓(_) = foo else {"): Example("guard case .bar = foo else {"), Example(""" let updatedUserNotificationSettings = deepLink.filter { nav in - guard case .settings(.notifications↓(_, _)) = nav else { return false } - return true + guard case .settings(.notifications↓(_, _)) = nav else { return false } + return true } """): Example(""" let updatedUserNotificationSettings = deepLink.filter { nav in - guard case .settings(.notifications) = nav else { return false } - return true + guard case .settings(.notifications) = nav else { return false } + return true } """), ] diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift index 1e575d8ff5..e80977416b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift @@ -16,77 +16,77 @@ struct LetVarWhitespaceRule: OptInRule { var x = 1 var y = 2 - """), + """), Example(""" let a = 5 var x = 1 - """), + """), Example(""" var a = 0 - """), + """), Example(""" let a = 1 + 2 let b = 5 - """), + """), Example(""" var x: Int { return 0 } - """), + """), Example(""" var x: Int { let a = 0 return a } - """), + """), Example(""" #if os(macOS) let a = 0 func f() {} #endif - """), + """), Example(""" #warning("TODO: remove it") let a = 0 #warning("TODO: remove it") let b = 0 - """), + """), Example(""" #error("TODO: remove it") let a = 0 - """), + """), Example(""" @available(swift 4) let a = 0 - """), + """), Example(""" @objc var s: String = "" - """), + """), Example(""" @objc func a() {} - """), + """), Example(""" var x = 0 lazy var y = 0 - """), + """), Example(""" @available(OSX, introduced: 10.6) @available(*, deprecated) var x = 0 - """), + """), Example(""" // swiftlint:disable superfluous_disable_command // swiftlint:disable force_cast let x = bar as! Bar - """), + """), Example(""" @available(swift 4) @UserDefault("param", defaultValue: true) @@ -94,14 +94,14 @@ struct LetVarWhitespaceRule: OptInRule { @Attribute func f() {} - """), + """), // Don't trigger on local variable declarations. Example(""" var x: Int { let a = 0 return a } - """), + """), Example(""" static var test: String { /* Comment block */ let s = "!" @@ -109,7 +109,7 @@ struct LetVarWhitespaceRule: OptInRule { } func f() {} - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(#""" @Flag(name: "name", help: "help") var fix = false @@ -120,32 +120,32 @@ struct LetVarWhitespaceRule: OptInRule { var format = false @Flag(help: "help") var useAlternativeExcluding = false - """#, excludeFromDocumentation: true), + """#, excludeFromDocumentation: true), ].map(Self.wrapIntoClass) + [ Example(""" a = 2 - """), + """), Example(""" a = 2 var b = 3 - """), + """), Example(""" #warning("message") let a = 2 - """), + """), Example(""" #if os(macOS) let a = 2 #endif - """), + """), // Don't trigger in closure bodies. Example(""" f { let a = 1 return a } - """), + """), Example(""" func f() { #if os(macOS) @@ -155,27 +155,27 @@ struct LetVarWhitespaceRule: OptInRule { return 1 #endif } - """), + """), ], triggeringExamples: [ Example(""" let a ↓func x() {} - """), + """), Example(""" var x = 0 ↓@objc func f() {} - """), + """), Example(""" var x = 0 ↓@objc func f() {} - """), + """), Example(""" @objc func f() { } ↓var x = 0 - """), + """), Example(""" func f() {} ↓@Wapper @@ -183,18 +183,18 @@ struct LetVarWhitespaceRule: OptInRule { @Wapper var isEnabled = true ↓func g() {} - """), + """), Example(""" #if os(macOS) let a = 0 ↓func f() {} #endif - """), + """), ].map(Self.wrapIntoClass) + [ Example(""" let a = 2 ↓b = 1 - """), + """), Example(""" #if os(macOS) let a = 0 @@ -203,7 +203,7 @@ struct LetVarWhitespaceRule: OptInRule { func f() {} ↓let a = 1 #endif - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), ] ) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift index ac4e58a920..38264908d5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineLiteralBracketsRule.swift @@ -46,7 +46,7 @@ struct MultilineLiteralBracketsRule: OptInRule { 5, 6, 7, 8, 9 ] - """), + """), ], triggeringExamples: [ Example(""" @@ -92,13 +92,13 @@ struct MultilineLiteralBracketsRule: OptInRule { 4, 5, 6, 7, 8, 9↓] - """), + """), Example(""" _ = [↓1, 2, 3, 4, 5, 6, 7, 8, 9 ] - """), + """), Example(""" class Hogwarts { let houseCup = [ diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift index 8296c2f86a..e6fd2e39f0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OperatorUsageWhitespaceRuleExamples.swift @@ -21,10 +21,10 @@ internal enum OperatorUsageWhitespaceRuleExamples { Example("let foo = SignalProducer, Error>([ self.signal, next ]).flatten(.concat)"), Example("\"let foo = 1\""), Example(""" - enum Enum { - case hello = 1 - case hello2 = 1 - } + enum Enum { + case hello = 1 + case hello2 = 1 + } """), Example(""" let something = Something Bool { Self.primes.contains(i) } - """), + """), Example(""" struct T { static let i = 0 @@ -16,13 +16,13 @@ enum PreferSelfInStaticReferencesRuleExamples { static let j = S.i + T.i static let k = { T.j }() } - """), + """), Example(""" class `Self` { static let i = 0 func f() -> Int { Self.i } } - """), + """), Example(""" class C { static private(set) var i = 0, j = C.i @@ -31,7 +31,7 @@ enum PreferSelfInStaticReferencesRuleExamples { var n: Int = C.k { didSet { m += 1 } } @GreaterThan(C.j) var m: Int } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" struct S { struct T { @@ -45,7 +45,7 @@ enum PreferSelfInStaticReferencesRuleExamples { static let j = Self.T.R.i + Self.R.j let h = Self.T.R.i + Self.R.j } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class C { static let s = 2 @@ -55,29 +55,29 @@ enum PreferSelfInStaticReferencesRuleExamples { } func g() -> Any { C.self } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" struct Record { static func get() -> Record { Record() } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" @objc class C: NSObject { @objc var s = "" @objc func f() { _ = #keyPath(C.s) } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class C { let i = 1 let c: C = C() func f(c: C) -> KeyPath { \\Self.i } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class C1 {} class C2: C1 {} - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class C1 {} class C2: C1 { @@ -91,7 +91,7 @@ enum PreferSelfInStaticReferencesRuleExamples { class C4 {} } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class S1 { class S2 {} @@ -100,21 +100,21 @@ enum PreferSelfInStaticReferencesRuleExamples { let s2 = S1() } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), ] static let triggeringExamples = [ Example(""" - final class CheckCellView: NSTableCellView { - @IBOutlet var checkButton: NSButton! + final class CheckCellView: NSTableCellView { + @IBOutlet var checkButton: NSButton! - override func awakeFromNib() { - checkButton.action = #selector(↓CheckCellView.check(_:)) - } + override func awakeFromNib() { + checkButton.action = #selector(↓CheckCellView.check(_:)) + } - @objc func check(_ button: AnyObject?) {} - } - """), + @objc func check(_ button: AnyObject?) {} + } + """), Example(""" class C { static let i = 1 @@ -123,7 +123,7 @@ enum PreferSelfInStaticReferencesRuleExamples { return ii } } - """), + """), Example(""" class C { func f() { @@ -131,7 +131,7 @@ enum PreferSelfInStaticReferencesRuleExamples { _ = [Int: ↓C]() } } - """), + """), Example(""" struct S { let j: Int @@ -142,7 +142,7 @@ enum PreferSelfInStaticReferencesRuleExamples { func i() -> KeyPath<↓S, Int> { \\↓S.j } func j(@Wrap(-↓S.i, ↓S.i) n: Int = ↓S.i) {} } - """), + """), Example(""" struct S { struct T { @@ -153,14 +153,14 @@ enum PreferSelfInStaticReferencesRuleExamples { } static let h = ↓S.T.i + ↓S.R.j } - """), + """), Example(""" enum E { case A static func f() -> ↓E { ↓E.A } static func g() -> ↓E { ↓E.f() } } - """), + """), Example(""" extension E { class C { @@ -176,7 +176,7 @@ enum PreferSelfInStaticReferencesRuleExamples { } } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class C { typealias A = C @@ -214,7 +214,7 @@ enum PreferSelfInStaticReferencesRuleExamples { } func g(a: [↓S]) -> [↓S] { a } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class T { let child: T @@ -222,32 +222,32 @@ enum PreferSelfInStaticReferencesRuleExamples { child = (input as! T).child } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), ] static let corrections = [ Example(""" - final class CheckCellView: NSTableCellView { - @IBOutlet var checkButton: NSButton! + final class CheckCellView: NSTableCellView { + @IBOutlet var checkButton: NSButton! - override func awakeFromNib() { - checkButton.action = #selector(↓CheckCellView.check(_:)) - } + override func awakeFromNib() { + checkButton.action = #selector(↓CheckCellView.check(_:)) + } - @objc func check(_ button: AnyObject?) {} - } - """): + @objc func check(_ button: AnyObject?) {} + } + """): Example(""" - final class CheckCellView: NSTableCellView { - @IBOutlet var checkButton: NSButton! + final class CheckCellView: NSTableCellView { + @IBOutlet var checkButton: NSButton! - override func awakeFromNib() { - checkButton.action = #selector(Self.check(_:)) - } + override func awakeFromNib() { + checkButton.action = #selector(Self.check(_:)) + } - @objc func check(_ button: AnyObject?) {} - } - """), + @objc func check(_ button: AnyObject?) {} + } + """), Example(""" struct S { static let i = 1 @@ -256,14 +256,14 @@ enum PreferSelfInStaticReferencesRuleExamples { static func f(_ l: Int = ↓S.i) -> Int { l*↓S.j } func g() { ↓S.i + ↓S.f() + k } } - """): Example(""" - struct S { - static let i = 1 - static let j = Self.i - let k = Self . j - static func f(_ l: Int = Self.i) -> Int { l*Self.j } - func g() { Self.i + Self.f() + k } - } - """), + """): Example(""" + struct S { + static let i = 1 + static let j = Self.i + let k = Self . j + static func f(_ l: Int = Self.i) -> Int { l*Self.j } + func g() { Self.i + Self.f() + k } + } + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift index 40b271ef2a..e9924e66dd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRuleExamples.swift @@ -12,7 +12,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """), + """), Example(""" class C { var x = 0 @@ -28,7 +28,7 @@ struct RedundantSelfInClosureRuleExamples { f { [weak self] in if let self { x = 1 } } } } - """), + """), Example(""" struct S { var x = 0, error = 0, exception = 0 @@ -58,7 +58,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """), + """), Example(""" enum E { case a(Int) @@ -79,20 +79,20 @@ struct RedundantSelfInClosureRuleExamples { } } } - """), + """), Example(""" - class C { - var a = 0 - init(_ a: Int) { - self.a = a - f { [weak self] in - guard let self else { return } - self.a = 1 + class C { + var a = 0 + init(_ a: Int) { + self.a = a + f { [weak self] in + guard let self else { return } + self.a = 1 + } } + func f(_: () -> Void) {} } - func f(_: () -> Void) {} - } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), ] static let triggeringExamples = [ @@ -107,7 +107,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """), + """), Example(""" class C { var x = 0 @@ -118,7 +118,7 @@ struct RedundantSelfInClosureRuleExamples { }() } } - """), + """), Example(""" class C { var x = 0 @@ -131,7 +131,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """), + """), Example(""" class C { var x = 0 @@ -142,7 +142,7 @@ struct RedundantSelfInClosureRuleExamples { f { [s = self] in s.x = 1 } } } - """), + """), Example(""" struct S { var x = 0 @@ -171,7 +171,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """), + """), Example(""" struct S { func f(_ work: @escaping () -> Void) { work() } @@ -179,7 +179,7 @@ struct RedundantSelfInClosureRuleExamples { f { let g = ↓self.g() } } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" extension E { static func f(_ work: @escaping () -> Void) { work() } @@ -188,7 +188,7 @@ struct RedundantSelfInClosureRuleExamples { func g() { E.f { ↓self.g() } } } } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" class C { var x = 0 @@ -211,7 +211,7 @@ struct RedundantSelfInClosureRuleExamples { } } } - """), + """), ] static let corrections = [ @@ -226,17 +226,17 @@ struct RedundantSelfInClosureRuleExamples { } } } - """): Example(""" - struct S { - var x = 0 - func f(_ work: @escaping () -> Void) { work() } - func g() { - f { - x = 1 - if x == 1 { g() } + """): Example(""" + struct S { + var x = 0 + func f(_ work: @escaping () -> Void) { work() } + func g() { + f { + x = 1 + if x == 1 { g() } + } } } - } - """), + """), ] } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift index 5783bd6013..f8068dafd2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ShorthandArgumentRule.swift @@ -17,22 +17,22 @@ struct ShorthandArgumentRule: OptInRule { nonTriggeringExamples: [ Example(""" f { $0 } - """), + """), Example(""" f { $0 + $1 + $2 } - """), + """), Example(""" f { $0.a + $0.b } - """), + """), Example(""" f { $0 + g { $0 } - """, configuration: ["allow_until_line_after_opening_brace": 1]), + """, configuration: ["allow_until_line_after_opening_brace": 1]), ], triggeringExamples: [ Example(""" @@ -43,7 +43,7 @@ struct ShorthandArgumentRule: OptInRule { + ↓$0 } - """), + """), Example(""" f { $0 @@ -53,18 +53,18 @@ struct ShorthandArgumentRule: OptInRule { + $0 + ↓$1 } - """, configuration: ["allow_until_line_after_opening_brace": 5]), + """, configuration: ["allow_until_line_after_opening_brace": 5]), Example(""" f { ↓$0 + ↓$1 } - """, configuration: ["always_disallow_more_than_one": true]), + """, configuration: ["always_disallow_more_than_one": true]), Example(""" f { ↓$0.a + ↓$0.b + $1 + ↓$2.c - } - """, configuration: ["always_disallow_member_access": true, "allow_until_line_after_opening_brace": 3]), + } + """, configuration: ["always_disallow_member_access": true, "allow_until_line_after_opening_brace": 3]), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift index 21d8fbe4ab..c2d5bfffbf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift @@ -19,7 +19,7 @@ struct SuperfluousElseRule: OptInRule { } else { return 3 } - """), + """), Example(""" if i > 0 { let a = 1 @@ -32,7 +32,7 @@ struct SuperfluousElseRule: OptInRule { } else { return 3 } - """), + """), Example(""" if i > 0 { if a > 1 { @@ -41,7 +41,7 @@ struct SuperfluousElseRule: OptInRule { } else { return 3 } - """), + """), Example(""" if i > 0 { if a > 1 { @@ -54,7 +54,7 @@ struct SuperfluousElseRule: OptInRule { } else { return 3 } - """, excludeFromDocumentation: true), + """, excludeFromDocumentation: true), Example(""" for i in list { if i > 12 { @@ -68,7 +68,7 @@ struct SuperfluousElseRule: OptInRule { break } } - """), + """), ], triggeringExamples: [ Example(""" @@ -78,7 +78,7 @@ struct SuperfluousElseRule: OptInRule { } ↓else { return 2 } - """), + """), Example(""" if i > 0 { return 1 @@ -87,7 +87,7 @@ struct SuperfluousElseRule: OptInRule { } ↓else if i > 18 { return 3 } - """), + """), Example(""" if i > 0 { if i < 12 { @@ -106,7 +106,7 @@ struct SuperfluousElseRule: OptInRule { } ↓else { return 3 } - """), + """), Example(""" for i in list { if i > 13 { @@ -119,7 +119,7 @@ struct SuperfluousElseRule: OptInRule { throw error } } - """), + """), ], corrections: [ Example(""" @@ -133,17 +133,17 @@ struct SuperfluousElseRule: OptInRule { // yet another comment } } - """): Example(""" - func f() -> Int { - if i > 0 { - return 1 - // comment + """): Example(""" + func f() -> Int { + if i > 0 { + return 1 + // comment + } + // another comment + return 2 + // yet another comment } - // another comment - return 2 - // yet another comment - } - """), + """), Example(""" func f() -> Int { if i > 0 { @@ -155,18 +155,18 @@ struct SuperfluousElseRule: OptInRule { return 3 } } - """): Example(""" - func f() -> Int { - if i > 0 { - return 1 - // comment - } - if i < 10 { - return 2 + """): Example(""" + func f() -> Int { + if i > 0 { + return 1 + // comment + } + if i < 10 { + return 2 + } + return 3 } - return 3 - } - """), + """), Example(""" func f() -> Int { @@ -178,19 +178,19 @@ struct SuperfluousElseRule: OptInRule { return 2 } } - """): Example(""" - func f() -> Int { + """): Example(""" + func f() -> Int { - if i > 0 { - return 1 - // comment - } - if i < 10 { - // another comment - return 2 + if i > 0 { + return 1 + // comment + } + if i < 10 { + // another comment + return 2 + } } - } - """), + """), Example(""" { if i > 0 { @@ -199,14 +199,14 @@ struct SuperfluousElseRule: OptInRule { return 2 } }() - """): Example(""" - { - if i > 0 { - return 1 - } - return 2 - }() - """), + """): Example(""" + { + if i > 0 { + return 1 + } + return 2 + }() + """), Example(""" for i in list { if i > 13 { @@ -223,24 +223,24 @@ struct SuperfluousElseRule: OptInRule { } } - """): Example(""" - for i in list { - if i > 13 { - return - } - if i > 12 { - continue // continue with next index - } - if i > 11 { - break - // end of loop - } - if i > 10 { - // Some error - throw error + """): Example(""" + for i in list { + if i > 13 { + return + } + if i > 12 { + continue // continue with next index + } + if i > 11 { + break + // end of loop + } + if i > 10 { + // Some error + throw error + } } - } - """), + """), ] ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift index 836e38a9be..74c20dd940 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRuleExamples.swift @@ -1,10 +1,10 @@ internal struct TypeContentsOrderRuleExamples { static let defaultOrderParts = [ - """ + """ // Type Aliases typealias CompletionHandler = ((TestEnum) -> Void) - """, - """ + """, + """ // Subtypes class TestClass { // 10 lines @@ -17,12 +17,12 @@ internal struct TypeContentsOrderRuleExamples { enum TestEnum { // 5 lines } - """, - """ + """, + """ // Type Properties static let cellIdentifier: String = "AmazingCell" - """, - """ + """, + """ // Instance Properties var shouldLayoutView1: Bool! weak var delegate: TestViewControllerDelegate? @@ -32,13 +32,13 @@ internal struct TypeContentsOrderRuleExamples { private var hasAnyLayoutedView: Bool { return hasLayoutedView1 || hasLayoutedView2 } - """, - """ + """, + """ // IBOutlets @IBOutlet private var view1: UIView! @IBOutlet private var view2: UIView! - """, - """ + """, + """ // Initializers override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) @@ -47,14 +47,14 @@ internal struct TypeContentsOrderRuleExamples { required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - """, - """ + """, + """ // Type Methods static func makeViewController() -> TestViewController { // some code } - """, - """ + """, + """ // View Life-Cycle Methods override func viewDidLoad() { super.viewDidLoad() @@ -82,15 +82,15 @@ internal struct TypeContentsOrderRuleExamples { override func viewIsAppearing(_ animated: Bool) { super.viewIsAppearing(animated) } - """, - """ + """, + """ // IBActions @IBAction func goNextButtonPressed() { goToNextVc() delegate?.didPressTrackedButton() } - """, - """ + """, + """ // Other Methods func goToNextVc() { /* TODO */ } @@ -102,8 +102,8 @@ internal struct TypeContentsOrderRuleExamples { } private func getRandomVc() -> UIViewController { return UIViewController() } - """, - """ + """, + """ // Subscripts subscript(_ someIndexThatIsNotEvenUsed: Int) -> String { get { @@ -114,12 +114,12 @@ internal struct TypeContentsOrderRuleExamples { log.warning("Just a test", newValue) } } - """, - """ + """, + """ deinit { log.debug("deinit") } - """, + """, ] static let nonTriggeringExamples = [ diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift index bdd84043f6..c5609af0bf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift @@ -12,38 +12,38 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { private static let nonTriggeringExamples: [Example] = [ Example(""" - switch x { + switch x { - case 0..<5: - print("x is low") + case 0..<5: + print("x is low") - case 5..<10: - print("x is high") + case 5..<10: + print("x is high") - default: - print("x is invalid") + default: + print("x is invalid") - } - """), + } + """), Example(""" - switch x { - case 0..<5: - print("x is low") + switch x { + case 0..<5: + print("x is low") - case 5..<10: - print("x is high") + case 5..<10: + print("x is high") - default: - print("x is invalid") - } - """), + default: + print("x is invalid") + } + """), Example(""" - switch x { - case 0..<5: print("x is low") - case 5..<10: print("x is high") - default: print("x is invalid") - } - """), + switch x { + case 0..<5: print("x is low") + case 5..<10: print("x is high") + default: print("x is invalid") + } + """), // Testing handling of trailing spaces: do not convert to """ style Example([ "switch x { \n", @@ -61,70 +61,70 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { switch x { case 0..<5: return "x is valid" - ↓ default: - return "x is invalid" - } - """): Example(""" - switch x { - case 0..<5: - return "x is valid" - - default: + ↓default: return "x is invalid" } - """), + """): Example(""" + switch x { + case 0..<5: + return "x is valid" + + default: + return "x is invalid" + } + """), Example(""" switch x { case 0..<5: print("x is valid") - ↓ default: + ↓default: print("x is invalid") } - """): Example(""" - switch x { - case 0..<5: - print("x is valid") - - default: - print("x is invalid") - } - """), + """): Example(""" + switch x { + case 0..<5: + print("x is valid") + + default: + print("x is invalid") + } + """), Example(""" switch x { case .valid: print("x is valid") - ↓ case .invalid: + ↓case .invalid: print("x is invalid") } - """): Example(""" - switch x { - case .valid: - print("x is valid") - - case .invalid: - print("x is invalid") - } - """), + """): Example(""" + switch x { + case .valid: + print("x is valid") + + case .invalid: + print("x is invalid") + } + """), Example(""" switch x { case .valid: print("multiple ...") print("... lines") - ↓ case .invalid: - print("multiple ...") - print("... lines") - } - """): Example(""" - switch x { - case .valid: - print("multiple ...") - print("... lines") - - case .invalid: + ↓case .invalid: print("multiple ...") print("... lines") } - """), + """): Example(""" + switch x { + case .valid: + print("multiple ...") + print("... lines") + + case .invalid: + print("multiple ...") + print("... lines") + } + """), ] private let pattern = "([^\\n{][ \\t]*\\n)([ \\t]*(?:case[^\\n]+|default):[ \\t]*\\n)" From 1faaf108381131de789d2dc34a1d0a50b6818fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 17 Jul 2024 22:11:52 +0200 Subject: [PATCH 116/265] Adapt SwiftSyntax repository URL (#5678) --- CHANGELOG.md | 2 +- Package.resolved | 2 +- Package.swift | 2 +- bazel/repos.bzl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d11a491ef8..bb32d2899b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ #### Enhancements * Linting got around 20% faster due to the praisworthy performance - improvements done in the [SwiftSyntax](https://github.com/apple/swift-syntax) + improvements done in the [SwiftSyntax](https://github.com/swiftlang/swift-syntax) library. * Rewrite the following rules with SwiftSyntax: diff --git a/Package.resolved b/Package.resolved index 5f29f82167..2d9174b8e3 100644 --- a/Package.resolved +++ b/Package.resolved @@ -39,7 +39,7 @@ { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", + "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { "revision" : "55c4e4669c031d697e1924022b8ba250cfde0f2f", "version" : "600.0.0-prerelease-2024-04-02" diff --git a/Package.swift b/Package.swift index 8dcec252bd..9b91a4bde1 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), - .package(url: "https://github.com/apple/swift-syntax.git", exact: "600.0.0-prerelease-2024-04-02"), + .package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "600.0.0-prerelease-2024-04-02"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), diff --git a/bazel/repos.bzl b/bazel/repos.bzl index ba4f937e22..447e216d8b 100644 --- a/bazel/repos.bzl +++ b/bazel/repos.bzl @@ -14,7 +14,7 @@ def swiftlint_repos(bzlmod = False): name = "SwiftSyntax", sha256 = "6572f60ca3c75c2a40f8ccec98c5cd0d3994599a39402d69b433381aaf2c1712", strip_prefix = "swift-syntax-510.0.2", - url = "https://github.com/apple/swift-syntax/archive/refs/tags/510.0.2.tar.gz", + url = "https://github.com/swiftlang/swift-syntax/archive/refs/tags/510.0.2.tar.gz", ) http_archive( From 3421f5f46d23b539e1afbc7e74c9275b26635997 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Thu, 18 Jul 2024 01:48:02 +0100 Subject: [PATCH 117/265] Enable `multiline_parameters` rule, and fix all cases (#5664) --- .swiftlint.yml | 1 - .../Idiomatic/UnneededBreakInSwitchRule.swift | 3 ++- .../Lint/AccessibilityLabelForImageRule.swift | 3 ++- .../Lint/AccessibilityTraitForButtonRule.swift | 3 ++- .../Rules/Lint/CaptureVariableRule.swift | 3 ++- .../Rules/Lint/LocalDocCommentRule.swift | 3 ++- .../Rules/Lint/OverrideInExtensionRule.swift | 3 ++- .../Rules/Lint/UnusedDeclarationRule.swift | 17 ++++++++++------- .../FileHeaderConfiguration.swift | 6 ++++-- .../Style/ClosureEndIndentationRule.swift | 9 ++++++--- .../Rules/Style/EmptyEnumArgumentsRule.swift | 3 ++- .../LiteralExpressionEndIndentationRule.swift | 3 ++- .../Configuration+LintableFiles.swift | 3 ++- Source/SwiftLintCore/Models/Command.swift | 8 ++++++-- Source/SwiftLintCore/Models/Example.swift | 12 +++++++++--- Source/SwiftLintCore/Models/Linter.swift | 8 ++++++-- .../SwiftLintCore/Models/RuleDescription.swift | 8 ++++++-- .../Protocols/CollectingRule.swift | 13 +++++++++---- Source/SwiftLintCore/Protocols/Rule.swift | 3 +-- .../SwiftLintCore/Reporters/HTMLReporter.swift | 3 ++- Source/swiftlint/Commands/Rules.swift | 3 ++- .../Extensions/Configuration+CommandLine.swift | 4 +++- .../Helpers/LintableFilesVisitor.swift | 16 ++++++++++++---- .../CollectingRuleTests.swift | 3 ++- .../FileNameRuleTests.swift | 6 ++++-- .../LinterCacheTests.swift | 16 +++++++++++----- Tests/SwiftLintTestHelpers/TestHelpers.swift | 18 ++++++++++++------ 27 files changed, 123 insertions(+), 58 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index f2adc863b1..fc5d5cd6db 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -32,7 +32,6 @@ disabled_rules: - multiline_arguments - multiline_arguments_brackets - multiline_function_chains - - multiline_parameters - multiline_parameters_brackets - no_extension_access_modifier - no_grouping_extension diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift index abf8ed04c2..ea46cba797 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededBreakInSwitchRule.swift @@ -3,7 +3,8 @@ import SwiftSyntax private func embedInSwitch( _ text: String, case: String = "case .bar", - file: StaticString = #filePath, line: UInt = #line) -> Example { + file: StaticString = #filePath, + line: UInt = #line) -> Example { Example(""" switch foo { \(`case`): diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift index b2f6a69ea2..1c59e13568 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift @@ -25,7 +25,8 @@ struct AccessibilityLabelForImageRule: ASTRule, OptInRule { // MARK: AST Rule - func validate(file: SwiftLintFile, kind: SwiftDeclarationKind, + func validate(file: SwiftLintFile, + kind: SwiftDeclarationKind, dictionary: SourceKittenDictionary) -> [StyleViolation] { // Only proceed to check View structs. guard kind == .struct, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift index d122ad0bae..c14ffb7b8c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityTraitForButtonRule.swift @@ -23,7 +23,8 @@ struct AccessibilityTraitForButtonRule: ASTRule, OptInRule { // MARK: AST Rule - func validate(file: SwiftLintFile, kind: SwiftDeclarationKind, + func validate(file: SwiftLintFile, + kind: SwiftDeclarationKind, dictionary: SourceKittenDictionary) -> [StyleViolation] { // Only proceed to check View structs. guard kind == .struct, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift index 11450314bb..10c4d6b20a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift @@ -158,7 +158,8 @@ struct CaptureVariableRule: AnalyzerRule, CollectingRule { file.declaredVariables(compilerArguments: compilerArguments) } - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Self.FileInfo], + func validate(file: SwiftLintFile, + collectedInfo: [SwiftLintFile: Self.FileInfo], compilerArguments: [String]) -> [StyleViolation] { file.captureListVariables(compilerArguments: compilerArguments) .filter { capturedVariable in collectedInfo.values.contains { $0.contains(capturedVariable.usr) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift index dc551ea499..bf9dc3b8ca 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/LocalDocCommentRule.swift @@ -53,7 +53,8 @@ private extension LocalDocCommentRule { final class Visitor: ViolationsSyntaxVisitor { private let docCommentRanges: [ByteSourceRange] - init(configuration: ConfigurationType, file: SwiftLintFile, + init(configuration: ConfigurationType, + file: SwiftLintFile, classifications: [SyntaxClassifiedRange]) { self.docCommentRanges = classifications .filter { $0.kind == .docLineComment || $0.kind == .docBlockComment } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift index 99d47cddff..f1554b2580 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/OverrideInExtensionRule.swift @@ -50,7 +50,8 @@ private extension OverrideInExtensionRule { final class Visitor: ViolationsSyntaxVisitor { private let allowedExtensions: Set - init(configuration: ConfigurationType, file: SwiftLintFile, + init(configuration: ConfigurationType, + file: SwiftLintFile, allowedExtensions: Set) { self.allowedExtensions = allowedExtensions super.init(configuration: configuration, file: file) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index fe9fd6f6fb..d2d8ac966b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -54,7 +54,8 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { ) } - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: Self.FileUSRs], + func validate(file: SwiftLintFile, + collectedInfo: [SwiftLintFile: Self.FileUSRs], compilerArguments _: [String]) -> [StyleViolation] { let allReferencedUSRs = collectedInfo.values.reduce(into: Set()) { $0.formUnion($1.referenced) } return violationOffsets(declaredUSRs: collectedInfo[file]?.declared ?? [], @@ -106,18 +107,20 @@ private extension SwiftLintFile { }) } - func declaredUSRs(index: SourceKittenDictionary, editorOpen: SourceKittenDictionary, - compilerArguments: [String], configuration: UnusedDeclarationConfiguration) - -> Set { + func declaredUSRs(index: SourceKittenDictionary, + editorOpen: SourceKittenDictionary, + compilerArguments: [String], + configuration: UnusedDeclarationConfiguration) -> Set { Set(index.traverseEntitiesDepthFirst { _, indexEntity in self.declaredUSR(indexEntity: indexEntity, editorOpen: editorOpen, compilerArguments: compilerArguments, configuration: configuration) }) } - func declaredUSR(indexEntity: SourceKittenDictionary, editorOpen: SourceKittenDictionary, - compilerArguments: [String], configuration: UnusedDeclarationConfiguration) - -> UnusedDeclarationRule.DeclaredUSR? { + func declaredUSR(indexEntity: SourceKittenDictionary, + editorOpen: SourceKittenDictionary, + compilerArguments: [String], + configuration: UnusedDeclarationConfiguration) -> UnusedDeclarationRule.DeclaredUSR? { guard let stringKind = indexEntity.kind, stringKind.starts(with: "source.lang.swift.decl."), !stringKind.contains(".accessor."), diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift index f3176dcf76..2090c23ba6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileHeaderConfiguration.swift @@ -65,8 +65,10 @@ struct FileHeaderConfiguration: SeverityBasedRuleConfiguration { } } - private func makeRegex(for file: SwiftLintFile, using pattern: String, - options: NSRegularExpression.Options, escapeFileName: Bool) -> NSRegularExpression? { + private func makeRegex(for file: SwiftLintFile, + using pattern: String, + options: NSRegularExpression.Options, + escapeFileName: Bool) -> NSRegularExpression? { // Recompile the regex for this file... let replacedPattern = file.path.map { path in let fileName = path.bridge().lastPathComponent diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift index 4c64aa58ed..4e760bbc0f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ClosureEndIndentationRule.swift @@ -119,7 +119,8 @@ extension ClosureEndIndentationRule { } } - private func violations(in file: SwiftLintFile, of kind: SwiftExpressionKind, + private func violations(in file: SwiftLintFile, + of kind: SwiftExpressionKind, dictionary: SourceKittenDictionary) -> [Violation] { guard kind == .call else { return [] @@ -269,7 +270,8 @@ extension ClosureEndIndentationRule { } private func isSingleLineClosure(dictionary: SourceKittenDictionary, - endPosition: ByteCount, file: SwiftLintFile) -> Bool { + endPosition: ByteCount, + file: SwiftLintFile) -> Bool { let contents = file.stringView guard let start = dictionary.bodyOffset, @@ -282,7 +284,8 @@ extension ClosureEndIndentationRule { } private func containsSingleLineClosure(dictionary: SourceKittenDictionary, - endPosition: ByteCount, file: SwiftLintFile) -> Bool { + endPosition: ByteCount, + file: SwiftLintFile) -> Bool { let contents = file.stringView guard let closure = trailingClosure(dictionary: dictionary, file: file), diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift index 95c017cd8d..f6d5409b95 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift @@ -3,7 +3,8 @@ import SwiftSyntax private func wrapInSwitch( variable: String = "foo", _ str: String, - file: StaticString = #filePath, line: UInt = #line) -> Example { + file: StaticString = #filePath, + line: UInt = #line) -> Example { Example( """ switch \(variable) { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift index 57ae0d070d..29193dba7b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/LiteralExpressionEndIndentationRule.swift @@ -220,7 +220,8 @@ extension LiteralExpressionEndIndentationRule { } } - private func violation(in file: SwiftLintFile, of kind: SwiftExpressionKind, + private func violation(in file: SwiftLintFile, + of kind: SwiftExpressionKind, dictionary: SourceKittenDictionary) -> Violation? { guard kind == .dictionary || kind == .array else { return nil diff --git a/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift b/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift index af11657c0f..79617bf622 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+LintableFiles.swift @@ -16,7 +16,8 @@ extension Configuration { /// - parameter excludeByPrefix: Whether or not uses excluding by prefix algorithm. /// /// - returns: Files to lint. - public func lintableFiles(inPath path: String, forceExclude: Bool, + public func lintableFiles(inPath path: String, + forceExclude: Bool, excludeBy: ExcludeBy) -> [SwiftLintFile] { lintablePaths(inPath: path, forceExclude: forceExclude, excludeBy: excludeBy) .compactMap(SwiftLintFile.init(pathDeferringReading:)) diff --git a/Source/SwiftLintCore/Models/Command.swift b/Source/SwiftLintCore/Models/Command.swift index e485200958..375cdf00a6 100644 --- a/Source/SwiftLintCore/Models/Command.swift +++ b/Source/SwiftLintCore/Models/Command.swift @@ -67,8 +67,12 @@ public struct Command: Equatable { /// defined. /// - parameter modifier: This command's modifier, if any. /// - parameter trailingComment: The comment following this command's `-` delimiter, if any. - public init(action: Action, ruleIdentifiers: Set = [], line: Int = 0, - character: Int? = nil, modifier: Modifier? = nil, trailingComment: String? = nil) { + public init(action: Action, + ruleIdentifiers: Set = [], + line: Int = 0, + character: Int? = nil, + modifier: Modifier? = nil, + trailingComment: String? = nil) { self.action = action self.ruleIdentifiers = ruleIdentifiers self.line = line diff --git a/Source/SwiftLintCore/Models/Example.swift b/Source/SwiftLintCore/Models/Example.swift index 977e7df02a..1c49edbb15 100644 --- a/Source/SwiftLintCore/Models/Example.swift +++ b/Source/SwiftLintCore/Models/Example.swift @@ -59,9 +59,15 @@ public extension Example { /// Defaults to the file where this initializer is called. /// - line: The line in the file where the example is located. /// Defaults to the line where this initializer is called. - init(_ code: String, configuration: [String: any Sendable]? = nil, testMultiByteOffsets: Bool = true, - testWrappingInComment: Bool = true, testWrappingInString: Bool = true, testDisableCommand: Bool = true, - testOnLinux: Bool = true, file: StaticString = #filePath, line: UInt = #line, + init(_ code: String, + configuration: [String: any Sendable]? = nil, + testMultiByteOffsets: Bool = true, + testWrappingInComment: Bool = true, + testWrappingInString: Bool = true, + testDisableCommand: Bool = true, + testOnLinux: Bool = true, + file: StaticString = #filePath, + line: UInt = #line, excludeFromDocumentation: Bool = false) { self.code = code self.configuration = configuration diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index 00f3a21277..be8a440ac5 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -57,7 +57,9 @@ private extension Rule { // As we need the configuration to get custom identifiers. // swiftlint:disable:next function_parameter_count - func lint(file: SwiftLintFile, regions: [Region], benchmark: Bool, + func lint(file: SwiftLintFile, + regions: [Region], + benchmark: Bool, storage: RuleStorage, superfluousDisableCommandRule: SuperfluousDisableCommandRule?, compilerArguments: [String]) -> LintResult? { @@ -143,7 +145,9 @@ public struct Linter { /// - parameter configuration: The SwiftLint configuration to apply to this linter. /// - parameter cache: The persisted cache to use for this linter. /// - parameter compilerArguments: The compiler arguments to use for this linter if it is to execute analyzer rules. - public init(file: SwiftLintFile, configuration: Configuration = Configuration.default, cache: LinterCache? = nil, + public init(file: SwiftLintFile, + configuration: Configuration = Configuration.default, + cache: LinterCache? = nil, compilerArguments: [String] = []) { self.file = file self.cache = cache diff --git a/Source/SwiftLintCore/Models/RuleDescription.swift b/Source/SwiftLintCore/Models/RuleDescription.swift index 9d94fc37de..4df2960eaf 100644 --- a/Source/SwiftLintCore/Models/RuleDescription.swift +++ b/Source/SwiftLintCore/Models/RuleDescription.swift @@ -71,9 +71,13 @@ public struct RuleDescription: Equatable, Sendable { /// - parameter corrections: Sets the description's `corrections` property. /// - parameter deprecatedAliases: Sets the description's `deprecatedAliases` property. /// - parameter requiresFileOnDisk: Sets the description's `requiresFileOnDisk` property. - public init(identifier: String, name: String, description: String, kind: RuleKind, + public init(identifier: String, + name: String, + description: String, + kind: RuleKind, minSwiftVersion: SwiftVersion = .five, - nonTriggeringExamples: [Example] = [], triggeringExamples: [Example] = [], + nonTriggeringExamples: [Example] = [], + triggeringExamples: [Example] = [], corrections: [Example: Example] = [:], deprecatedAliases: Set = [], requiresFileOnDisk: Bool = false) { diff --git a/Source/SwiftLintCore/Protocols/CollectingRule.swift b/Source/SwiftLintCore/Protocols/CollectingRule.swift index 1d6ae737fb..3bacde8e81 100644 --- a/Source/SwiftLintCore/Protocols/CollectingRule.swift +++ b/Source/SwiftLintCore/Protocols/CollectingRule.swift @@ -29,7 +29,8 @@ public protocol CollectingRule: AnyCollectingRule { /// - parameter compilerArguments: The compiler arguments needed to compile this file. /// /// - returns: All style violations to the rule's expectations. - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], + func validate(file: SwiftLintFile, + collectedInfo: [SwiftLintFile: FileInfo], compilerArguments: [String]) -> [StyleViolation] /// Executes the rule on a file after collecting file info for all files and returns any violations to the rule's @@ -56,7 +57,9 @@ public extension CollectingRule { func collectInfo(for file: SwiftLintFile, compilerArguments _: [String]) -> FileInfo { collectInfo(for: file) } - func validate(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], + + func validate(file: SwiftLintFile, + collectedInfo: [SwiftLintFile: FileInfo], compilerArguments _: [String]) -> [StyleViolation] { validate(file: file, collectedInfo: collectedInfo) } @@ -98,7 +101,8 @@ package protocol CollectingCorrectableRule: CollectingRule, CorrectableRule { /// - parameter compilerArguments: The compiler arguments needed to compile this file. /// /// - returns: All corrections that were applied. - func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], + func correct(file: SwiftLintFile, + collectedInfo: [SwiftLintFile: FileInfo], compilerArguments: [String]) -> [Correction] /// Attempts to correct the violations to this rule in the specified file after collecting file info for all files @@ -114,7 +118,8 @@ package protocol CollectingCorrectableRule: CollectingRule, CorrectableRule { } package extension CollectingCorrectableRule { - func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: FileInfo], + func correct(file: SwiftLintFile, + collectedInfo: [SwiftLintFile: FileInfo], compilerArguments _: [String]) -> [Correction] { correct(file: file, collectedInfo: collectedInfo) } diff --git a/Source/SwiftLintCore/Protocols/Rule.swift b/Source/SwiftLintCore/Protocols/Rule.swift index 685e1ef859..d04f234e53 100644 --- a/Source/SwiftLintCore/Protocols/Rule.swift +++ b/Source/SwiftLintCore/Protocols/Rule.swift @@ -82,8 +82,7 @@ public extension Rule { try self.configuration.apply(configuration: configuration) } - func validate(file: SwiftLintFile, using _: RuleStorage, - compilerArguments: [String]) -> [StyleViolation] { + func validate(file: SwiftLintFile, using _: RuleStorage, compilerArguments: [String]) -> [StyleViolation] { validate(file: file, compilerArguments: compilerArguments) } diff --git a/Source/SwiftLintCore/Reporters/HTMLReporter.swift b/Source/SwiftLintCore/Reporters/HTMLReporter.swift index ceaf3042bb..778c2e78ae 100644 --- a/Source/SwiftLintCore/Reporters/HTMLReporter.swift +++ b/Source/SwiftLintCore/Reporters/HTMLReporter.swift @@ -21,7 +21,8 @@ struct HTMLReporter: Reporter { // MARK: - Internal // swiftlint:disable:next function_body_length - internal static func generateReport(_ violations: [StyleViolation], swiftlintVersion: String, + internal static func generateReport(_ violations: [StyleViolation], + swiftlintVersion: String, dateString: String) -> String { let rows = violations.enumerated() .map { generateSingleRow(for: $1, at: $0 + 1) } diff --git a/Source/swiftlint/Commands/Rules.swift b/Source/swiftlint/Commands/Rules.swift index dc709af831..33cb9bd94a 100644 --- a/Source/swiftlint/Commands/Rules.swift +++ b/Source/swiftlint/Commands/Rules.swift @@ -93,7 +93,8 @@ extension SwiftLint { } } - private func createInstance(of ruleType: any Rule.Type, using config: Configuration, + private func createInstance(of ruleType: any Rule.Type, + using config: Configuration, configure: Bool) -> any Rule { configure ? config.configuredRule(forID: ruleType.identifier) ?? ruleType.init() diff --git a/Source/swiftlint/Extensions/Configuration+CommandLine.swift b/Source/swiftlint/Extensions/Configuration+CommandLine.swift index c1dc248e82..048a6edfe3 100644 --- a/Source/swiftlint/Extensions/Configuration+CommandLine.swift +++ b/Source/swiftlint/Extensions/Configuration+CommandLine.swift @@ -252,7 +252,9 @@ extension Configuration { } } - func visitLintableFiles(options: LintOrAnalyzeOptions, cache: LinterCache? = nil, storage: RuleStorage, + func visitLintableFiles(options: LintOrAnalyzeOptions, + cache: LinterCache? = nil, + storage: RuleStorage, visitorBlock: @escaping (CollectedLinter) async -> Void) async throws -> [SwiftLintFile] { let visitor = try LintableFilesVisitor.create(options, cache: cache, allowZeroLintableFiles: allowZeroLintableFiles, diff --git a/Source/swiftlint/Helpers/LintableFilesVisitor.swift b/Source/swiftlint/Helpers/LintableFilesVisitor.swift index a9dd7d3ace..c11d11688d 100644 --- a/Source/swiftlint/Helpers/LintableFilesVisitor.swift +++ b/Source/swiftlint/Helpers/LintableFilesVisitor.swift @@ -83,10 +83,18 @@ struct LintableFilesVisitor { let mode: LintOrAnalyzeModeWithCompilerArguments let block: (CollectedLinter) async -> Void - private init(paths: [String], action: String, useSTDIN: Bool, quiet: Bool, showProgressBar: Bool, - useScriptInputFiles: Bool, forceExclude: Bool, useExcludingByPrefix: Bool, - cache: LinterCache?, compilerInvocations: CompilerInvocations?, - allowZeroLintableFiles: Bool, block: @escaping (CollectedLinter) async -> Void) { + private init(paths: [String], + action: String, + useSTDIN: Bool, + quiet: Bool, + showProgressBar: Bool, + useScriptInputFiles: Bool, + forceExclude: Bool, + useExcludingByPrefix: Bool, + cache: LinterCache?, + compilerInvocations: CompilerInvocations?, + allowZeroLintableFiles: Bool, + block: @escaping (CollectedLinter) async -> Void) { self.paths = resolveParamsFiles(args: paths) self.action = action self.useSTDIN = useSTDIN diff --git a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift index 83ab869e2f..8d4aa43cb5 100644 --- a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift @@ -124,7 +124,8 @@ final class CollectingRuleTests: SwiftLintTestCase { return [] } - func correct(file: SwiftLintFile, collectedInfo: [SwiftLintFile: String], + func correct(file: SwiftLintFile, + collectedInfo: [SwiftLintFile: String], compilerArguments _: [String]) -> [Correction] { collectedInfo[file] == "baz" ? [Correction(ruleDescription: Spec.description, location: Location(file: file, byteOffset: 2))] diff --git a/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift index 2a4bc69b93..30f3167966 100644 --- a/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift @@ -4,8 +4,10 @@ import XCTest private let fixturesDirectory = "\(TestResources.path)/FileNameRuleFixtures" final class FileNameRuleTests: SwiftLintTestCase { - private func validate(fileName: String, excludedOverride: [String]? = nil, - prefixPattern: String? = nil, suffixPattern: String? = nil, + private func validate(fileName: String, + excludedOverride: [String]? = nil, + prefixPattern: String? = nil, + suffixPattern: String? = nil, nestedTypeSeparator: String? = nil) throws -> [StyleViolation] { let file = SwiftLintFile(path: fixturesDirectory.stringByAppendingPathComponent(fileName))! let rule: FileNameRule diff --git a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift index 311e145e36..3191a6a9f1 100644 --- a/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift +++ b/Tests/SwiftLintFrameworkTests/LinterCacheTests.swift @@ -77,8 +77,11 @@ final class LinterCacheTests: SwiftLintTestCase { CacheTestHelper(dict: dict, cache: cache) } - private func cacheAndValidate(violations: [StyleViolation], forFile: String, configuration: Configuration, - file: StaticString = #filePath, line: UInt = #line) { + private func cacheAndValidate(violations: [StyleViolation], + forFile: String, + configuration: Configuration, + file: StaticString = #filePath, + line: UInt = #line) { cache.cache(violations: violations, forFile: forFile, configuration: configuration) cache = cache.flushed() XCTAssertEqual(cache.violations(forFile: forFile, configuration: configuration)!, @@ -86,7 +89,8 @@ final class LinterCacheTests: SwiftLintTestCase { } private func cacheAndValidateNoViolationsTwoFiles(configuration: Configuration, - file: StaticString = #filePath, line: UInt = #line) { + file: StaticString = #filePath, + line: UInt = #line) { let (file1, file2) = ("file1.swift", "file2.swift") // swiftlint:disable:next force_cast let fileManager = cache.fileManager as! TestFileManager @@ -96,8 +100,10 @@ final class LinterCacheTests: SwiftLintTestCase { cacheAndValidate(violations: [], forFile: file2, configuration: configuration, file: file, line: line) } - private func validateNewConfigDoesntHitCache(dict: [String: Any], initialConfig: Configuration, - file: StaticString = #filePath, line: UInt = #line) throws { + private func validateNewConfigDoesntHitCache(dict: [String: Any], + initialConfig: Configuration, + file: StaticString = #filePath, + line: UInt = #line) throws { let newConfig = try Configuration(dict: dict) let (file1, file2) = ("file1.swift", "file2.swift") diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index c79a9d5bf6..5418b7377e 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -60,7 +60,8 @@ public extension Configuration { } } -public func violations(_ example: Example, config inputConfig: Configuration = Configuration.default, +public func violations(_ example: Example, + config inputConfig: Configuration = Configuration.default, requiresFileOnDisk: Bool = false) -> [StyleViolation] { SwiftLintFile.clearCaches() let config = inputConfig.applyingConfiguration(from: example) @@ -264,7 +265,8 @@ private extension String { } } -public func makeConfig(_ ruleConfiguration: Any?, _ identifier: String, +public func makeConfig(_ ruleConfiguration: Any?, + _ identifier: String, skipDisableCommandTests: Bool = false) -> Configuration? { let superfluousDisableCommandRuleIdentifier = SuperfluousDisableCommandRule.description.identifier let identifiers: Set = skipDisableCommandTests ? [identifier] @@ -433,8 +435,10 @@ public extension XCTestCase { } } - func verifyCorrections(_ ruleDescription: RuleDescription, config: Configuration, - disableCommands: [String], testMultiByteOffsets: Bool, + func verifyCorrections(_ ruleDescription: RuleDescription, + config: Configuration, + disableCommands: [String], + testMultiByteOffsets: Bool, parserDiagnosticsDisabledForTests: Bool = true) { let ruleDescription = ruleDescription.focused() @@ -459,8 +463,10 @@ public extension XCTestCase { } } - private func verifyExamples(triggers: [Example], nonTriggers: [Example], - configuration config: Configuration, requiresFileOnDisk: Bool) { + private func verifyExamples(triggers: [Example], + nonTriggers: [Example], + configuration config: Configuration, + requiresFileOnDisk: Bool) { // Non-triggering examples don't violate for nonTrigger in nonTriggers { let unexpectedViolations = violations(nonTrigger, config: config, From 238415b4f732d13b5d0b284ba049d0847875860a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 20 Jul 2024 16:24:17 +0200 Subject: [PATCH 118/265] Place corrections optionally into violations (#5680) This avoids maintaining two lists of objects. --- .../PrivateOverFilePrivateRule.swift | 6 +- .../RedundantTypeAnnotationRule.swift | 14 ++-- .../Rules/Lint/UnusedParameterRule.swift | 31 ++++---- .../Rules/Style/ImplicitReturnRule.swift | 6 +- .../NonOverridableClassDeclarationRule.swift | 14 ++-- .../Rules/Style/OpeningBraceRule.swift | 72 +++++++------------ .../PreferSelfInStaticReferencesRule.swift | 6 +- .../Style/RedundantSelfInClosureRule.swift | 10 +-- .../Style/ReturnArrowWhitespaceRule.swift | 25 +++---- .../SwiftSyntaxCorrectableRule.swift | 4 +- .../Protocols/SwiftSyntaxRule.swift | 51 +++++++++++-- .../Visitors/ViolationsSyntaxVisitor.swift | 27 +------ 12 files changed, 123 insertions(+), 143 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift index 14d2187300..146fb79455 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift @@ -113,9 +113,9 @@ private extension PrivateOverFilePrivateRule { private func visit(withModifier node: some WithModifiersSyntax) { if let modifier = node.modifiers.first(where: { $0.name.tokenKind == .keyword(.fileprivate) }) { - violations.append(modifier.positionAfterSkippingLeadingTrivia) - violationCorrections.append( - ViolationCorrection( + violations.append( + at: modifier.positionAfterSkippingLeadingTrivia, + correction: .init( start: modifier.positionAfterSkippingLeadingTrivia, end: modifier.endPositionBeforeTrailingTrivia, replacement: "private" diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index f13e745de4..019ff40ac0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -203,12 +203,14 @@ private extension RedundantTypeAnnotationRule { guard isLiteralRedundant || initializer.hasRedundant(type: type.type) else { return } - violations.append(type.positionAfterSkippingLeadingTrivia) - violationCorrections.append(ViolationCorrection( - start: type.position, - end: type.endPositionBeforeTrailingTrivia, - replacement: "" - )) + violations.append( + at: type.positionAfterSkippingLeadingTrivia, + correction: .init( + start: type.position, + end: type.endPositionBeforeTrailingTrivia, + replacement: "" + ) + ) } } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift index f13b9806a9..70cfe125b3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedParameterRule.swift @@ -144,19 +144,8 @@ private extension UnusedParameterRule { override func visitPost(_ node: CodeBlockItemListSyntax) { let declarations = scope.peek() ?? [] for declaration in declarations.reversed() where !referencedDeclarations.contains(declaration) { - // Violation - guard case let .parameter(name) = declaration else { - continue - } - let violation = ReasonedRuleViolation( - position: name.positionAfterSkippingLeadingTrivia, - reason: "Parameter '\(name.text)' is unused; consider removing or replacing it with '_'", - severity: configuration.severity - ) - violations.append(violation) - - // Correction - guard let previousToken = name.previousToken(viewMode: .sourceAccurate) else { + guard case let .parameter(name) = declaration, + let previousToken = name.previousToken(viewMode: .sourceAccurate) else { continue } let startPosReplacement = @@ -167,12 +156,16 @@ private extension UnusedParameterRule { } else { (name.positionAfterSkippingLeadingTrivia, name.text + " _") } - let correction = ViolationCorrection( - start: startPosReplacement.0, - end: name.endPositionBeforeTrailingTrivia, - replacement: startPosReplacement.1 - ) - violationCorrections.append(correction) + violations.append(.init( + position: name.positionAfterSkippingLeadingTrivia, + reason: "Parameter '\(name.text)' is unused; consider removing or replacing it with '_'", + severity: configuration.severity, + correction: .init( + start: startPosReplacement.0, + end: name.endPositionBeforeTrailingTrivia, + replacement: startPosReplacement.1 + ) + )) } super.visitPost(node) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRule.swift index 236280e18a..f58d9db366 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ImplicitReturnRule.swift @@ -66,9 +66,9 @@ private extension ImplicitReturnRule { return } let returnKeyword = returnStmt.returnKeyword - violations.append(returnKeyword.positionAfterSkippingLeadingTrivia) - violationCorrections.append( - ViolationCorrection( + violations.append( + at: returnKeyword.positionAfterSkippingLeadingTrivia, + correction: .init( start: returnKeyword.positionAfterSkippingLeadingTrivia, end: returnKeyword.endPositionBeforeTrailingTrivia .advanced(by: returnStmt.expression == nil ? 0 : 1), diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift index 31355fa784..a4ede58399 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/NonOverridableClassDeclarationRule.swift @@ -127,20 +127,18 @@ private extension NonOverridableClassDeclarationRule { inFinalClass || modifiers.contains(keyword: .private) else { return } - violations.append(ReasonedRuleViolation( + violations.append(.init( position: classKeyword.positionAfterSkippingLeadingTrivia, reason: inFinalClass - ? "Class \(types) in final classes should themselves be final" - : "Private class methods and properties should be declared final", - severity: configuration.severity - )) - violationCorrections.append( - ViolationCorrection( + ? "Class \(types) in final classes should themselves be final" + : "Private class methods and properties should be declared final", + severity: configuration.severity, + correction: .init( start: classKeyword.positionAfterSkippingLeadingTrivia, end: classKeyword.endPositionBeforeTrailingTrivia, replacement: configuration.finalClassModifier.rawValue ) - ) + )) } } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index ba36909ea8..f1508c333f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -22,144 +22,125 @@ private extension OpeningBraceRule { override func visitPost(_ node: ActorDeclSyntax) { let body = node.memberBlock if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: ClassDeclSyntax) { let body = node.memberBlock if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: EnumDeclSyntax) { let body = node.memberBlock if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: ExtensionDeclSyntax) { let body = node.memberBlock if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: ProtocolDeclSyntax) { let body = node.memberBlock if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: StructDeclSyntax) { let body = node.memberBlock if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: CatchClauseSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: DeferStmtSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: DoStmtSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: ForStmtSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: GuardStmtSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: IfExprSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } if case let .codeBlock(body) = node.elseBody, let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: RepeatStmtSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: WhileStmtSyntax) { let body = node.body if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: SwitchExprSyntax) { if let correction = node.violationCorrection(locationConverter) { - violations.append(node.openingPosition) - violationCorrections.append(correction) + violations.append(at: node.openingPosition, correction: correction) } } override func visitPost(_ node: AccessorDeclSyntax) { if let body = node.body, let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: PatternBindingSyntax) { if let body = node.accessorBlock, let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } override func visitPost(_ node: PrecedenceGroupDeclSyntax) { if let correction = node.violationCorrection(locationConverter) { - violations.append(node.openingPosition) - violationCorrections.append(correction) + violations.append(at: node.openingPosition, correction: correction) } } @@ -175,8 +156,7 @@ private extension OpeningBraceRule { node.keyPathInParent != \FunctionCallExprSyntax.calledExpression, let correction = node.violationCorrection(locationConverter) { // Trailing closure - violations.append(node.openingPosition) - violationCorrections.append(correction) + violations.append(at: node.openingPosition, correction: correction) } } @@ -188,8 +168,7 @@ private extension OpeningBraceRule { return } if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } @@ -201,8 +180,7 @@ private extension OpeningBraceRule { return } if let correction = body.violationCorrection(locationConverter) { - violations.append(body.openingPosition) - violationCorrections.append(correction) + violations.append(at: body.openingPosition, correction: correction) } } @@ -219,6 +197,8 @@ private extension OpeningBraceRule { } private extension BracedSyntax { + typealias ViolationCorrection = ReasonedRuleViolation.ViolationCorrection + var openingPosition: AbsolutePosition { leftBrace.positionAfterSkippingLeadingTrivia } @@ -230,7 +210,7 @@ private extension BracedSyntax { let leftBraceLocation = leftBrace.startLocation(converter: locationConverter) let violation = ViolationCorrection( start: previousToken.endPositionBeforeTrailingTrivia, - end: leftBrace.positionAfterSkippingLeadingTrivia, + end: openingPosition, replacement: " " ) if previousLocation.line != leftBraceLocation.line { @@ -246,7 +226,7 @@ private extension BracedSyntax { let comment = triviaBetween.description.trimmingTrailingCharacters(in: .whitespaces) return ViolationCorrection( start: previousToken.endPositionBeforeTrailingTrivia + SourceLength(of: comment), - end: leftBrace.positionAfterSkippingLeadingTrivia, + end: openingPosition, replacement: " " ) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift index 0bae82b4bd..c9b9e62b65 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/PreferSelfInStaticReferencesRule.swift @@ -214,9 +214,9 @@ private extension PreferSelfInStaticReferencesRule { private func addViolation(on node: TokenSyntax) { if let parentName = parentDeclScopes.peek()?.parentName, node.tokenKind == .identifier(parentName) { - violations.append(node.positionAfterSkippingLeadingTrivia) - violationCorrections.append( - ViolationCorrection( + violations.append( + at: node.positionAfterSkippingLeadingTrivia, + correction: .init( start: node.positionAfterSkippingLeadingTrivia, end: node.endPositionBeforeTrailingTrivia, replacement: "Self" diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift index f4ec12f337..17dde72a66 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/RedundantSelfInClosureRule.swift @@ -79,9 +79,8 @@ private extension RedundantSelfInClosureRule { functionCallType: activeFunctionCallType, selfCaptureKind: activeSelfCaptureKind, scope: scope - ).walk(tree: node.statements, handler: \.violationCorrections) - violations.append(contentsOf: localViolationCorrections.map(\.start)) - violationCorrections.append(contentsOf: localViolationCorrections) + ).walk(tree: node.statements, handler: \.violations) + violations.append(contentsOf: localViolationCorrections) selfCaptures.pop() } @@ -137,8 +136,9 @@ private class ExplicitSelfVisitor: DeclaredIde override func visitPost(_ node: MemberAccessExprSyntax) { if !hasSeenDeclaration(for: node.declName.baseName.text), node.isBaseSelf, isSelfRedundant { - violationCorrections.append( - ViolationCorrection( + violations.append( + at: node.positionAfterSkippingLeadingTrivia, + correction: .init( start: node.positionAfterSkippingLeadingTrivia, end: node.period.endPositionBeforeTrailingTrivia, replacement: "" diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift index ac292aa644..7248f2ff24 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ReturnArrowWhitespaceRule.swift @@ -57,36 +57,27 @@ struct ReturnArrowWhitespaceRule: SwiftSyntaxCorrectableRule { private extension ReturnArrowWhitespaceRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionTypeSyntax) { - guard let violation = node.returnClause.arrow.arrowViolation else { - return + if let violation = node.returnClause.arrow.arrowViolation { + violations.append(violation) } - - violations.append(violation.start) - violationCorrections.append(violation) } override func visitPost(_ node: FunctionSignatureSyntax) { - guard let output = node.returnClause, let violation = output.arrow.arrowViolation else { - return + if let output = node.returnClause, let violation = output.arrow.arrowViolation { + violations.append(violation) } - - violations.append(violation.start) - violationCorrections.append(violation) } override func visitPost(_ node: ClosureSignatureSyntax) { - guard let output = node.returnClause, let violation = output.arrow.arrowViolation else { - return + if let output = node.returnClause, let violation = output.arrow.arrowViolation { + violations.append(violation) } - - violations.append(violation.start) - violationCorrections.append(violation) } } } private extension TokenSyntax { - var arrowViolation: ViolationCorrection? { + var arrowViolation: ReasonedRuleViolation? { guard let previousToken = previousToken(viewMode: .sourceAccurate), let nextToken = nextToken(viewMode: .sourceAccurate) else { return nil @@ -119,6 +110,6 @@ private extension TokenSyntax { return nil } - return ViolationCorrection(start: start, end: end, replacement: correction) + return .init(position: start, correction: .init(start: start, end: end, replacement: correction)) } } diff --git a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift index 2ae76d303d..19c15d1186 100644 --- a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift +++ b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift @@ -40,7 +40,9 @@ public extension SwiftSyntaxCorrectableRule { } // There is no rewriter. Falling back to the correction ranges collected by the visitor (if any). - let violationCorrections = makeVisitor(file: file).walk(tree: syntaxTree, handler: \.violationCorrections) + let violationCorrections = makeVisitor(file: file) + .walk(tree: syntaxTree, handler: \.violations) + .compactMap(\.correction) if violationCorrections.isEmpty { return [] } diff --git a/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift b/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift index 1a47105905..a7e43549a6 100644 --- a/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift +++ b/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift @@ -75,22 +75,53 @@ public extension SwiftSyntaxRule { /// A violation produced by `ViolationsSyntaxVisitor`s. public struct ReasonedRuleViolation: Comparable, Hashable { + /// The correction of a violation that is basically the violation's range in the source code and a + /// replacement for this range that would fix the violation. + public struct ViolationCorrection: Hashable { + /// Start position of the violation range. + let start: AbsolutePosition + /// End position of the violation range. + let end: AbsolutePosition + /// Replacement for the violating range. + let replacement: String + + /// Create a ``ViolationCorrection``. + /// - Parameters: + /// - start: Start position of the violation range. + /// - end: End position of the violation range. + /// - replacement: Replacement for the violating range. + public init(start: AbsolutePosition, end: AbsolutePosition, replacement: String) { + self.start = start + self.end = end + self.replacement = replacement + } + } + /// The violation's position. public let position: AbsolutePosition /// A specific reason for the violation. public let reason: String? /// The violation's severity. public let severity: ViolationSeverity? + /// An optional correction of the violation to be used in rewriting (see ``SwiftSyntaxCorrectableRule``). Can be + /// left unset when creating a violation, especially if the rule is not correctable or provides a custom rewriter. + public let correction: ViolationCorrection? /// Creates a `ReasonedRuleViolation`. /// - /// - parameter position: The violations position in the analyzed source file. - /// - parameter reason: The reason for the violation if different from the rule's description. - /// - parameter severity: The severity of the violation if different from the rule's default configured severity. - public init(position: AbsolutePosition, reason: String? = nil, severity: ViolationSeverity? = nil) { + /// - Parameters: + /// - position: The violations position in the analyzed source file. + /// - reason: The reason for the violation if different from the rule's description. + /// - severity: The severity of the violation if different from the rule's default configured severity. + /// - correction: An optional correction of the violation to be used in rewriting. + public init(position: AbsolutePosition, + reason: String? = nil, + severity: ViolationSeverity? = nil, + correction: ViolationCorrection? = nil) { self.position = position self.reason = reason self.severity = severity + self.correction = correction } public static func < (lhs: Self, rhs: Self) -> Bool { @@ -101,14 +132,22 @@ public struct ReasonedRuleViolation: Comparable, Hashable { /// Extension for arrays of `ReasonedRuleViolation`s that provides the automatic conversion of /// `AbsolutePosition`s into `ReasonedRuleViolation`s (without a specific reason). public extension Array where Element == ReasonedRuleViolation { - /// Append a minimal violation for the specified position. + /// Add a violation at the specified position using the default description and severity. /// /// - parameter position: The position for the violation to append. mutating func append(_ position: AbsolutePosition) { append(ReasonedRuleViolation(position: position)) } - /// Append minimal violations for the specified positions. + /// Add a violation and the correction at the specified position using the default description and severity. + /// + /// - parameter position: The position for the violation to append. + /// - parameter correction: An optional correction to be applied when running with `--fix`. + mutating func append(at position: AbsolutePosition, correction: ReasonedRuleViolation.ViolationCorrection? = nil) { + append(ReasonedRuleViolation(position: position, correction: correction)) + } + + /// Add violations for the specified positions using the default description and severity. /// /// - parameter positions: The positions for the violations to append. mutating func append(contentsOf positions: [AbsolutePosition]) { diff --git a/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift b/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift index 1835e903f0..9551411ce2 100644 --- a/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift +++ b/Source/SwiftLintCore/Visitors/ViolationsSyntaxVisitor.swift @@ -11,7 +11,7 @@ open class ViolationsSyntaxVisitor: SyntaxVisi public lazy var locationConverter = file.locationConverter /// Initializer for a ``ViolationsSyntaxVisitor``. - /// + /// /// - Parameters: /// - configuration: Configuration of a rule. /// - file: File from which the syntax tree stems from. @@ -24,9 +24,6 @@ open class ViolationsSyntaxVisitor: SyntaxVisi /// Positions in a source file where violations should be reported. public var violations: [ReasonedRuleViolation] = [] - /// Ranges of violations to be used in rewriting (see ``SwiftSyntaxCorrectableRule``). It is not mandatory to fill - /// this list while traversing the AST, especially not if the rule is not correctable or provides a custom rewriter. - public var violationCorrections = [ViolationCorrection]() /// List of declaration types that shall be skipped while traversing the AST. open var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [] } @@ -56,28 +53,6 @@ open class ViolationsSyntaxVisitor: SyntaxVisi } } -/// The correction of a violation that is basically the violation's range in the source code and a -/// replacement for this range that would fix the violation. -public struct ViolationCorrection { - /// Start position of the violation range. - public let start: AbsolutePosition - /// End position of the violation range. - let end: AbsolutePosition - /// Replacement for the violating range. - let replacement: String - - /// Create a ``ViolationCorrection``. - /// - Parameters: - /// - start: Start position of the violation range. - /// - end: End position of the violation range. - /// - replacement: Replacement for the violating range. - public init(start: AbsolutePosition, end: AbsolutePosition, replacement: String) { - self.start = start - self.end = end - self.replacement = replacement - } -} - public extension Array where Element == any DeclSyntaxProtocol.Type { /// All visitable declaration syntax types. static let all: Self = [ From 9f8a3f56622ded0d9db5bce359648dbe844fe386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 20 Jul 2024 17:22:32 +0200 Subject: [PATCH 119/265] Fix some typos (#5683) --- .../DiscardedNotificationCenterObserverRule.swift | 4 ++-- .../Rules/Style/OpeningBraceRuleExamples.swift | 6 +++--- .../Protocols/SwiftSyntaxCorrectableRule.swift | 2 +- Tests/SwiftLintTestHelpers/TestHelpers.swift | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift index 97bcde86ad..5b42b2a113 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DiscardedNotificationCenterObserverRule.swift @@ -38,8 +38,8 @@ struct DiscardedNotificationCenterObserverRule: OptInRule { obs.append(nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })) """), Example(""" - func foo(_ notif: Any) { - obs.append(notif) + func foo(_ notify: Any) { + obs.append(notify) } foo(nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })) """), diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index 37d05fb1b2..f95befcdb8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -198,10 +198,10 @@ struct OpeningBraceRuleExamples { let bar: String? = "bar" if - let foooo = foo, - let barrr = bar + let foo = foo, + let bar = bar ↓{ - print(foooo + barrr) + print(foo + bar) } } """), diff --git a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift index 19c15d1186..d8961d2223 100644 --- a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift +++ b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift @@ -92,7 +92,7 @@ open class ViolationsSyntaxRewriter: SyntaxRew /// Positions in a source file where corrections were applied. public var correctionPositions = [AbsolutePosition]() - /// Initilizer for a ``ViolationsSyntaxRewriter``. + /// Initializer for a ``ViolationsSyntaxRewriter``. /// /// - Parameters: /// - configuration: Configuration of a rule. diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index 5418b7377e..06dc892cd0 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -75,8 +75,8 @@ public func violations(_ example: Example, let file = SwiftLintFile.testFile(withContents: stringStrippingMarkers.code, persistToDisk: true) let storage = RuleStorage() - let collecter = Linter(file: file, configuration: config, compilerArguments: file.makeCompilerArguments()) - let linter = collecter.collect(into: storage) + let collector = Linter(file: file, configuration: config, compilerArguments: file.makeCompilerArguments()) + let linter = collector.collect(into: storage) return linter.styleViolations(using: storage).withoutFiles() } @@ -212,8 +212,8 @@ private extension Configuration { let includeCompilerArguments = self.rules.contains(where: { $0 is any AnalyzerRule }) let compilerArguments = includeCompilerArguments ? file.makeCompilerArguments() : [] let storage = RuleStorage() - let collecter = Linter(file: file, configuration: self, compilerArguments: compilerArguments) - let linter = collecter.collect(into: storage) + let collector = Linter(file: file, configuration: self, compilerArguments: compilerArguments) + let linter = collector.collect(into: storage) let corrections = linter.correct(using: storage).sorted { $0.location < $1.location } if expectedLocations.isEmpty { XCTAssertEqual( @@ -420,14 +420,14 @@ public extension XCTestCase { .map { $0.with(code: command + $0.code) } for trigger in disabledTriggers { - let violationsPartionedByType = makeViolations(trigger) + let violationsPartitionedByType = makeViolations(trigger) .partitioned { $0.ruleIdentifier == SuperfluousDisableCommandRule.description.identifier } - XCTAssert(violationsPartionedByType.first.isEmpty, + XCTAssert(violationsPartitionedByType.first.isEmpty, "Violation(s) still triggered although rule was disabled", file: trigger.file, line: trigger.line) - XCTAssert(violationsPartionedByType.second.isEmpty, + XCTAssert(violationsPartitionedByType.second.isEmpty, "Disable command was superfluous since no violations(s) triggered", file: trigger.file, line: trigger.line) From cb0f5ab0074caa62960a69281304a2ae14cadd45 Mon Sep 17 00:00:00 2001 From: Hayashi Tatsuya <62803132+swiftty@users.noreply.github.com> Date: Sun, 21 Jul 2024 00:36:24 +0900 Subject: [PATCH 120/265] Verify and document fixed `opening_brace` correction (#5620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 6 ++++++ .../Style/OpeningBraceRuleExamples.swift | 20 +++++++++++++++++++ Tests/SwiftLintTestHelpers/TestHelpers.swift | 10 +++++++--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb32d2899b..968431bc00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -107,6 +107,12 @@ [Martin Redington](https://github.com/mildm8nnered) [#5660](https://github.com/realm/SwiftLint/issues/5660) +* Fix `opening_brace` correction and make sure that disable commands + are taken into account before applying a fix. + [swiftty](https://github.com/swiftty) + [SimplyDanny](https://github.com/SimplyDanny) + [#5598](https://github.com/realm/SwiftLint/issues/5598) + ## 0.55.1: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index f95befcdb8..19cc630465 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -546,5 +546,25 @@ struct OpeningBraceRuleExamples { return } """), + // https://github.com/realm/SwiftLint/issues/5598 + Example(""" + func foo() { + if q1, q2 + { + do1() + } else if q3, q4 + { + do2() + } + } + """): Example(""" + func foo() { + if q1, q2 { + do1() + } else if q3, q4 { + do2() + } + } + """), ] } diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index 06dc892cd0..032fad3c36 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -216,9 +216,13 @@ private extension Configuration { let linter = collector.collect(into: storage) let corrections = linter.correct(using: storage).sorted { $0.location < $1.location } if expectedLocations.isEmpty { - XCTAssertEqual( - corrections.count, before.code != expected.code ? 1 : 0, #function + ".expectedLocationsEmpty", - file: before.file, line: before.line) + XCTAssertGreaterThanOrEqual( + corrections.count, + before.code != expected.code ? 1 : 0, + #function + ".expectedLocationsEmpty", + file: before.file, + line: before.line + ) } else { XCTAssertEqual( corrections.count, From b63807de6d15a55c0746dacaf96ac2387d9803ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 20 Jul 2024 19:11:55 +0200 Subject: [PATCH 121/265] Fail in debug builds if a rule produces corrections while not being correctable (#5684) --- Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift b/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift index a7e43549a6..32b691aa61 100644 --- a/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift +++ b/Source/SwiftLintCore/Protocols/SwiftSyntaxRule.swift @@ -46,8 +46,13 @@ public extension SwiftSyntaxRule { return [] } - return makeVisitor(file: file) + let violations = makeVisitor(file: file) .walk(tree: syntaxTree, handler: \.violations) + assert( + violations.allSatisfy { $0.correction == nil || self is any SwiftSyntaxCorrectableRule }, + "\(Self.self) produced corrections without being correctable." + ) + return violations .sorted() .map { makeViolation(file: file, violation: $0) } } From 2cc1acb6838a3d61d4de8afd58c72803e2488c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 20 Jul 2024 23:22:54 +0200 Subject: [PATCH 122/265] Check at the violation position if a correction can be applied (#5682) --- .../Style/OpeningBraceRuleExamples.swift | 15 ++++++++++++ .../SwiftSyntaxCorrectableRule.swift | 23 ++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index 19cc630465..e41dc09977 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -566,5 +566,20 @@ struct OpeningBraceRuleExamples { } } """), + Example(""" + if + "test".isEmpty + // swiftlint:disable:next opening_brace + { + // code here + } + """): Example(""" + if + "test".isEmpty + // swiftlint:disable:next opening_brace + { + // code here + } + """), ] } diff --git a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift index d8961d2223..f977d9b050 100644 --- a/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift +++ b/Source/SwiftLintCore/Protocols/SwiftSyntaxCorrectableRule.swift @@ -24,7 +24,7 @@ public extension SwiftSyntaxCorrectableRule { if let rewriter = makeRewriter(file: file) { let newTree = rewriter.visit(syntaxTree) let positions = rewriter.correctionPositions - if positions.isEmpty { + guard positions.isNotEmpty else { return [] } let corrections = positions @@ -40,25 +40,32 @@ public extension SwiftSyntaxCorrectableRule { } // There is no rewriter. Falling back to the correction ranges collected by the visitor (if any). - let violationCorrections = makeVisitor(file: file) + let violations = makeVisitor(file: file) .walk(tree: syntaxTree, handler: \.violations) - .compactMap(\.correction) - if violationCorrections.isEmpty { + guard violations.isNotEmpty else { return [] } + + let locationConverter = file.locationConverter + let disabledRegions = file.regions() + .filter { $0.areRulesDisabled(ruleIDs: Self.description.allIdentifiers) } + .compactMap { $0.toSourceRange(locationConverter: locationConverter) } + typealias CorrectionRange = (range: NSRange, correction: String) - let correctionRanges = violationCorrections + let correctionRanges = violations + .filter { !$0.position.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) } + .compactMap(\.correction) .compactMap { correction in file.stringView.NSRange(start: correction.start, end: correction.end).map { range in CorrectionRange(range: range, correction: correction.replacement) } } - .filter { (correctionRange: CorrectionRange) in - file.ruleEnabled(violatingRange: correctionRange.range, for: self) != nil - } .sorted { (lhs: CorrectionRange, rhs: CorrectionRange) -> Bool in lhs.range.location > rhs.range.location } + guard correctionRanges.isNotEmpty else { + return [] + } var corrections = [Correction]() var contents = file.contents From ffed4552d7291f7b32bcf4f56f167af10f8dfc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sun, 21 Jul 2024 13:43:17 +0200 Subject: [PATCH 123/265] Document SwiftLintPlugin execution from Script Build Phase (#5677) --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 0da7a7e5fe..5a7eb86ed7 100644 --- a/README.md +++ b/README.md @@ -332,6 +332,27 @@ else fi ``` +If you're using the SwiftLintPlugin in a Swift package, +you may refer to the `swiftlint` executable in the +following way: + +```bash +SWIFT_PACKAGE_DIR="${BUILD_DIR%Build/*}SourcePackages/artifacts" +SWIFTLINT_CMD=$(ls "$SWIFT_PACKAGE_DIR"/swiftlintplugins/SwiftLintBinary/SwiftLintBinary.artifactbundle/swiftlint-*/bin/swiftlint | head -n 1) + +if test -f "$SWIFTLINT_CMD" 2>&1 +then + "$SWIFTLINT_CMD" +else + echo "warning: `swiftlint` command not found - See https://github.com/realm/SwiftLint#installation for installation instructions." +fi +``` + +> [!NOTE] +> The `SWIFTLINT_CMD` path uses the default Xcode configuration and has been +> tested on Xcode 15/16. In case of another configuration (e.g. a custom +> Swift package path), please adapt the values accordingly. + > [!TIP] > Uncheck `Based on dependency analysis` to run `swiftlint` on all incremental > builds, suppressing the unspecified outputs warning. From a14c4a994e4a19ab97145a235d0b551f9e6b4f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 21 Jul 2024 22:47:34 +0200 Subject: [PATCH 124/265] Improve test coverage slightly (#5687) --- .../Rules/Idiomatic/ExplicitTopLevelACLRule.swift | 14 ++++++++++---- .../Rules/Idiomatic/OneDelarationPerFileRule.swift | 2 +- .../Idiomatic/PrivateOverFilePrivateRule.swift | 9 +++++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift index a1f5a64487..d85c33c66a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ExplicitTopLevelACLRule.swift @@ -12,18 +12,24 @@ struct ExplicitTopLevelACLRule: OptInRule { nonTriggeringExamples: [ Example("internal enum A {}"), Example("public final class B {}"), - Example("private struct C {}"), + Example(""" + private struct S1 { + struct S2 {} + } + """), Example("internal enum A { enum B {} }"), - Example("internal final class Foo {}"), - Example("internal\nclass Foo {}"), + Example("internal final actor Foo {}"), + Example("internal typealias Foo = Bar"), Example("internal func a() {}"), Example("extension A: Equatable {}"), Example("extension A {}"), + Example("f { func f() {} }", excludeFromDocumentation: true), + Example("do { func f() {} }", excludeFromDocumentation: true), ], triggeringExamples: [ Example("↓enum A {}"), Example("final ↓class B {}"), - Example("↓struct C {}"), + Example("↓protocol P {}"), Example("↓func a() {}"), Example("internal let a = 0\n↓func b() {}"), ] diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift index 3e691d20c1..02b605aa1d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift @@ -11,7 +11,7 @@ struct OneDelarationPerFileRule: OptInRule { kind: .idiomatic, nonTriggeringExamples: [ Example(""" - class Foo {} + actor Foo {} """), Example(""" class Foo {} diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift index 146fb79455..f0ffcc60b7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift @@ -12,9 +12,10 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule { nonTriggeringExamples: [ Example("extension String {}"), Example("private extension String {}"), - Example("public \n enum MyEnum {}"), + Example("public protocol P {}"), Example("open extension \n String {}"), Example("internal extension String {}"), + Example("package typealias P = Int"), Example(""" extension String { fileprivate func Something(){} @@ -36,7 +37,7 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule { } """), Example(""" - struct Outter { + struct Outer { struct Inter { fileprivate struct Inner {} } @@ -55,6 +56,10 @@ struct PrivateOverFilePrivateRule: SwiftSyntaxCorrectableRule { fileprivate let myInt = 4 } """), + Example(""" + ↓fileprivate func f() {} + ↓fileprivate var x = 0 + """), ], corrections: [ Example("↓fileprivate enum MyEnum {}"): From d46bfcd657ff8957f42b95c00deaf5cab21d27d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 21 Jul 2024 23:20:45 +0200 Subject: [PATCH 125/265] Fix some typos (#5688) --- Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift | 2 +- ...nPerFileRule.swift => OneDeclarationPerFileRule.swift} | 4 ++-- Tests/GeneratedTests/GeneratedTests.swift | 4 ++-- .../ExplicitTypeInterfaceRuleTests.swift | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) rename Source/SwiftLintBuiltInRules/Rules/Idiomatic/{OneDelarationPerFileRule.swift => OneDeclarationPerFileRule.swift} (96%) diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 4766e60c8f..2db9b04f44 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -137,7 +137,7 @@ public let builtInRules: [any Rule.Type] = [ NotificationCenterDetachmentRule.self, NumberSeparatorRule.self, ObjectLiteralRule.self, - OneDelarationPerFileRule.self, + OneDeclarationPerFileRule.self, OpeningBraceRule.self, OperatorFunctionWhitespaceRule.self, OperatorUsageWhitespaceRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDeclarationPerFileRule.swift similarity index 96% rename from Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift rename to Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDeclarationPerFileRule.swift index 02b605aa1d..7094c9b82f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDelarationPerFileRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/OneDeclarationPerFileRule.swift @@ -1,7 +1,7 @@ import SwiftSyntax @SwiftSyntaxRule -struct OneDelarationPerFileRule: OptInRule { +struct OneDeclarationPerFileRule: OptInRule { var configuration = SeverityConfiguration(.warning) static let description = RuleDescription( @@ -40,7 +40,7 @@ struct OneDelarationPerFileRule: OptInRule { ) } -private extension OneDelarationPerFileRule { +private extension OneDeclarationPerFileRule { final class Visitor: ViolationsSyntaxVisitor { private var declarationVisited = false override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { .all } diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 8eb59eed05..84f639a8ff 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -811,9 +811,9 @@ final class ObjectLiteralRuleGeneratedTests: SwiftLintTestCase { } } -final class OneDelarationPerFileRuleGeneratedTests: SwiftLintTestCase { +final class OneDeclarationPerFileRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { - verifyRule(OneDelarationPerFileRule.description) + verifyRule(OneDeclarationPerFileRule.description) } } diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift index 8768283aaf..37d079aa3a 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift @@ -48,7 +48,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { ] let triggeringExamples: [Example] = [ Example("class Foo {\n var ↓myVar = 0\n\n}\n"), - Example("class Foo {\n let ↓mylet = 0\n\n}\n"), + Example("class Foo {\n let ↓myLet = 0\n\n}\n"), Example("class Foo {\n class var ↓myClassVar = 0\n}\n"), ] let description = ExplicitTypeInterfaceRule.description @@ -76,7 +76,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { ] let triggeringExamples: [Example] = [ Example("class Foo {\n var ↓myVar = 0\n\n}\n"), - Example("class Foo {\n let ↓mylet = 0\n\n}\n"), + Example("class Foo {\n let ↓myLet = 0\n\n}\n"), Example("class Foo {\n static var ↓myStaticVar = 0\n}\n"), Example("class Foo {\n class var ↓myClassVar = 0\n}\n"), Example("class Foo {\n let ↓array = [\"foo\", \"bar\"]\n}\n"), @@ -150,7 +150,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { } func testFastEnumerationDeclaration() { - let nonTriggeringExaples = [ + let nonTriggeringExamples = [ Example(""" func foo() { let elements: [Int] = [1, 2] @@ -168,7 +168,7 @@ final class ExplicitTypeInterfaceRuleTests: SwiftLintTestCase { let triggeringExamples = ExplicitTypeInterfaceRule.description.triggeringExamples let description = ExplicitTypeInterfaceRule.description .with(triggeringExamples: triggeringExamples) - .with(nonTriggeringExamples: nonTriggeringExaples) + .with(nonTriggeringExamples: nonTriggeringExamples) verifyRule(description) } From b9f38435de77238e9a2d8921764238f4bc049451 Mon Sep 17 00:00:00 2001 From: Koichiro Ueki <43738558+Ueeek@users.noreply.github.com> Date: Tue, 23 Jul 2024 01:34:20 +0900 Subject: [PATCH 126/265] Make `no_empty_block` rule opt-in and add configurations (#5685) --- CHANGELOG.md | 2 +- .../Rules/Idiomatic/NoEmptyBlockRule.swift | 152 ++++++++++++------ .../NoEmptyBlockConfiguration.swift | 25 +++ .../default_rule_configurations.yml | 1 + .../NoEmptyBlockConfigurationTests.swift | 54 +++++++ 5 files changed, 186 insertions(+), 48 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift create mode 100644 Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 968431bc00..73c18130f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ [Martin Redington](https://github.com/mildm8nnered) [#5552](https://github.com/realm/SwiftLint/issues/5552) -* Add `no_empty_block` default rule to validate that code blocks are not empty. +* Add `no_empty_block` opt-in rule to validate that code blocks are not empty. They should at least contain a comment. [Ueeek](https://github.com/Ueeek) [#5615](https://github.com/realm/SwiftLint/issues/5615) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift index 2ed5b456f1..51efc92461 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift @@ -1,8 +1,9 @@ +import SwiftLintCore import SwiftSyntax @SwiftSyntaxRule -struct NoEmptyBlockRule: Rule { - var configuration = SeverityConfiguration(.warning) +struct NoEmptyBlockRule: OptInRule { + var configuration = NoEmptyBlockConfiguration() static let description = RuleDescription( identifier: "no_empty_block", @@ -11,85 +12,122 @@ struct NoEmptyBlockRule: Rule { kind: .idiomatic, nonTriggeringExamples: [ Example(""" + func f() { + /* do something */ + } + var flag = true { willSet { /* do something */ } } """), + Example(""" - do { - /* do something */ - } catch { - /* do something */ + class Apple { + init() { /* do something */ } + + deinit { /* do something */ } } """), + Example(""" - defer { + for _ in 0..<10 { /* do something */ } + + do { + /* do something */ + } catch { /* do something */ } - """), - Example(""" - deinit { /* do something */ } - """), - Example(""" - for _ in 0..<10 { /* do something */ } - """), - Example(""" + func f() { - /* do something */ + defer { + /* do something */ + } + print("other code") } - """), - Example(""" + if flag { /* do something */ } else { /* do something */ } + + repeat { /* do something */ } while (flag) + + while i < 10 { /* do something */ } """), + Example(""" - init() { /* do something */ } - """), + func f() {} + + var flag = true { + willSet {} + } + """, configuration: ["disabled_block_types": ["function_bodies"]]), + Example(""" - repeat { /* do something */ } while (flag) - """), + class Apple { + init() {} + + deinit {} + } + """, configuration: ["disabled_block_types": ["initializer_bodies"]]), + Example(""" - while i < 10 { /* do something */ } - """), + for _ in 0..<10 {} + + do { + } catch { + } + + func f() { + defer {} + print("other code") + } + + if flag { + } else { + } + + repeat {} while (flag) + + while i < 10 {} + """, configuration: ["disabled_block_types": ["statement_blocks"]]), ], triggeringExamples: [ Example(""" + func f() ↓{} + var flag = true { willSet ↓{} } """), + Example(""" - do ↓{ - } catch ↓{ + class Apple { + init() ↓{} + + deinit ↓{} } """), - Example(""" - defer ↓{} - """), - Example(""" - deinit ↓{} - """), + Example(""" for _ in 0..<10 ↓{} - """), - Example(""" - func f() ↓{} - """), - Example(""" + + do ↓{ + } catch ↓{ + } + + func f() { + defer ↓{} + print("other code") + } + if flag ↓{ } else ↓{ } - """), - Example(""" - init() ↓{} - """), - Example(""" + repeat ↓{} while (flag) - """), - Example(""" + while i < 10 ↓{} """), ] @@ -99,16 +137,36 @@ struct NoEmptyBlockRule: Rule { private extension NoEmptyBlockRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: CodeBlockSyntax) { - // No need to show a warning since Empty Block of `guard` is compile error. - guard node.parent?.kind != .guardStmt else { return } + if let codeBlockType = node.codeBlockType, configuration.enabledBlockTypes.contains(codeBlockType) { + validate(node: node) + } + } + func validate(node: CodeBlockSyntax) { guard node.statements.isEmpty, !node.leftBrace.trailingTrivia.containsComments, !node.rightBrace.leadingTrivia.containsComments else { return } - violations.append(node.leftBrace.positionAfterSkippingLeadingTrivia) } } } + +private extension CodeBlockSyntax { + var codeBlockType: NoEmptyBlockConfiguration.CodeBlockType? { + switch parent?.kind { + case .functionDecl, .accessorDecl: + .functionBodies + case .initializerDecl, .deinitializerDecl: + .initializerBodies + case .forStmt, .doStmt, .whileStmt, .repeatStmt, .ifExpr, .catchClause, .deferStmt: + .statementBlocks + case .guardStmt: + // No need to handle this case since Empty Block of `guard` is compile error. + nil + default: + nil + } + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift new file mode 100644 index 0000000000..1e8625c4bc --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift @@ -0,0 +1,25 @@ +import SwiftLintCore + +@AutoApply +struct NoEmptyBlockConfiguration: SeverityBasedRuleConfiguration { + typealias Parent = NoEmptyBlockRule + + @MakeAcceptableByConfigurationElement + enum CodeBlockType: String, CaseIterable { + case functionBodies = "function_bodies" + case initializerBodies = "initializer_bodies" + case statementBlocks = "statement_blocks" + + static let all = Set(allCases) + } + + @ConfigurationElement(key: "severity") + private(set) var severityConfiguration = SeverityConfiguration(.warning) + + @ConfigurationElement(key: "disabled_block_types") + private(set) var disabledBlockTypes: [CodeBlockType] = [] + + var enabledBlockTypes: Set { + CodeBlockType.all.subtracting(disabledBlockTypes) + } +} diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 653b753cf5..990c7b2e64 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -336,6 +336,7 @@ nimble_operator: severity: warning no_empty_block: severity: warning + disabled_block_types: [] no_extension_access_modifier: severity: error no_fallthrough_only: diff --git a/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift new file mode 100644 index 0000000000..39168dfd30 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift @@ -0,0 +1,54 @@ +@testable import SwiftLintBuiltInRules +@testable import SwiftLintCore +import XCTest + +final class NoEmptyBlockConfigurationTests: SwiftLintTestCase { + func testDefaultConfiguration() { + let config = NoEmptyBlockConfiguration() + XCTAssertEqual(config.severityConfiguration.severity, .warning) + XCTAssertEqual(config.enabledBlockTypes, NoEmptyBlockConfiguration.CodeBlockType.all) + } + + func testApplyingCustomConfiguration() throws { + var config = NoEmptyBlockConfiguration() + try config.apply( + configuration: [ + "severity": "error", + "disabled_block_types": ["function_bodies"], + ] as [String: any Sendable] + ) + XCTAssertEqual(config.severityConfiguration.severity, .error) + XCTAssertEqual(config.enabledBlockTypes, Set([.initializerBodies, .statementBlocks])) + } + + func testInvalidKeyInCustomConfiguration() { + var config = NoEmptyBlockConfiguration() + XCTAssertEqual( + try Issue.captureConsole { try config.apply(configuration: ["invalidKey": "error"]) }, + "warning: Configuration for 'no_empty_block' rule contains the invalid key(s) 'invalidKey'." + ) + } + + func testInvalidTypeOfCustomConfiguration() { + var config = NoEmptyBlockConfiguration() + checkError(Issue.invalidConfiguration(ruleID: NoEmptyBlockRule.description.identifier)) { + try config.apply(configuration: "invalidKey") + } + } + + func testInvalidTypeOfValueInCustomConfiguration() { + var config = NoEmptyBlockConfiguration() + checkError(Issue.invalidConfiguration(ruleID: NoEmptyBlockRule.description.identifier)) { + try config.apply(configuration: ["severity": "foo"]) + } + } + + func testConsoleDescription() throws { + var config = NoEmptyBlockConfiguration() + try config.apply(configuration: ["disabled_block_types": ["initializer_bodies", "statement_blocks"]]) + XCTAssertEqual( + RuleConfigurationDescription.from(configuration: config).oneLiner(), + "severity: warning; disabled_block_types: [initializer_bodies, statement_blocks]" + ) + } +} From 98cf87ab8de65fff7a7a376b9f3e1dbea8af71cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 23 Jul 2024 20:14:29 +0200 Subject: [PATCH 127/265] Rename macros to something more descriptive (#5686) --- .../AttributesConfiguration.swift | 2 +- .../BlanketDisableCommandConfiguration.swift | 2 +- .../CollectionAlignmentConfiguration.swift | 2 +- .../ColonConfiguration.swift | 2 +- .../ComputedAccessorsOrderConfiguration.swift | 4 +-- ...itionalReturnsOnNewlineConfiguration.swift | 2 +- .../CyclomaticComplexityConfiguration.swift | 2 +- .../DiscouragedDirectInitConfiguration.swift | 2 +- .../EmptyCountConfiguration.swift | 2 +- .../ExpiringTodoConfiguration.swift | 2 +- .../ExplicitInitConfiguration.swift | 2 +- .../ExplicitTypeInterfaceConfiguration.swift | 4 +-- .../FileLengthConfiguration.swift | 2 +- .../FileNameConfiguration.swift | 2 +- .../FileNameNoSpaceConfiguration.swift | 2 +- .../FileTypesOrderConfiguration.swift | 4 +-- .../ForWhereConfiguration.swift | 2 +- .../FunctionParameterCountConfiguration.swift | 2 +- .../IdentifierNameConfiguration.swift | 2 +- .../ImplicitReturnConfiguration.swift | 4 +-- ...icitlyUnwrappedOptionalConfiguration.swift | 4 +-- .../InclusiveLanguageConfiguration.swift | 2 +- .../IndentationWidthConfiguration.swift | 2 +- .../LineLengthConfiguration.swift | 2 +- .../ModifierOrderConfiguration.swift | 2 +- .../MultilineArgumentsConfiguration.swift | 4 +-- .../MultilineParametersConfiguration.swift | 2 +- .../NestingConfiguration.swift | 2 +- ...ridableClassDeclarationConfiguration.swift | 4 +-- .../NumberSeparatorConfiguration.swift | 2 +- .../ObjectLiteralConfiguration.swift | 2 +- .../OpeningBraceConfiguration.swift | 2 +- ...OperatorUsageWhitespaceConfiguration.swift | 2 +- .../OverriddenSuperCallConfiguration.swift | 2 +- ...refixedTopLevelConstantConfiguration.swift | 2 +- .../PrivateOutletConfiguration.swift | 2 +- .../PrivateOverFilePrivateConfiguration.swift | 2 +- .../ProhibitedSuperConfiguration.swift | 2 +- ...RedundantTypeAnnotationConfiguration.swift | 2 +- .../RedundantVoidReturnConfiguration.swift | 2 +- .../SelfBindingConfiguration.swift | 2 +- .../ShorthandArgumentConfiguration.swift | 2 +- .../SortedImportsConfiguration.swift | 4 +-- .../StatementPositionConfiguration.swift | 4 +-- .../SwitchCaseAlignmentConfiguration.swift | 2 +- .../TestCaseAccessibilityConfiguration.swift | 2 +- .../TodoConfiguration.swift | 4 +-- .../TrailingClosureConfiguration.swift | 2 +- .../TrailingCommaConfiguration.swift | 2 +- .../TrailingWhitespaceConfiguration.swift | 2 +- .../TypeContentsOrderConfiguration.swift | 4 +-- .../TypeNameConfiguration.swift | 2 +- .../UnitTestConfiguration.swift | 2 +- .../UnneededOverrideRuleConfiguration.swift | 2 +- .../UnusedDeclarationConfiguration.swift | 2 +- .../UnusedImportConfiguration.swift | 2 +- .../UnusedOptionalBindingConfiguration.swift | 2 +- ...WhitespaceClosingBracesConfiguration.swift | 2 +- .../VerticalWhitespaceConfiguration.swift | 2 +- .../XCTSpecificMatcherConfiguration.swift | 4 +-- Source/SwiftLintCore/Helpers/Macros.swift | 29 +++++++++++++++++-- .../Models/ViolationSeverity.swift | 2 +- .../RuleConfigurationMacros.swift | 4 +-- .../SwiftLintCoreMacros.swift | 4 +-- ...ceptableByConfigurationElementTests.swift} | 13 ++++----- ...ests.swift => AutoConfigParserTests.swift} | 16 +++++----- .../RuleConfigurationDescriptionTests.swift | 2 +- 67 files changed, 118 insertions(+), 96 deletions(-) rename Tests/MacroTests/{MakeAcceptableByConfigurationElementTests.swift => AcceptableByConfigurationElementTests.swift} (86%) rename Tests/MacroTests/{AutoApplyTests.swift => AutoConfigParserTests.swift} (96%) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/AttributesConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/AttributesConfiguration.swift index e9a6fe06b9..da8917e26e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/AttributesConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/AttributesConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct AttributesConfiguration: SeverityBasedRuleConfiguration { typealias Parent = AttributesRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift index 66e4284f9c..c960606aa2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/BlanketDisableCommandConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct BlanketDisableCommandConfiguration: SeverityBasedRuleConfiguration { typealias Parent = BlanketDisableCommandRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CollectionAlignmentConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CollectionAlignmentConfiguration.swift index 0838689139..0c2ba8eadd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CollectionAlignmentConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CollectionAlignmentConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct CollectionAlignmentConfiguration: SeverityBasedRuleConfiguration { typealias Parent = CollectionAlignmentRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ColonConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ColonConfiguration.swift index ee0379a0a7..078ecded56 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ColonConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ColonConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ColonConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ColonRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ComputedAccessorsOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ComputedAccessorsOrderConfiguration.swift index 01a3a2e3eb..ce06b9dfa4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ComputedAccessorsOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ComputedAccessorsOrderConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ComputedAccessorsOrderConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ComputedAccessorsOrderRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum Order: String { case getSet = "get_set" case setGet = "set_get" diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ConditionalReturnsOnNewlineConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ConditionalReturnsOnNewlineConfiguration.swift index 2a44156d46..29f948bef0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ConditionalReturnsOnNewlineConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ConditionalReturnsOnNewlineConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ConditionalReturnsOnNewlineConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ConditionalReturnsOnNewlineRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift index 3d366cd6c2..0ebcd63fe7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/CyclomaticComplexityConfiguration.swift @@ -1,7 +1,7 @@ import SourceKittenFramework import SwiftLintCore -@AutoApply +@AutoConfigParser struct CyclomaticComplexityConfiguration: RuleConfiguration { typealias Parent = CyclomaticComplexityRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift index 776a7000cc..72753bf382 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DiscouragedDirectInitConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct DiscouragedDirectInitConfiguration: SeverityBasedRuleConfiguration { typealias Parent = DiscouragedDirectInitRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/EmptyCountConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/EmptyCountConfiguration.swift index c0302c9cee..8216adce8e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/EmptyCountConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/EmptyCountConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct EmptyCountConfiguration: SeverityBasedRuleConfiguration { typealias Parent = EmptyCountRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExpiringTodoConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExpiringTodoConfiguration.swift index 4667ff09ee..29f1fb7da0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExpiringTodoConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExpiringTodoConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ExpiringTodoConfiguration: RuleConfiguration { typealias Parent = ExpiringTodoRule typealias Severity = SeverityConfiguration diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitInitConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitInitConfiguration.swift index 12797b725e..6fd03935db 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitInitConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitInitConfiguration.swift @@ -1,4 +1,4 @@ -@AutoApply +@AutoConfigParser struct ExplicitInitConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ExplicitInitRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitTypeInterfaceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitTypeInterfaceConfiguration.swift index b57dd54f74..89d4b8a2ed 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitTypeInterfaceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitTypeInterfaceConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ExplicitTypeInterfaceConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ExplicitTypeInterfaceRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum VariableKind: String, CaseIterable { case instance case local diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift index fab9eff557..e5a1675079 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileLengthConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct FileLengthConfiguration: RuleConfiguration { typealias Parent = FileLengthRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift index 9caeff15f9..08d414eacd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct FileNameConfiguration: SeverityBasedRuleConfiguration { typealias Parent = FileNameRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameNoSpaceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameNoSpaceConfiguration.swift index 8482977ece..e9f8128390 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameNoSpaceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameNoSpaceConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct FileNameNoSpaceConfiguration: SeverityBasedRuleConfiguration { typealias Parent = FileNameNoSpaceRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift index 5a88b26009..4ec1bc066b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileTypesOrderConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct FileTypesOrderConfiguration: SeverityBasedRuleConfiguration { typealias Parent = FileTypesOrderRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum FileType: String { case supportingType = "supporting_type" case mainType = "main_type" diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ForWhereConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ForWhereConfiguration.swift index 56f13072e4..3a29712110 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ForWhereConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ForWhereConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ForWhereConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ForWhereRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift index f964487b69..f72993a7a1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionParameterCountConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct FunctionParameterCountConfiguration: RuleConfiguration { typealias Parent = FunctionParameterCountRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift index 7f8a98b1ad..7cdb33754a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IdentifierNameConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct IdentifierNameConfiguration: RuleConfiguration { typealias Parent = IdentifierNameRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift index edcd8f2c68..d4bbe24d71 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitReturnConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ImplicitReturnConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ImplicitReturnRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum ReturnKind: String, CaseIterable, Comparable { case closure case function diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitlyUnwrappedOptionalConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitlyUnwrappedOptionalConfiguration.swift index 1f4ec57f41..d60c7a8cff 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitlyUnwrappedOptionalConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ImplicitlyUnwrappedOptionalConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ImplicitlyUnwrappedOptionalConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ImplicitlyUnwrappedOptionalRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum ImplicitlyUnwrappedOptionalModeConfiguration: String { // swiftlint:disable:this type_name case all = "all" case allExceptIBOutlets = "all_except_iboutlets" diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift index 281f9079a6..8139a3cd38 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/InclusiveLanguageConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct InclusiveLanguageConfiguration: SeverityBasedRuleConfiguration { typealias Parent = InclusiveLanguageRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift index 9e6e1be378..8e79864f5b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/IndentationWidthConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct IndentationWidthConfiguration: SeverityBasedRuleConfiguration { typealias Parent = IndentationWidthRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift index a8baca89c9..0f83c6ee24 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/LineLengthConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct LineLengthConfiguration: RuleConfiguration { typealias Parent = LineLengthRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift index f805557e67..d2ce6210c9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ModifierOrderConfiguration.swift @@ -1,7 +1,7 @@ import SourceKittenFramework import SwiftLintCore -@AutoApply +@AutoConfigParser struct ModifierOrderConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ModifierOrderRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineArgumentsConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineArgumentsConfiguration.swift index 674e5fb039..e0939e6daf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineArgumentsConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineArgumentsConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct MultilineArgumentsConfiguration: SeverityBasedRuleConfiguration { typealias Parent = MultilineArgumentsRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum FirstArgumentLocation: String { case anyLine = "any_line" case sameLine = "same_line" diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift index 963afd7b6e..f8705d7cb0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct MultilineParametersConfiguration: SeverityBasedRuleConfiguration { typealias Parent = MultilineParametersRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift index 9fe2c155cd..750b1793ef 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NestingConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct NestingConfiguration: RuleConfiguration { typealias Parent = NestingRule typealias Severity = SeverityLevelsConfiguration diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NonOverridableClassDeclarationConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NonOverridableClassDeclarationConfiguration.swift index 5022944724..c302c8dfa1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NonOverridableClassDeclarationConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NonOverridableClassDeclarationConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply // swiftlint:disable:next type_name +@AutoConfigParser // swiftlint:disable:next type_name struct NonOverridableClassDeclarationConfiguration: SeverityBasedRuleConfiguration { typealias Parent = NonOverridableClassDeclarationRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum FinalClassModifier: String { case finalClass = "final class" case `static` = "static" diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NumberSeparatorConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NumberSeparatorConfiguration.swift index 6268222e0a..aad4aad6f9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NumberSeparatorConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NumberSeparatorConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct NumberSeparatorConfiguration: SeverityBasedRuleConfiguration { typealias Parent = NumberSeparatorRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ObjectLiteralConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ObjectLiteralConfiguration.swift index fd691da869..f18c01ab8c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ObjectLiteralConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ObjectLiteralConfiguration.swift @@ -2,7 +2,7 @@ import SwiftLintCore typealias DiscouragedObjectLiteralConfiguration = ObjectLiteralConfiguration -@AutoApply +@AutoConfigParser struct ObjectLiteralConfiguration: SeverityBasedRuleConfiguration { @ConfigurationElement(key: "severity") private(set) var severityConfiguration = SeverityConfiguration(.warning) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift index 85f40e1da0..1e72688009 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct OpeningBraceConfiguration: SeverityBasedRuleConfiguration { typealias Parent = OpeningBraceRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OperatorUsageWhitespaceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OperatorUsageWhitespaceConfiguration.swift index 09c8bcd489..1bd83318f6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OperatorUsageWhitespaceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OperatorUsageWhitespaceConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct OperatorUsageWhitespaceConfiguration: SeverityBasedRuleConfiguration { typealias Parent = OperatorUsageWhitespaceRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift index 9affca857b..1c4a3f12bc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OverriddenSuperCallConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct OverriddenSuperCallConfiguration: SeverityBasedRuleConfiguration { typealias Parent = OverriddenSuperCallRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrefixedTopLevelConstantConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrefixedTopLevelConstantConfiguration.swift index f6057ceb93..591b8cc13a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrefixedTopLevelConstantConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrefixedTopLevelConstantConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct PrefixedTopLevelConstantConfiguration: SeverityBasedRuleConfiguration { typealias Parent = PrefixedTopLevelConstantRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOutletConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOutletConfiguration.swift index e31075e071..ae3fdf5702 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOutletConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOutletConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct PrivateOutletConfiguration: SeverityBasedRuleConfiguration { typealias Parent = PrivateOutletRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOverFilePrivateConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOverFilePrivateConfiguration.swift index ed9766230f..69fc9eb042 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOverFilePrivateConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PrivateOverFilePrivateConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct PrivateOverFilePrivateConfiguration: SeverityBasedRuleConfiguration { typealias Parent = PrivateOverFilePrivateRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift index d12c4a91ec..cd06da7cf1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ProhibitedSuperConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ProhibitedSuperConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ProhibitedSuperRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift index fa837304f5..3eb9596298 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct RedundantTypeAnnotationConfiguration: SeverityBasedRuleConfiguration { typealias Parent = RedundantTypeAnnotationRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantVoidReturnConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantVoidReturnConfiguration.swift index c81e36723a..14dbe5aba1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantVoidReturnConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantVoidReturnConfiguration.swift @@ -1,4 +1,4 @@ -@AutoApply +@AutoConfigParser struct RedundantVoidReturnConfiguration: SeverityBasedRuleConfiguration { typealias Parent = RedundantVoidReturnRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SelfBindingConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SelfBindingConfiguration.swift index 005a838f3c..9557225db9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SelfBindingConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SelfBindingConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct SelfBindingConfiguration: SeverityBasedRuleConfiguration { typealias Parent = SelfBindingRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ShorthandArgumentConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ShorthandArgumentConfiguration.swift index e5313e64d9..07907bb75a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ShorthandArgumentConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ShorthandArgumentConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct ShorthandArgumentConfiguration: SeverityBasedRuleConfiguration { typealias Parent = ShorthandArgumentRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SortedImportsConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SortedImportsConfiguration.swift index 8aaab0abc8..6d08c57d33 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SortedImportsConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SortedImportsConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct SortedImportsConfiguration: SeverityBasedRuleConfiguration { typealias Parent = SortedImportsRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum SortedImportsGroupingConfiguration: String { /// Sorts import lines based on any import attributes (e.g. `@testable`, `@_exported`, etc.), followed by a case /// insensitive comparison of the imported module name. diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/StatementPositionConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/StatementPositionConfiguration.swift index a0361e64d7..1844fdfa8c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/StatementPositionConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/StatementPositionConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct StatementPositionConfiguration: SeverityBasedRuleConfiguration { typealias Parent = StatementPositionRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum StatementModeConfiguration: String { case `default` = "default" case uncuddledElse = "uncuddled_else" diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SwitchCaseAlignmentConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SwitchCaseAlignmentConfiguration.swift index 7f0a94920e..1828a7508e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SwitchCaseAlignmentConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/SwitchCaseAlignmentConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct SwitchCaseAlignmentConfiguration: SeverityBasedRuleConfiguration { typealias Parent = SwitchCaseAlignmentRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TestCaseAccessibilityConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TestCaseAccessibilityConfiguration.swift index 05296ceb18..51fbb0fb7d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TestCaseAccessibilityConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TestCaseAccessibilityConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct TestCaseAccessibilityConfiguration: SeverityBasedRuleConfiguration { typealias Parent = TestCaseAccessibilityRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TodoConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TodoConfiguration.swift index 437c57a2cb..7fd34fda29 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TodoConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TodoConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct TodoConfiguration: SeverityBasedRuleConfiguration { typealias Parent = TodoRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum TodoKeyword: String, CaseIterable { case todo = "TODO" case fixme = "FIXME" diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingClosureConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingClosureConfiguration.swift index e4b4862921..58f88681fd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingClosureConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingClosureConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct TrailingClosureConfiguration: SeverityBasedRuleConfiguration { typealias Parent = TrailingClosureRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingCommaConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingCommaConfiguration.swift index f386f1967d..7a07760192 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingCommaConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingCommaConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct TrailingCommaConfiguration: SeverityBasedRuleConfiguration { typealias Parent = TrailingCommaRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingWhitespaceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingWhitespaceConfiguration.swift index d8577e64ae..0eb7577b40 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingWhitespaceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TrailingWhitespaceConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct TrailingWhitespaceConfiguration: SeverityBasedRuleConfiguration { typealias Parent = TrailingWhitespaceRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift index 9a229c6016..01f1427f6e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeContentsOrderConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@MakeAcceptableByConfigurationElement +@AcceptableByConfigurationElement enum TypeContent: String { case `case` = "case" case typeAlias = "type_alias" @@ -19,7 +19,7 @@ enum TypeContent: String { case deinitializer = "deinitializer" } -@AutoApply +@AutoConfigParser struct TypeContentsOrderConfiguration: SeverityBasedRuleConfiguration { typealias Parent = TypeContentsOrderRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift index ff21a9eee0..d9d51cb664 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/TypeNameConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct TypeNameConfiguration: RuleConfiguration { typealias Parent = TypeNameRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnitTestConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnitTestConfiguration.swift index 43be8e9889..96f5d0de6d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnitTestConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnitTestConfiguration.swift @@ -6,7 +6,7 @@ typealias FinalTestCaseConfiguration = UnitTestConfiguration typealias NoMagicNumbersConfiguration = UnitTestConfiguration typealias SingleTestClassConfiguration = UnitTestConfiguration -@AutoApply +@AutoConfigParser struct UnitTestConfiguration: SeverityBasedRuleConfiguration { @ConfigurationElement(key: "severity") private(set) var severityConfiguration = SeverityConfiguration(.warning) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnneededOverrideRuleConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnneededOverrideRuleConfiguration.swift index 14d4968152..cdbf8441fa 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnneededOverrideRuleConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnneededOverrideRuleConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct UnneededOverrideRuleConfiguration: SeverityBasedRuleConfiguration { typealias Parent = UnneededOverrideRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedDeclarationConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedDeclarationConfiguration.swift index 58877e82a5..e3deec3ac3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedDeclarationConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedDeclarationConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct UnusedDeclarationConfiguration: SeverityBasedRuleConfiguration { typealias Parent = UnusedDeclarationRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift index eaa8571e19..aed18138ff 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedImportConfiguration.swift @@ -27,7 +27,7 @@ struct TransitiveModuleConfiguration: Equatable, AcceptableByConfi } } -@AutoApply +@AutoConfigParser struct UnusedImportConfiguration: SeverityBasedRuleConfiguration { typealias Parent = UnusedImportRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedOptionalBindingConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedOptionalBindingConfiguration.swift index fa094ad346..083d7d27a7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedOptionalBindingConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/UnusedOptionalBindingConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct UnusedOptionalBindingConfiguration: SeverityBasedRuleConfiguration { typealias Parent = UnusedOptionalBindingRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceClosingBracesConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceClosingBracesConfiguration.swift index 700b06e04b..cb62a95da0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceClosingBracesConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceClosingBracesConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply // swiftlint:disable:next type_name +@AutoConfigParser // swiftlint:disable:next type_name struct VerticalWhitespaceClosingBracesConfiguration: SeverityBasedRuleConfiguration { typealias Parent = VerticalWhitespaceClosingBracesRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceConfiguration.swift index 2249594ee8..2bc989d73f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/VerticalWhitespaceConfiguration.swift @@ -1,6 +1,6 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct VerticalWhitespaceConfiguration: SeverityBasedRuleConfiguration { typealias Parent = VerticalWhitespaceRule diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/XCTSpecificMatcherConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/XCTSpecificMatcherConfiguration.swift index 249c35ef4e..298fb42c2f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/XCTSpecificMatcherConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/XCTSpecificMatcherConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct XCTSpecificMatcherConfiguration: SeverityBasedRuleConfiguration { typealias Parent = XCTSpecificMatcherRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum Matcher: String, CaseIterable { case oneArgumentAsserts = "one-argument-asserts" case twoArgumentAsserts = "two-argument-asserts" diff --git a/Source/SwiftLintCore/Helpers/Macros.swift b/Source/SwiftLintCore/Helpers/Macros.swift index 45df01a6a1..7d6270d2ac 100644 --- a/Source/SwiftLintCore/Helpers/Macros.swift +++ b/Source/SwiftLintCore/Helpers/Macros.swift @@ -4,9 +4,20 @@ member, names: named(apply) ) +public macro AutoConfigParser() = #externalMacro( + module: "SwiftLintCoreMacros", + type: "AutoConfigParser" +) + +/// Deprecated. Use `AutoConfigParser` instead. +@available(*, deprecated, renamed: "AutoConfigParser") +@attached( + member, + names: named(apply) +) public macro AutoApply() = #externalMacro( module: "SwiftLintCoreMacros", - type: "AutoApply" + type: "AutoConfigParser" ) /// Macro that lets an enum with a ``String`` raw type automatically conform to ``AcceptableByConfigurationElement``. @@ -15,9 +26,21 @@ public macro AutoApply() = #externalMacro( conformances: AcceptableByConfigurationElement, names: named(init(fromAny:context:)), named(asOption) ) +public macro AcceptableByConfigurationElement() = #externalMacro( + module: "SwiftLintCoreMacros", + type: "AcceptableByConfigurationElement" +) + +/// Deprecated. Use `AcceptableByConfigurationElement` instead. +@available(*, deprecated, renamed: "AcceptableByConfigurationElement") +@attached( + extension, + conformances: AcceptableByConfigurationElement, + names: named(init(fromAny:context:)), named(asOption) +) public macro MakeAcceptableByConfigurationElement() = #externalMacro( module: "SwiftLintCoreMacros", - type: "MakeAcceptableByConfigurationElement" + type: "AcceptableByConfigurationElement" ) /// Macro that adds a conformance to the ``SwiftSyntaxRule`` protocol and a default `makeVisitor(file:)` implementation @@ -27,7 +50,7 @@ public macro MakeAcceptableByConfigurationElement() = #externalMacro( /// - foldExpressions: Setting it to `true` adds an implementation of `preprocess(file:)` which folds expressions /// before they are passed to the visitor. /// - explicitRewriter: Set it to `true` to add a `makeRewriter(file:)` implementation which creates a rewriter -/// defined in the rule struct. In this case, the rule automatically conforms to +/// defined in the rule struct. In this case, the rule automatically conforms to /// ``SwiftSyntaxCorrectableRule``. @attached( extension, diff --git a/Source/SwiftLintCore/Models/ViolationSeverity.swift b/Source/SwiftLintCore/Models/ViolationSeverity.swift index deef926ffa..41c75abb03 100644 --- a/Source/SwiftLintCore/Models/ViolationSeverity.swift +++ b/Source/SwiftLintCore/Models/ViolationSeverity.swift @@ -1,5 +1,5 @@ /// The magnitude of a `StyleViolation`. -@MakeAcceptableByConfigurationElement +@AcceptableByConfigurationElement public enum ViolationSeverity: String, Comparable, Codable, InlinableOptionType { /// Non-fatal. If using SwiftLint as an Xcode build phase, Xcode will mark the build as having succeeded. case warning diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index c505caad51..665a9e4335 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -3,7 +3,7 @@ import SwiftSyntax import SwiftSyntaxBuilder import SwiftSyntaxMacros -enum AutoApply: MemberMacro { +enum AutoConfigParser: MemberMacro { // swiftlint:disable:next function_body_length static func expansion( of _: AttributeSyntax, @@ -88,7 +88,7 @@ enum AutoApply: MemberMacro { } } -enum MakeAcceptableByConfigurationElement: ExtensionMacro { +enum AcceptableByConfigurationElement: ExtensionMacro { static func expansion( of _: AttributeSyntax, attachedTo declaration: some DeclGroupSyntax, diff --git a/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift b/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift index fda8ad5534..fdea5b5c42 100644 --- a/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift +++ b/Source/SwiftLintCoreMacros/SwiftLintCoreMacros.swift @@ -6,8 +6,8 @@ import SwiftSyntaxMacros @main struct SwiftLintCoreMacros: CompilerPlugin { let providingMacros: [any Macro.Type] = [ - AutoApply.self, - MakeAcceptableByConfigurationElement.self, + AutoConfigParser.self, + AcceptableByConfigurationElement.self, SwiftSyntaxRule.self, ] } diff --git a/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift b/Tests/MacroTests/AcceptableByConfigurationElementTests.swift similarity index 86% rename from Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift rename to Tests/MacroTests/AcceptableByConfigurationElementTests.swift index 5f62738da1..b63c5a6a2b 100644 --- a/Tests/MacroTests/MakeAcceptableByConfigurationElementTests.swift +++ b/Tests/MacroTests/AcceptableByConfigurationElementTests.swift @@ -3,15 +3,14 @@ import SwiftSyntaxMacrosTestSupport import XCTest private let macros = [ - "MakeAcceptableByConfigurationElement": MakeAcceptableByConfigurationElement.self + "AcceptableByConfigurationElement": AcceptableByConfigurationElement.self ] -// swiftlint:disable:next type_name -final class MakeAcceptableByConfigurationElementTests: XCTestCase { +final class AcceptableByConfigurationElementTests: XCTestCase { func testNoEnum() { assertMacroExpansion( """ - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement struct S { } """, @@ -29,7 +28,7 @@ final class MakeAcceptableByConfigurationElementTests: XCTestCase { func testNoStringRawType() { assertMacroExpansion( """ - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum E { } """, @@ -47,7 +46,7 @@ final class MakeAcceptableByConfigurationElementTests: XCTestCase { func testPrivateEnum() { assertMacroExpansion( """ - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement private enum E: String { } """, @@ -75,7 +74,7 @@ final class MakeAcceptableByConfigurationElementTests: XCTestCase { func testPublicEnum() { assertMacroExpansion( """ - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement public enum E: String { } """, diff --git a/Tests/MacroTests/AutoApplyTests.swift b/Tests/MacroTests/AutoConfigParserTests.swift similarity index 96% rename from Tests/MacroTests/AutoApplyTests.swift rename to Tests/MacroTests/AutoConfigParserTests.swift index 377fe34f48..39d9505032 100644 --- a/Tests/MacroTests/AutoApplyTests.swift +++ b/Tests/MacroTests/AutoConfigParserTests.swift @@ -3,14 +3,14 @@ import SwiftSyntaxMacrosTestSupport import XCTest private let macros = [ - "AutoApply": AutoApply.self + "AutoConfigParser": AutoConfigParser.self ] -final class AutoApplyTests: XCTestCase { +final class AutoConfigParserTests: XCTestCase { func testAttachToClass() { assertMacroExpansion( """ - @AutoApply + @AutoConfigParser class C { } """, @@ -28,7 +28,7 @@ final class AutoApplyTests: XCTestCase { func testNoConfigurationElements() { assertMacroExpansion( """ - @AutoApply + @AutoConfigParser struct S { } """, @@ -54,7 +54,7 @@ final class AutoApplyTests: XCTestCase { func testConfigurationElementsWithoutKeys() { assertMacroExpansion( """ - @AutoApply + @AutoConfigParser struct S { @ConfigurationElement var eA = 1 @@ -96,7 +96,7 @@ final class AutoApplyTests: XCTestCase { func testInlinedConfigurationElements() { assertMacroExpansion( """ - @AutoApply + @AutoConfigParser struct S { @ConfigurationElement(key: "eD") var eA = 1 @@ -147,7 +147,7 @@ final class AutoApplyTests: XCTestCase { func testSeverityBasedConfigurationWithoutSeverityProperty() { assertMacroExpansion( """ - @AutoApply + @AutoConfigParser struct S: SeverityBasedRuleConfiguration { } """, @@ -180,7 +180,7 @@ final class AutoApplyTests: XCTestCase { // swiftlint:disable line_length assertMacroExpansion( """ - @AutoApply + @AutoConfigParser struct S: SeverityBasedRuleConfiguration { @ConfigurationElement var severityConfiguration = .warning diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index 6419d39950..a4fc6bd707 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -6,7 +6,7 @@ import XCTest // swiftlint:disable:next type_body_length final class RuleConfigurationDescriptionTests: XCTestCase { - @AutoApply + @AutoConfigParser private struct TestConfiguration: RuleConfiguration { typealias Parent = RuleMock // swiftlint:disable:this nesting From 6ee4623565b82d8a475a4c9c27676c9e95c1b8be Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 24 Jul 2024 18:30:36 +0100 Subject: [PATCH 128/265] Fix deprecation warnings (#5695) --- .../Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift index 1e8625c4bc..a09221fc0b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift @@ -1,10 +1,10 @@ import SwiftLintCore -@AutoApply +@AutoConfigParser struct NoEmptyBlockConfiguration: SeverityBasedRuleConfiguration { typealias Parent = NoEmptyBlockRule - @MakeAcceptableByConfigurationElement + @AcceptableByConfigurationElement enum CodeBlockType: String, CaseIterable { case functionBodies = "function_bodies" case initializerBodies = "initializer_bodies" From 03b28d5ece83d5f8b59954688f711cedcf9a74e6 Mon Sep 17 00:00:00 2001 From: "LamTrinh.Dev" Date: Thu, 25 Jul 2024 01:31:29 +0700 Subject: [PATCH 129/265] Fix typo (#5691) --- .../SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift index 5b5f549bfe..edfd3f2bc0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CommentSpacingRule.swift @@ -57,7 +57,7 @@ struct CommentSpacingRule: SourceKitFreeRule, SubstitutionCorrectableRule { */ """), Example(""" - /*#-editable-code Swift Platground editable area*/default/*#-end-editable-code*/ + /*#-editable-code Swift Playground editable area*/default/*#-end-editable-code*/ """), ], triggeringExamples: [ From b257cd2c173a946c32a0226224a407d3bc79620a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 24 Jul 2024 22:55:44 +0200 Subject: [PATCH 130/265] Update status badge --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a7eb86ed7..190cca2ffd 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ SwiftLint hooks into [Clang](http://clang.llvm.org) and [AST](http://clang.llvm.org/docs/IntroductionToTheClangAST.html) representation of your source files for more accurate results. -[![Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=main)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=main) -[![codecov.io](https://codecov.io/github/realm/SwiftLint/coverage.svg?branch=main)](https://codecov.io/github/realm/SwiftLint?branch=main) +[![Azure Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=main)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=main) +[![Buildkite Build Status](https://badge.buildkite.com/e2a5bc32c347e76e2793e4c5764a5f42bcd42bbe32f79c3a53.svg?branch=main)](https://buildkite.com/swiftlint/swiftlint) ![](https://raw.githubusercontent.com/realm/SwiftLint/main/assets/screenshot.png) From 7904d9a4389ccfeee8df5b0093613a1f6cfeefad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 24 Jul 2024 22:57:24 +0200 Subject: [PATCH 131/265] Support `--target` paths being passed to command plugin (#5696) --- CHANGELOG.md | 4 ++ .../SwiftLintCommandPlugin.swift | 68 +++++++++++-------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73c18130f6..2eaaf5c738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,10 @@ [SimplyDanny](https://github.com/SimplyDanny) [#2120](https://github.com/realm/SwiftLint/issues/2120) +* Support `--target` paths being passed to command plugin by Xcode. + [SimplyDanny](https://github.com/SimplyDanny) + [#5603](https://github.com/realm/SwiftLint/issues/5603) + * Add modified configurations to examples in rule documentation. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift index 7ad7275dd5..3ff555170e 100644 --- a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift +++ b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift @@ -3,38 +3,48 @@ import PackagePlugin @main struct SwiftLintCommandPlugin: CommandPlugin { - func performCommand( - context: PluginContext, - arguments: [String] - ) throws { - let tool: PluginContext.Tool = try context.tool(named: "swiftlint") - // Caching is managed internally because the cache must be located within the `pluginWorkDirectory`. - if arguments.contains("--cache-path") { - Diagnostics.error("Setting Cache Path Not Allowed") + func performCommand(context: PluginContext, arguments: [String]) throws { + guard !arguments.contains("--cache-path") else { + Diagnostics.error("Caching is managed by the plugin and so setting `--cache-path` is not allowed") return } - let process: Process = .init() - process.currentDirectoryURL = URL(fileURLWithPath: context.package.directory.string) - process.executableURL = URL(fileURLWithPath: tool.path.string) - // The analyze command does not support the `--cache-path` argument - if arguments.contains("analyze") { + var argExtractor = ArgumentExtractor(arguments) + let targetNames = argExtractor.extractOption(named: "target") + let targets = targetNames.isEmpty + ? context.package.targets + : try context.package.targets(named: targetNames) + let tool = try context.tool(named: "swiftlint") + for target in targets { + guard let target = target.sourceModule else { + Diagnostics.warning("Target '\(target.name)' is not a source module; skipping it") + continue + } + + let process = Process() + process.currentDirectoryURL = URL(fileURLWithPath: context.package.directory.string) + process.executableURL = URL(fileURLWithPath: tool.path.string) process.arguments = arguments - } else { - process.arguments = arguments + ["--cache-path", "\(context.pluginWorkDirectory.string)"] - } - try process.run() - process.waitUntilExit() - switch process.terminationReason { - case .exit: - break - case .uncaughtSignal: - Diagnostics.error("Uncaught Signal") - @unknown default: - Diagnostics.error("Unexpected Termination Reason") - } - guard process.terminationStatus == EXIT_SUCCESS else { - Diagnostics.error("Command Failed") - return + if !arguments.contains("analyze") { + // The analyze command does not support the `--cache-path` argument. + process.arguments! += ["--cache-path", "\(context.pluginWorkDirectory.string)"] + } + process.arguments! += [target.directory.string] + + try process.run() + process.waitUntilExit() + switch process.terminationReason { + case .exit: + Diagnostics.remark("Finished running in module '\(target.name)'") + case .uncaughtSignal: + Diagnostics.error("Got uncaught signal while running in module '\(target.name)'") + @unknown default: + Diagnostics.error("Stopped running in module '\(target.name) due to unexpected termination reason") + } + if process.terminationStatus != EXIT_SUCCESS { + Diagnostics.warning( + "Command found violations or unsuccessfully stopped running in module '\(target.name)'" + ) + } } } } From 7b84112179830ce8accfd9d38bdd13afd099c272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 25 Jul 2024 19:39:07 +0200 Subject: [PATCH 132/265] Remove reporter category from documentation (#5697) --- .jazzy.yaml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.jazzy.yaml b/.jazzy.yaml index 6ea87fd649..d25736b793 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -19,14 +19,3 @@ custom_categories: - name: Rules children: - Rule Directory - - name: Reporters - children: - - CSVReporter - - CheckstyleReporter - - CodeClimateReporter - - EmojiReporter - - GitHubActionsLoggingReporter - - HTMLReporter - - JSONReporter - - JUnitReporter - - MarkdownReporter From cce9febcb7660fdc5e5604e784166f3af178268b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 25 Jul 2024 21:13:17 +0200 Subject: [PATCH 133/265] Use SwiftSyntax version 600.0.0-prerelease-2024-07-24 (#5701) --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.resolved | 4 ++-- Package.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2eaaf5c738..dd2a1463ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ #### Enhancements -* Linting got around 20% faster due to the praisworthy performance +* Linting got up to 30% faster due to the praisworthy performance improvements done in the [SwiftSyntax](https://github.com/swiftlang/swift-syntax) library. diff --git a/MODULE.bazel b/MODULE.bazel index f2c9c9de40..bbf3cb70c7 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,7 +11,7 @@ bazel_dep(name = "platforms", version = "0.0.8") bazel_dep(name = "rules_apple", version = "3.3.0", repo_name = "build_bazel_rules_apple") bazel_dep(name = "rules_swift", version = "1.16.0", repo_name = "build_bazel_rules_swift") bazel_dep(name = "sourcekitten", version = "0.35.0", repo_name = "com_github_jpsim_sourcekitten") -bazel_dep(name = "swift-syntax", version = "600.0.0-prerelease-2024-04-02", repo_name = "SwiftSyntax") +bazel_dep(name = "swift-syntax", version = "600.0.0-prerelease-2024-07-24", repo_name = "SwiftSyntax") bazel_dep(name = "swift_argument_parser", version = "1.3.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") bazel_dep(name = "yams", version = "5.0.6", repo_name = "sourcekitten_com_github_jpsim_yams") diff --git a/Package.resolved b/Package.resolved index 2d9174b8e3..286a73b22e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "55c4e4669c031d697e1924022b8ba250cfde0f2f", - "version" : "600.0.0-prerelease-2024-04-02" + "revision" : "82a453c2dfa335c7e778695762438dfe72b328d2", + "version" : "600.0.0-prerelease-2024-07-24" } }, { diff --git a/Package.swift b/Package.swift index 9b91a4bde1..3efda3e7f5 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), - .package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "600.0.0-prerelease-2024-04-02"), + .package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "600.0.0-prerelease-2024-07-24"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), From cbe9bd04497fdcd37d832cc26d620966c2e58f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 25 Jul 2024 22:12:58 +0200 Subject: [PATCH 134/265] Disable upcoming Swift feature "InternalImportsByDefault" (#5702) --- BUILD | 2 -- Package.swift | 1 - 2 files changed, 3 deletions(-) diff --git a/BUILD b/BUILD index afd327d672..b13f510f8e 100644 --- a/BUILD +++ b/BUILD @@ -35,8 +35,6 @@ copts = [ "-enable-upcoming-feature", "ForwardTrailingClosures", "-enable-upcoming-feature", - "InternalImportsByDefault", - "-enable-upcoming-feature", "ImplicitOpenExistentials", ] diff --git a/Package.swift b/Package.swift index 3efda3e7f5..af32be06c4 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,6 @@ let swiftFeatures: [SwiftSetting] = [ .enableUpcomingFeature("ConciseMagicFile"), .enableUpcomingFeature("ImportObjcForwardDeclarations"), .enableUpcomingFeature("ForwardTrailingClosures"), - .enableUpcomingFeature("InternalImportsByDefault"), .enableUpcomingFeature("ImplicitOpenExistentials"), ] From b2214728b1cb202b7e6f375f7785539431e22f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 25 Jul 2024 22:22:57 +0200 Subject: [PATCH 135/265] Update SPM dependencies (#5703) --- Package.resolved | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.resolved b/Package.resolved index 286a73b22e..30811f5487 100644 --- a/Package.resolved +++ b/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", "state" : { - "revision" : "db51c407d3be4a051484a141bf0bff36c43d3b1e", - "version" : "1.8.0" + "revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0", + "version" : "1.8.2" } }, { @@ -68,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/jpsim/Yams.git", "state" : { - "revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3", - "version" : "5.0.6" + "revision" : "3036ba9d69cf1fd04d433527bc339dc0dc75433d", + "version" : "5.1.3" } } ], From 4b9c15969de31c08f1425acd18bfaff5fd97e63f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 25 Jul 2024 22:43:57 +0200 Subject: [PATCH 136/265] Remove unused conformance (#5704) --- .../Extensions/NSRegularExpression+SwiftLint.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift b/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift index cd06e8b0b8..4f392828ea 100644 --- a/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/NSRegularExpression+SwiftLint.swift @@ -34,12 +34,6 @@ private struct RegexCacheKey: Hashable { } } -extension NSRegularExpression: Comparable { - public static func < (lhs: NSRegularExpression, rhs: NSRegularExpression) -> Bool { - lhs.pattern < rhs.pattern - } -} - public extension NSRegularExpression { static func cached(pattern: String, options: Options? = nil) throws -> NSRegularExpression { let options = options ?? [.anchorsMatchLines, .dotMatchesLineSeparators] From f72666ec778e06e95324945ab5cce3c85e4a53f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 26 Jul 2024 19:43:57 +0200 Subject: [PATCH 137/265] Fix some issue in SARIF reporter (#5705) --- .../Reporters/JSONReporter.swift | 2 +- .../Reporters/SARIFReporter.swift | 6 +- .../ReporterTests.swift | 221 +++++++++++------- .../Resources/CannedCSVReporterOutput.csv | 6 +- .../CannedCheckstyleReporterOutput.xml | 8 +- .../CannedCodeClimateReporterOutput.json | 12 +- .../Resources/CannedEmojiReporterOutput.txt | 7 +- ...nnedGitHubActionsLoggingReporterOutput.txt | 6 +- .../CannedGitLabJUnitReporterOutput.xml | 12 +- .../Resources/CannedHTMLReporterOutput.html | 14 +- .../Resources/CannedJSONReporterOutput.json | 24 +- .../Resources/CannedJunitReporterOutput.xml | 6 +- .../Resources/CannedMarkdownReporterOutput.md | 6 +- .../CannedRelativePathReporterOutput.txt | 6 +- .../Resources/CannedSARIFReporterOutput.json | 18 +- .../CannedSonarQubeReporterOutput.json | 76 +++--- .../Resources/CannedSummaryReporterOutput.txt | 2 +- .../Resources/CannedXcodeReporterOutput.txt | 6 +- 18 files changed, 247 insertions(+), 191 deletions(-) diff --git a/Source/SwiftLintCore/Reporters/JSONReporter.swift b/Source/SwiftLintCore/Reporters/JSONReporter.swift index 537c0f73c5..334152c6c7 100644 --- a/Source/SwiftLintCore/Reporters/JSONReporter.swift +++ b/Source/SwiftLintCore/Reporters/JSONReporter.swift @@ -10,7 +10,7 @@ struct JSONReporter: Reporter { static let description = "Reports violations as a JSON array." static func generateReport(_ violations: [StyleViolation]) -> String { - toJSON(violations.map(dictionary(for:))) + toJSON(violations.map(dictionary(for:)), options: [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]) } // MARK: - Private diff --git a/Source/SwiftLintCore/Reporters/SARIFReporter.swift b/Source/SwiftLintCore/Reporters/SARIFReporter.swift index 42024e52a2..108e4fb2d6 100644 --- a/Source/SwiftLintCore/Reporters/SARIFReporter.swift +++ b/Source/SwiftLintCore/Reporters/SARIFReporter.swift @@ -30,7 +30,7 @@ struct SARIFReporter: Reporter { ], ] as [String: Any] - return toJSON(SARIFJson) + return toJSON(SARIFJson, options: [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]) } // MARK: - Private @@ -54,11 +54,11 @@ struct SARIFReporter: Reporter { return [ "physicalLocation": [ "artifactLocation": [ - "uri": location.file ?? "" + "uri": location.relativeFile ?? "" ], "region": [ "startLine": line, - "startColumn": location.character ?? "1", + "startColumn": location.character ?? 1, ], ], ] diff --git a/Tests/SwiftLintFrameworkTests/ReporterTests.swift b/Tests/SwiftLintFrameworkTests/ReporterTests.swift index 94b16edb6a..252881c47f 100644 --- a/Tests/SwiftLintFrameworkTests/ReporterTests.swift +++ b/Tests/SwiftLintFrameworkTests/ReporterTests.swift @@ -5,6 +5,35 @@ import SourceKittenFramework import XCTest final class ReporterTests: SwiftLintTestCase { + private let violations = [ + StyleViolation( + ruleDescription: LineLengthRule.description, + location: Location(file: "filename", line: 1, character: 1), + reason: "Violation Reason 1" + ), + StyleViolation( + ruleDescription: LineLengthRule.description, + severity: .error, + location: Location(file: "filename", line: 1), + reason: "Violation Reason 2" + ), + StyleViolation( + ruleDescription: SyntacticSugarRule.description, + severity: .error, + location: Location( + file: FileManager.default.currentDirectoryPath + "/path/file.swift", + line: 1, + character: 2 + ), + reason: "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array"), + StyleViolation( + ruleDescription: ColonRule.description, + severity: .error, + location: Location(file: nil), + reason: nil + ), + ] + func testReporterFromString() { for reporter in reportersList { XCTAssertEqual(reporter.identifier, reporterFrom(identifier: reporter.identifier).identifier) @@ -15,50 +44,32 @@ final class ReporterTests: SwiftLintTestCase { SwiftLintFile(path: "\(testResourcesPath)/\(filename)")!.contents } - private func generateViolations() -> [StyleViolation] { - let location = Location(file: "filename", line: 1, character: 2) - return [ - StyleViolation(ruleDescription: LineLengthRule.description, - location: location, - reason: "Violation Reason"), - StyleViolation(ruleDescription: LineLengthRule.description, - severity: .error, - location: location, - reason: "Violation Reason"), - StyleViolation(ruleDescription: SyntacticSugarRule.description, - severity: .error, - location: location, - reason: "Shorthand syntactic sugar should be used" + - ", i.e. [Int] instead of Array"), - StyleViolation(ruleDescription: ColonRule.description, - severity: .error, - location: Location(file: nil), - reason: nil), - ] - } - - func testXcodeReporter() { - let expectedOutput = stringFromFile("CannedXcodeReporterOutput.txt") - let result = XcodeReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testXcodeReporter() throws { + try assertEqualContent( + referenceFile: "CannedXcodeReporterOutput.txt", + reporterType: XcodeReporter.self + ) } - func testEmojiReporter() { - let expectedOutput = stringFromFile("CannedEmojiReporterOutput.txt") - let result = EmojiReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testEmojiReporter() throws { + try assertEqualContent( + referenceFile: "CannedEmojiReporterOutput.txt", + reporterType: EmojiReporter.self + ) } - func testGitHubActionsLoggingReporter() { - let expectedOutput = stringFromFile("CannedGitHubActionsLoggingReporterOutput.txt") - let result = GitHubActionsLoggingReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testGitHubActionsLoggingReporter() throws { + try assertEqualContent( + referenceFile: "CannedGitHubActionsLoggingReporterOutput.txt", + reporterType: GitHubActionsLoggingReporter.self + ) } - func testGitLabJUnitReporter() { - let expectedOutput = stringFromFile("CannedGitLabJUnitReporterOutput.xml") - let result = GitLabJUnitReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testGitLabJUnitReporter() throws { + try assertEqualContent( + referenceFile: "CannedGitLabJUnitReporterOutput.xml", + reporterType: GitLabJUnitReporter.self + ) } private func jsonValue(_ jsonString: String) throws -> NSObject { @@ -74,70 +85,75 @@ final class ReporterTests: SwiftLintTestCase { } func testJSONReporter() throws { - let expectedOutput = stringFromFile("CannedJSONReporterOutput.json") - let result = JSONReporter.generateReport(generateViolations()) - XCTAssertEqual(try jsonValue(result), try jsonValue(expectedOutput)) + try assertEqualContent( + referenceFile: "CannedJSONReporterOutput.json", + reporterType: JSONReporter.self, + stringConverter: { try jsonValue($0) } + ) } - func testCSVReporter() { - let expectedOutput = stringFromFile("CannedCSVReporterOutput.csv") - let result = CSVReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testCSVReporter() throws { + try assertEqualContent( + referenceFile: "CannedCSVReporterOutput.csv", + reporterType: CSVReporter.self + ) } - func testCheckstyleReporter() { - let expectedOutput = stringFromFile("CannedCheckstyleReporterOutput.xml") - let result = CheckstyleReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testCheckstyleReporter() throws { + try assertEqualContent( + referenceFile: "CannedCheckstyleReporterOutput.xml", + reporterType: CheckstyleReporter.self + ) } - func testCodeClimateReporter() { - let expectedOutput = stringFromFile("CannedCodeClimateReporterOutput.json") - let result = CodeClimateReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testCodeClimateReporter() throws { + try assertEqualContent( + referenceFile: "CannedCodeClimateReporterOutput.json", + reporterType: CodeClimateReporter.self + ) } - func testSARIFReporter() { - let expectedOutput = stringFromFile("CannedSARIFReporterOutput.json").replacingOccurrences( - of: "${SWIFT_LINT_VERSION}", - with: SwiftLintCore.Version.current.value - ).trimmingCharacters(in: .whitespacesAndNewlines) - let result = SARIFReporter.generateReport(generateViolations()) - XCTAssertEqual(expectedOutput, result) + func testSARIFReporter() throws { + try assertEqualContent( + referenceFile: "CannedSARIFReporterOutput.json", + reporterType: SARIFReporter.self + ) } - func testJunitReporter() { - let expectedOutput = stringFromFile("CannedJunitReporterOutput.xml") - let result = JUnitReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testJunitReporter() throws { + try assertEqualContent( + referenceFile: "CannedJunitReporterOutput.xml", + reporterType: JUnitReporter.self + ) } - func testHTMLReporter() { - let expectedOutput = stringFromFile("CannedHTMLReporterOutput.html") - let result = HTMLReporter.generateReport( - generateViolations(), - swiftlintVersion: "1.2.3", - dateString: "13/12/2016" + func testHTMLReporter() throws { + try assertEqualContent( + referenceFile: "CannedHTMLReporterOutput.html", + reporterType: HTMLReporter.self ) - XCTAssertEqual(result, expectedOutput) } - func testSonarQubeReporter() { - let expectedOutput = stringFromFile("CannedSonarQubeReporterOutput.json") - let result = SonarQubeReporter.generateReport(generateViolations()) - XCTAssertEqual(try jsonValue(result), try jsonValue(expectedOutput)) + func testSonarQubeReporter() throws { + try assertEqualContent( + referenceFile: "CannedSonarQubeReporterOutput.json", + reporterType: SonarQubeReporter.self, + stringConverter: { try jsonValue($0) } + ) } - func testMarkdownReporter() { - let expectedOutput = stringFromFile("CannedMarkdownReporterOutput.md") - let result = MarkdownReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testMarkdownReporter() throws { + try assertEqualContent( + referenceFile: "CannedMarkdownReporterOutput.md", + reporterType: MarkdownReporter.self + ) } - func testRelativePathReporter() { - let expectedOutput = stringFromFile("CannedRelativePathReporterOutput.txt") - let result = RelativePathReporter.generateReport(generateViolations()) - XCTAssertEqual(result, expectedOutput) + func testRelativePathReporter() throws { + try assertEqualContent( + referenceFile: "CannedRelativePathReporterOutput.txt", + reporterType: RelativePathReporter.self + ) } func testRelativePathReporterPaths() { @@ -160,7 +176,7 @@ final class ReporterTests: SwiftLintTestCase { location: Location(file: "filename", line: 1, character: 2), reason: "Violation Reason" ) - let result = SummaryReporter.generateReport(generateViolations() + [correctableViolation]) + let result = SummaryReporter.generateReport(violations + [correctableViolation]) XCTAssertEqual(result, expectedOutput) } @@ -170,4 +186,41 @@ final class ReporterTests: SwiftLintTestCase { let result = SummaryReporter.generateReport([]) XCTAssertEqual(result, expectedOutput) } + + private func assertEqualContent(referenceFile: String, + reporterType: any Reporter.Type, + stringConverter: (String) throws -> some Equatable = { $0 }, + file: StaticString = #filePath, + line: UInt = #line) throws { + let dateFormatter = DateFormatter() + dateFormatter.dateStyle = .short + let reference = stringFromFile(referenceFile).replacingOccurrences( + of: "${CURRENT_WORKING_DIRECTORY}", + with: FileManager.default.currentDirectoryPath + ).replacingOccurrences( + of: "${SWIFTLINT_VERSION}", + with: SwiftLintCore.Version.current.value + ).replacingOccurrences( + of: "${TODAYS_DATE}", + with: dateFormatter.string(from: Date()) + ) + let reporterOutput = reporterType.generateReport(violations) + let convertedReference = try stringConverter(reference) + let convertedReporterOutput = try stringConverter(reporterOutput) + if convertedReference != convertedReporterOutput { + let referenceURL = URL(fileURLWithPath: "\(testResourcesPath)/\(referenceFile)") + try reporterOutput.replacingOccurrences( + of: FileManager.default.currentDirectoryPath, + with: "${CURRENT_WORKING_DIRECTORY}" + ).replacingOccurrences( + of: SwiftLintCore.Version.current.value, + with: "${SWIFTLINT_VERSION}" + ).replacingOccurrences( + of: dateFormatter.string(from: Date()), + with: "${TODAYS_DATE}" + ) + .write(to: referenceURL, atomically: true, encoding: .utf8) + } + XCTAssertEqual(convertedReference, convertedReporterOutput, file: file, line: line) + } } diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedCSVReporterOutput.csv b/Tests/SwiftLintFrameworkTests/Resources/CannedCSVReporterOutput.csv index 3b59168ff0..2db0eb122f 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedCSVReporterOutput.csv +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedCSVReporterOutput.csv @@ -1,5 +1,5 @@ file,line,character,severity,type,reason,rule_id -filename,1,2,Warning,Line Length,Violation Reason,line_length -filename,1,2,Error,Line Length,Violation Reason,line_length -filename,1,2,Error,Syntactic Sugar,"Shorthand syntactic sugar should be used, i.e. [Int] instead of Array",syntactic_sugar +filename,1,1,Warning,Line Length,Violation Reason 1,line_length +filename,1,,Error,Line Length,Violation Reason 2,line_length +${CURRENT_WORKING_DIRECTORY}/path/file.swift,1,2,Error,Syntactic Sugar,"Shorthand syntactic sugar should be used, i.e. [Int] instead of Array",syntactic_sugar ,,,Error,Colon Spacing,Colons should be next to the identifier when specifying a type and next to the key in dictionary literals,colon \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedCheckstyleReporterOutput.xml b/Tests/SwiftLintFrameworkTests/Resources/CannedCheckstyleReporterOutput.xml index b5cd3c2ccd..320a251ce8 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedCheckstyleReporterOutput.xml +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedCheckstyleReporterOutput.xml @@ -3,9 +3,11 @@ - - - + + + + + \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json index 9e50e3d701..c6f197c017 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedCodeClimateReporterOutput.json @@ -1,9 +1,9 @@ [ { "check_name" : "Line Length", - "description" : "Violation Reason", + "description" : "Violation Reason 1", "engine_name" : "SwiftLint", - "fingerprint" : "917a85854a9500cfd28520fa4875a3ecbba171e522f13452c7adec71fc14497a", + "fingerprint" : "4a17aef14fdc2dbdd95ab2ee78d1b7d6cc289539d290b283cbabedd30e929f5f", "location" : { "lines" : { "begin" : 1, @@ -16,9 +16,9 @@ }, { "check_name" : "Line Length", - "description" : "Violation Reason", + "description" : "Violation Reason 2", "engine_name" : "SwiftLint", - "fingerprint" : "917a85854a9500cfd28520fa4875a3ecbba171e522f13452c7adec71fc14497a", + "fingerprint" : "4a17aef14fdc2dbdd95ab2ee78d1b7d6cc289539d290b283cbabedd30e929f5f", "location" : { "lines" : { "begin" : 1, @@ -33,13 +33,13 @@ "check_name" : "Syntactic Sugar", "description" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array", "engine_name" : "SwiftLint", - "fingerprint" : "6477f518963149b01807a31e7067be97dc39a30b93673e1e246f812e9ea5ef21", + "fingerprint" : "752322cea7c7ad97a20777d51a8d44c33a7e037290344c8fed6881ec916b6f1a", "location" : { "lines" : { "begin" : 1, "end" : 1 }, - "path" : "filename" + "path" : "path/file.swift" }, "severity" : "major", "type" : "issue" diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedEmojiReporterOutput.txt b/Tests/SwiftLintFrameworkTests/Resources/CannedEmojiReporterOutput.txt index 8087d60ce3..7830e72d6c 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedEmojiReporterOutput.txt +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedEmojiReporterOutput.txt @@ -1,6 +1,7 @@ +${CURRENT_WORKING_DIRECTORY}/path/file.swift +⛔️ Line 1: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) Other ⛔️ Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) filename -⛔️ Line 1: Violation Reason (line_length) -⛔️ Line 1: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) -⚠️ Line 1: Violation Reason (line_length) \ No newline at end of file +⛔️ Line 1: Violation Reason 2 (line_length) +⚠️ Line 1: Violation Reason 1 (line_length) \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedGitHubActionsLoggingReporterOutput.txt b/Tests/SwiftLintFrameworkTests/Resources/CannedGitHubActionsLoggingReporterOutput.txt index 4303095881..b7071ab8e3 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedGitHubActionsLoggingReporterOutput.txt +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedGitHubActionsLoggingReporterOutput.txt @@ -1,4 +1,4 @@ -::warning file=filename,line=1,col=2::Violation Reason (line_length) -::error file=filename,line=1,col=2::Violation Reason (line_length) -::error file=filename,line=1,col=2::Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) +::warning file=filename,line=1,col=1::Violation Reason 1 (line_length) +::error file=filename,line=1,col=1::Violation Reason 2 (line_length) +::error file=path/file.swift,line=1,col=2::Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) ::error file=,line=1,col=1::Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedGitLabJUnitReporterOutput.xml b/Tests/SwiftLintFrameworkTests/Resources/CannedGitLabJUnitReporterOutput.xml index 339a7808d7..cfbbfc8fec 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedGitLabJUnitReporterOutput.xml +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedGitLabJUnitReporterOutput.xml @@ -3,29 +3,29 @@ Severity: warning Rule: line_length -Reason: Violation Reason +Reason: Violation Reason 1 File: filename Line: 1 -Column: 2 +Column: 1 Severity: error Rule: line_length -Reason: Violation Reason +Reason: Violation Reason 2 File: filename Line: 1 -Column: 2 +Column: nil - + Severity: error Rule: syntactic_sugar Reason: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> -File: filename +File: path/file.swift Line: 1 Column: 2 diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedHTMLReporterOutput.html b/Tests/SwiftLintFrameworkTests/Resources/CannedHTMLReporterOutput.html index 82cfc00a2f..928353df6e 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedHTMLReporterOutput.html +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedHTMLReporterOutput.html @@ -78,20 +78,20 @@

Violations

1 filename - 1:2 + 1:1 Warning - Violation Reason + Violation Reason 1 2 filename - 1:2 + 1:0 Error - Violation Reason + Violation Reason 2 3 - filename + path/file.swift 1:2 Error Shorthand syntactic sugar should be used, i.e. [Int] instead of Array<Int> @@ -114,7 +114,7 @@

Summary

Total files with violations - 1 + 2 Total warnings @@ -132,7 +132,7 @@

Summary

Created with SwiftLint - 1.2.3 on 13/12/2016 + ${SWIFTLINT_VERSION} on ${TODAYS_DATE}

\ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedJSONReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedJSONReporterOutput.json index e20478afd6..a125107eb3 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedJSONReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedJSONReporterOutput.json @@ -1,38 +1,38 @@ [ { - "reason" : "Violation Reason", - "character" : 2, + "character" : 1, "file" : "filename", - "rule_id" : "line_length", "line" : 1, + "reason" : "Violation Reason 1", + "rule_id" : "line_length", "severity" : "Warning", "type" : "Line Length" }, { - "reason" : "Violation Reason", - "character" : 2, + "character" : null, "file" : "filename", - "rule_id" : "line_length", "line" : 1, + "reason" : "Violation Reason 2", + "rule_id" : "line_length", "severity" : "Error", "type" : "Line Length" }, { - "reason" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array", "character" : 2, - "file" : "filename", - "rule_id" : "syntactic_sugar", + "file" : "${CURRENT_WORKING_DIRECTORY}/path/file.swift", "line" : 1, + "reason" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array", + "rule_id" : "syntactic_sugar", "severity" : "Error", "type" : "Syntactic Sugar" }, { - "reason" : "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals", "character" : null, "file" : null, - "rule_id" : "colon", "line" : null, + "reason" : "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals", + "rule_id" : "colon", "severity" : "Error", "type" : "Colon Spacing" } -] \ No newline at end of file +] diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedJunitReporterOutput.xml b/Tests/SwiftLintFrameworkTests/Resources/CannedJunitReporterOutput.xml index 2bb514f06f..b786f1f1f3 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedJunitReporterOutput.xml +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedJunitReporterOutput.xml @@ -2,12 +2,12 @@ - Warning:Line:1 + Warning:Line:1 - Error:Line:1 + Error:Line:1 - + Error:Line:1 diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedMarkdownReporterOutput.md b/Tests/SwiftLintFrameworkTests/Resources/CannedMarkdownReporterOutput.md index 6610899238..d74bd35e7f 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedMarkdownReporterOutput.md +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedMarkdownReporterOutput.md @@ -1,6 +1,6 @@ file | line | severity | reason | rule_id --- | --- | --- | --- | --- -filename | 1 | :warning: | Line Length: Violation Reason | line_length -filename | 1 | :stop\_sign: | Line Length: Violation Reason | line_length -filename | 1 | :stop\_sign: | Syntactic Sugar: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array | syntactic_sugar +filename | 1 | :warning: | Line Length: Violation Reason 1 | line_length +filename | 1 | :stop\_sign: | Line Length: Violation Reason 2 | line_length +${CURRENT_WORKING_DIRECTORY}/path/file.swift | 1 | :stop\_sign: | Syntactic Sugar: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array | syntactic_sugar | | :stop\_sign: | Colon Spacing: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals | colon \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedRelativePathReporterOutput.txt b/Tests/SwiftLintFrameworkTests/Resources/CannedRelativePathReporterOutput.txt index cab4b2c635..c3b7322b65 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedRelativePathReporterOutput.txt +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedRelativePathReporterOutput.txt @@ -1,4 +1,4 @@ -filename:1:2: warning: Line Length Violation: Violation Reason (line_length) -filename:1:2: error: Line Length Violation: Violation Reason (line_length) -filename:1:2: error: Syntactic Sugar Violation: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) +filename:1:1: warning: Line Length Violation: Violation Reason 1 (line_length) +filename:1:1: error: Line Length Violation: Violation Reason 2 (line_length) +path/file.swift:1:2: error: Syntactic Sugar Violation: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) :1:1: error: Colon Spacing Violation: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json index b12a09a47b..5e02405221 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedSARIFReporterOutput.json @@ -1,5 +1,5 @@ { - "$schema" : "https:\/\/docs.oasis-open.org\/sarif\/sarif\/v2.1.0\/cos02\/schemas\/sarif-schema-2.1.0.json", + "$schema" : "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json", "runs" : [ { "results" : [ @@ -12,14 +12,14 @@ "uri" : "filename" }, "region" : { - "startColumn" : 2, + "startColumn" : 1, "startLine" : 1 } } } ], "message" : { - "text" : "Violation Reason" + "text" : "Violation Reason 1" }, "ruleId" : "line_length" }, @@ -32,14 +32,14 @@ "uri" : "filename" }, "region" : { - "startColumn" : 2, + "startColumn" : 1, "startLine" : 1 } } } ], "message" : { - "text" : "Violation Reason" + "text" : "Violation Reason 2" }, "ruleId" : "line_length" }, @@ -49,7 +49,7 @@ { "physicalLocation" : { "artifactLocation" : { - "uri" : "filename" + "uri" : "path/file.swift" }, "region" : { "startColumn" : 2, @@ -82,12 +82,12 @@ ], "tool" : { "driver" : { - "informationUri" : "https:\/\/github.com\/realm\/SwiftLint\/blob\/${SWIFT_LINT_VERSION}\/README.md", + "informationUri" : "https://github.com/realm/SwiftLint/blob/${SWIFTLINT_VERSION}/README.md", "name" : "SwiftLint", - "semanticVersion" : "${SWIFT_LINT_VERSION}" + "semanticVersion" : "${SWIFTLINT_VERSION}" } } } ], "version" : "2.1.0" -} +} \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedSonarQubeReporterOutput.json b/Tests/SwiftLintFrameworkTests/Resources/CannedSonarQubeReporterOutput.json index fb2472e4eb..bb6a1529f2 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedSonarQubeReporterOutput.json +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedSonarQubeReporterOutput.json @@ -1,56 +1,56 @@ { - "issues":[ + "issues" : [ { - "engineId":"SwiftLint", - "primaryLocation":{ - "filePath":"filename", - "message":"Violation Reason", - "textRange":{ - "startLine":1 + "engineId" : "SwiftLint", + "primaryLocation" : { + "filePath" : "filename", + "message" : "Violation Reason 1", + "textRange" : { + "startLine" : 1 } }, - "ruleId":"line_length", - "severity":"MINOR", - "type":"CODE_SMELL" + "ruleId" : "line_length", + "severity" : "MINOR", + "type" : "CODE_SMELL" }, { - "engineId":"SwiftLint", - "primaryLocation":{ - "filePath":"filename", - "message":"Violation Reason", - "textRange":{ - "startLine":1 + "engineId" : "SwiftLint", + "primaryLocation" : { + "filePath" : "filename", + "message" : "Violation Reason 2", + "textRange" : { + "startLine" : 1 } }, - "ruleId":"line_length", - "severity":"MAJOR", - "type":"CODE_SMELL" + "ruleId" : "line_length", + "severity" : "MAJOR", + "type" : "CODE_SMELL" }, { - "engineId":"SwiftLint", - "primaryLocation":{ - "filePath":"filename", - "message":"Shorthand syntactic sugar should be used, i.e. [Int] instead of Array", - "textRange":{ - "startLine":1 + "engineId" : "SwiftLint", + "primaryLocation" : { + "filePath" : "path\/file.swift", + "message" : "Shorthand syntactic sugar should be used, i.e. [Int] instead of Array", + "textRange" : { + "startLine" : 1 } }, - "ruleId":"syntactic_sugar", - "severity":"MAJOR", - "type":"CODE_SMELL" + "ruleId" : "syntactic_sugar", + "severity" : "MAJOR", + "type" : "CODE_SMELL" }, { - "engineId":"SwiftLint", - "primaryLocation":{ - "filePath":"", - "message":"Colons should be next to the identifier when specifying a type and next to the key in dictionary literals", - "textRange":{ - "startLine":1 + "engineId" : "SwiftLint", + "primaryLocation" : { + "filePath" : "", + "message" : "Colons should be next to the identifier when specifying a type and next to the key in dictionary literals", + "textRange" : { + "startLine" : 1 } }, - "ruleId":"colon", - "severity":"MAJOR", - "type":"CODE_SMELL" + "ruleId" : "colon", + "severity" : "MAJOR", + "type" : "CODE_SMELL" } ] -} +} \ No newline at end of file diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedSummaryReporterOutput.txt b/Tests/SwiftLintFrameworkTests/Resources/CannedSummaryReporterOutput.txt index 5771f1c01c..211a0a0cd4 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedSummaryReporterOutput.txt +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedSummaryReporterOutput.txt @@ -6,5 +6,5 @@ | syntactic_sugar | no | yes | no | 0 | 1 | 1 | 1 | | vertical_whitespace_opening_braces | yes | yes | no | 1 | 0 | 1 | 1 | +------------------------------------+--------+-------------+--------+----------+--------+------------------+-----------------+ -| Total | | | | 2 | 3 | 5 | 2 | +| Total | | | | 2 | 3 | 5 | 3 | +------------------------------------+--------+-------------+--------+----------+--------+------------------+-----------------+ diff --git a/Tests/SwiftLintFrameworkTests/Resources/CannedXcodeReporterOutput.txt b/Tests/SwiftLintFrameworkTests/Resources/CannedXcodeReporterOutput.txt index cab4b2c635..553120fb05 100644 --- a/Tests/SwiftLintFrameworkTests/Resources/CannedXcodeReporterOutput.txt +++ b/Tests/SwiftLintFrameworkTests/Resources/CannedXcodeReporterOutput.txt @@ -1,4 +1,4 @@ -filename:1:2: warning: Line Length Violation: Violation Reason (line_length) -filename:1:2: error: Line Length Violation: Violation Reason (line_length) -filename:1:2: error: Syntactic Sugar Violation: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) +filename:1:1: warning: Line Length Violation: Violation Reason 1 (line_length) +filename:1:1: error: Line Length Violation: Violation Reason 2 (line_length) +${CURRENT_WORKING_DIRECTORY}/path/file.swift:1:2: error: Syntactic Sugar Violation: Shorthand syntactic sugar should be used, i.e. [Int] instead of Array (syntactic_sugar) :1:1: error: Colon Spacing Violation: Colons should be next to the identifier when specifying a type and next to the key in dictionary literals (colon) \ No newline at end of file From 9dbd40a4ef6a56cdfb0ef879332c171d549d5f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 26 Jul 2024 20:35:54 +0200 Subject: [PATCH 138/265] Add changelog entry for #5705 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd2a1463ad..cd227b978b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,12 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5592](https://github.com/realm/SwiftLint/issues/5592) +* Use correct types and relative paths in SARIF reporter output. Generally + avoid escaping slashes in JSON output as well. + [SimplyDanny](https://github.com/SimplyDanny) + [#5598](https://github.com/realm/SwiftLint/issues/5598) + [#5599](https://github.com/realm/SwiftLint/issues/5599) + * Keep initializers with attributed parameters in `unneeded_synthesized_initializer` rule. [SimplyDanny](https://github.com/SimplyDanny) From d28901e27e09290fed4ef0a93e1c15468c7f953c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 27 Jul 2024 18:05:14 +0200 Subject: [PATCH 139/265] Remove deprecated option `--in-process-sourcekit` entirely (#5707) --- CHANGELOG.md | 4 +++- Source/swiftlint/Commands/Analyze.swift | 1 - Source/swiftlint/Commands/Lint.swift | 1 - Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift | 2 -- Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift | 10 ---------- 5 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd227b978b..0be2545b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,10 @@ #### Breaking -* The deprecated `--path` argument has now been removed completely. +* The deprecated `--path` and `--in-process-sourcekit` arguments have now been + removed completely. [Martin Redington](https://github.com/mildm8nnered) + [SimplyDanny](https://github.com/SimplyDanny) [#5614](https://github.com/realm/SwiftLint/issues/5614) * When SwiftLint corrects violations automatically (`swiftlint lint --fix`) diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index 1a9b254bce..d000077baa 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -47,7 +47,6 @@ extension SwiftLint { format: common.format, compilerLogPath: compilerLogPath, compileCommands: compileCommands, - inProcessSourcekit: common.inProcessSourcekit, checkForUpdates: common.checkForUpdates ) diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index b0e5cdd1ad..27911e6fb5 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -59,7 +59,6 @@ extension SwiftLint { format: common.format, compilerLogPath: nil, compileCommands: nil, - inProcessSourcekit: common.inProcessSourcekit, checkForUpdates: common.checkForUpdates ) try await LintOrAnalyzeCommand.run(options) diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift index b04b6c70d8..779293fdf7 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift @@ -44,8 +44,6 @@ struct LintOrAnalyzeArguments: ParsableArguments { var writeBaseline: String? @Option(help: "The working directory to use when running SwiftLint.") var workingDirectory: String? - @Flag(help: "Use the in-process version of SourceKit.") - var inProcessSourcekit = false @Option(help: "The file where violations should be saved. Prints to stdout by default.") var output: String? @Flag(help: "Show a live-updating progress bar instead of each file being processed.") diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift index af94107f54..1994c12ff4 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift @@ -36,15 +36,6 @@ struct LintOrAnalyzeCommand { ) } } - if options.inProcessSourcekit { - // TODO: [08/11/2024] Remove deprecation warning after ~2 years. - queuedPrintError( - """ - warning: The --in-process-sourcekit option is deprecated. \ - SwiftLint now always uses an in-process SourceKit. - """ - ) - } try await Signposts.record(name: "LintOrAnalyzeCommand.run") { try await options.autocorrect ? autocorrect(options) : lintOrAnalyze(options) } @@ -286,7 +277,6 @@ struct LintOrAnalyzeOptions { let format: Bool let compilerLogPath: String? let compileCommands: String? - let inProcessSourcekit: Bool let checkForUpdates: Bool var verb: String { From 39b7c9f13461ded8469eaeb056998548494d2ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 27 Jul 2024 18:24:32 +0200 Subject: [PATCH 140/265] Move and refactor methods (#5706) --- .../Rules/Style/OpeningBraceRule.swift | 155 +++++++----------- 1 file changed, 57 insertions(+), 98 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index f1508c333f..afeab06660 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -20,128 +20,78 @@ struct OpeningBraceRule: SwiftSyntaxCorrectableRule { private extension OpeningBraceRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: ActorDeclSyntax) { - let body = node.memberBlock - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.memberBlock) } override func visitPost(_ node: ClassDeclSyntax) { - let body = node.memberBlock - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.memberBlock) } override func visitPost(_ node: EnumDeclSyntax) { - let body = node.memberBlock - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.memberBlock) } override func visitPost(_ node: ExtensionDeclSyntax) { - let body = node.memberBlock - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.memberBlock) } override func visitPost(_ node: ProtocolDeclSyntax) { - let body = node.memberBlock - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.memberBlock) } override func visitPost(_ node: StructDeclSyntax) { - let body = node.memberBlock - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.memberBlock) } override func visitPost(_ node: CatchClauseSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: DeferStmtSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: DoStmtSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: ForStmtSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: GuardStmtSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: IfExprSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } - if case let .codeBlock(body) = node.elseBody, let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) + collectViolation(for: node.body) + if case let .codeBlock(body) = node.elseBody { + collectViolation(for: body) } } override func visitPost(_ node: RepeatStmtSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: WhileStmtSyntax) { - let body = node.body - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: SwitchExprSyntax) { - if let correction = node.violationCorrection(locationConverter) { - violations.append(at: node.openingPosition, correction: correction) - } + collectViolation(for: node) } override func visitPost(_ node: AccessorDeclSyntax) { - if let body = node.body, let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.body) } override func visitPost(_ node: PatternBindingSyntax) { - if let body = node.accessorBlock, let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: node.accessorBlock) } override func visitPost(_ node: PrecedenceGroupDeclSyntax) { - if let correction = node.violationCorrection(locationConverter) { - violations.append(at: node.openingPosition, correction: correction) - } + collectViolation(for: node) } override func visitPost(_ node: ClosureExprSyntax) { @@ -153,10 +103,9 @@ private extension OpeningBraceRule { return } if parent.is(FunctionCallExprSyntax.self) || parent.is(MultipleTrailingClosureElementSyntax.self), - node.keyPathInParent != \FunctionCallExprSyntax.calledExpression, - let correction = node.violationCorrection(locationConverter) { + node.keyPathInParent != \FunctionCallExprSyntax.calledExpression { // Trailing closure - violations.append(at: node.openingPosition, correction: correction) + collectViolation(for: node) } } @@ -167,9 +116,7 @@ private extension OpeningBraceRule { if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.funcKeyword) { return } - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: body) } override func visitPost(_ node: InitializerDeclSyntax) { @@ -179,9 +126,7 @@ private extension OpeningBraceRule { if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.initKeyword) { return } - if let correction = body.violationCorrection(locationConverter) { - violations.append(at: body.openingPosition, correction: correction) - } + collectViolation(for: body) } private func refersToMultilineFunction(_ body: CodeBlockSyntax, functionIndicator: TokenSyntax) -> Bool { @@ -193,28 +138,33 @@ private extension OpeningBraceRule { let braceLocation = body.leftBrace.endLocation(converter: locationConverter) return startLocation.line != endLocation.line && endLocation.line != braceLocation.line } - } -} -private extension BracedSyntax { - typealias ViolationCorrection = ReasonedRuleViolation.ViolationCorrection - - var openingPosition: AbsolutePosition { - leftBrace.positionAfterSkippingLeadingTrivia - } + private func collectViolation(for bracedItem: (some BracedSyntax)?) { + if let bracedItem, let correction = violationCorrection(bracedItem) { + violations.append( + ReasonedRuleViolation( + position: bracedItem.openingPosition, + correction: correction + ) + ) + } + } - func violationCorrection(_ locationConverter: SourceLocationConverter) -> ViolationCorrection? { - if let previousToken = leftBrace.previousToken(viewMode: .sourceAccurate) { + private func violationCorrection(_ node: some BracedSyntax) -> ReasonedRuleViolation.ViolationCorrection? { + let leftBrace = node.leftBrace + guard let previousToken = leftBrace.previousToken(viewMode: .sourceAccurate) else { + return nil + } + let openingPosition = node.openingPosition let triviaBetween = previousToken.trailingTrivia + leftBrace.leadingTrivia let previousLocation = previousToken.endLocation(converter: locationConverter) let leftBraceLocation = leftBrace.startLocation(converter: locationConverter) - let violation = ViolationCorrection( - start: previousToken.endPositionBeforeTrailingTrivia, - end: openingPosition, - replacement: " " - ) if previousLocation.line != leftBraceLocation.line { - return violation + return .init( + start: previousToken.endPositionBeforeTrailingTrivia, + end: openingPosition, + replacement: " " + ) } if previousLocation.column + 1 == leftBraceLocation.column { return nil @@ -224,14 +174,23 @@ private extension BracedSyntax { return nil } let comment = triviaBetween.description.trimmingTrailingCharacters(in: .whitespaces) - return ViolationCorrection( + return .init( start: previousToken.endPositionBeforeTrailingTrivia + SourceLength(of: comment), end: openingPosition, replacement: " " ) } - return violation + return .init( + start: previousToken.endPositionBeforeTrailingTrivia, + end: openingPosition, + replacement: " " + ) } - return nil + } +} + +private extension BracedSyntax { + var openingPosition: AbsolutePosition { + leftBrace.positionAfterSkippingLeadingTrivia } } From 103e585b56170e4d22c2f979da9932356a340083 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 28 Jul 2024 19:05:03 +0100 Subject: [PATCH 141/265] Make sure that violations of the typesafe_array_init rule are correctly reported as violations of that rule rather than array_init (#5710) --- CHANGELOG.md | 6 ++++++ .../Rules/Lint/TypesafeArrayInitRule.swift | 2 +- .../TypesafeArrayInitRuleTests.swift | 19 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 Tests/SwiftLintFrameworkTests/TypesafeArrayInitRuleTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 0be2545b4c..32590667f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,12 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5598](https://github.com/realm/SwiftLint/issues/5598) +* Violations of the `typesafe_array_init` rule will now be correctly + reported as such, instead of as violations of the `array_init` + rule. + [Martin Redington](https://github.com/mildm8nnered) + [#5709](https://github.com/realm/SwiftLint/issues/5709) + ## 0.55.1: Universal Washing Powder #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift index 129cbd66cc..0d7ea85937 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift @@ -76,7 +76,7 @@ struct TypesafeArrayInitRule: AnalyzerRule { return false } return pointsToSystemMapType(pointee: request) - } + }.map { StyleViolation(ruleDescription: Self.description, location: $0.location ) } } private func pointsToSystemMapType(pointee: [String: any SourceKitRepresentable]) -> Bool { diff --git a/Tests/SwiftLintFrameworkTests/TypesafeArrayInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/TypesafeArrayInitRuleTests.swift new file mode 100644 index 0000000000..59d0769491 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/TypesafeArrayInitRuleTests.swift @@ -0,0 +1,19 @@ +@testable import SwiftLintBuiltInRules +import XCTest + +final class TypesafeArrayInitRuleTests: SwiftLintTestCase { + func testViolationRuleIdentifier() { + let baseDescription = TypesafeArrayInitRule.description + guard let triggeringExample = baseDescription.triggeringExamples.first else { + XCTFail("No triggering examples found") + return + } + guard let config = makeConfig(nil, baseDescription.identifier) else { + XCTFail("Failed to create configuration") + return + } + let violations = SwiftLintFrameworkTests.violations(triggeringExample, config: config, requiresFileOnDisk: true) + XCTAssertGreaterThanOrEqual(violations.count, 1) + XCTAssertEqual(violations.first?.ruleIdentifier, baseDescription.identifier) + } +} From 1f1dca36589b4211478e6f0c53557cea49accb77 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 29 Jul 2024 16:48:36 +0200 Subject: [PATCH 142/265] Clarify usage of custom rules under only rules (#5712) --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 190cca2ffd..dc97e44e70 100644 --- a/README.md +++ b/README.md @@ -851,8 +851,18 @@ All syntax kinds used in a snippet of Swift code can be extracted asking which match to `keyword` and `identifier` in the above list. -If using custom rules in combination with `only_rules`, make sure to add -`custom_rules` as an item under `only_rules`. +If using custom rules in combination with `only_rules`, you must include the +literal string `custom_rules` in the `only_rules` list: + +```yaml +only_rules: + - custom_rules + +custom_rules: + no_hiding_in_strings: + regex: "([nN]inja)" + match_kinds: string +``` Unlike Swift custom rules, you can use official SwiftLint builds (e.g. from Homebrew) to run regex custom rules. From 5f4149c308eeae79d45bc7c9ecfe2edfb3bb21dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 29 Jul 2024 21:38:44 +0200 Subject: [PATCH 143/265] Remove spaces before and after slashes used as "or" --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dc97e44e70..e5868b1cec 100644 --- a/README.md +++ b/README.md @@ -921,9 +921,9 @@ opt_in_rules: - force_cast ``` -### Child / Parent Configs (Locally) +### Child/Parent Configs (Locally) -You can specify a `child_config` and / or a `parent_config` reference within a +You can specify a `child_config` and/or a `parent_config` reference within a configuration file. These references should be local paths relative to the folder of the configuration file they are specified in. This even works recursively, as long as there are no cycles and no ambiguities. @@ -954,9 +954,9 @@ When merging parent and child configs, `included` and `excluded` configurations are processed carefully to account for differences in the directory location of the containing configuration files. -### Child / Parent Configs (Remote) +### Child/Parent Configs (Remote) -Just as you can provide local `child_config` / `parent_config` references, +Just as you can provide local `child_config`/`parent_config` references, instead of referencing local paths, you can just put urls that lead to configuration files. In order for SwiftLint to detect these remote references, they must start with `http://` or `https://`. @@ -978,8 +978,8 @@ there once SwiftLint has run successfully at least once. If needed, the timeouts for the remote configuration fetching can be specified manually via the configuration file(s) using the -`remote_timeout` / `remote_timeout_if_cached` specifiers. These values default -to 2 / 1 second(s). +`remote_timeout`/`remote_timeout_if_cached` specifiers. These values default +to 2 seconds or 1 second, respectively. ### Command Line @@ -1006,7 +1006,7 @@ configuration. `.swiftlint.yml` files are only considered as a nested configuration if they have not been used to build the main configuration already (e. g. by having been referenced via something like `child_config: Folder/.swiftlint.yml`). -Also, `parent_config` / `child_config` specifications of nested configurations +Also, `parent_config`/`child_config` specifications of nested configurations are getting ignored because there's no sense to that. If one (or more) SwiftLint file(s) are explicitly specified via the `--config` From e44bf9adb6ab7333afdd5b574fd10fbd10b51593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 30 Jul 2024 22:23:01 +0200 Subject: [PATCH 144/265] Add new `brace_on_new_line` option to `opening_brace` rule (#5708) --- CHANGELOG.md | 4 + .../OpeningBraceConfiguration.swift | 2 + .../Rules/Style/OpeningBraceRule.swift | 28 ++++++- .../Style/OpeningBraceRuleExamples.swift | 79 +++++++++++++++++++ .../default_rule_configurations.yml | 1 + 5 files changed, 112 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32590667f0..e13e2e49a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,10 @@ [Ueeek](https://github.com/Ueeek) [#5615](https://github.com/realm/SwiftLint/issues/5615) +* Add new `brace_on_new_line` option to `opening_brace` rule that enforces opening + braces to be on a separate line after the preceding declaration. + [SimplyDanny](https://github.com/SimplyDanny) + * Add new `unused_parameter` rule that triggers on function/initializer/subscript parameters that are not used inside of the function/initializer/subscript. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift index 1e72688009..bac9426c26 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift @@ -8,4 +8,6 @@ struct OpeningBraceConfiguration: SeverityBasedRuleConfiguration { private(set) var severityConfiguration = SeverityConfiguration(.warning) @ConfigurationElement(key: "allow_multiline_func") private(set) var allowMultilineFunc = false + @ConfigurationElement(key: "brace_on_new_line") + private(set) var braceOnNewLine = false } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index afeab06660..79818a2dc3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -8,8 +8,14 @@ struct OpeningBraceRule: SwiftSyntaxCorrectableRule { static let description = RuleDescription( identifier: "opening_brace", name: "Opening Brace Spacing", - description: "Opening braces should be preceded by a single space and on the same line " + - "as the declaration", + description: """ + The correct positioning of braces that introduce a block of code or member list is highly controversial. \ + No matter which style is preferred, consistency is key. Apart from different tastes, \ + the positioning of braces can also have a significant impact on the readability of the code, \ + especially for visually impaired developers. This rule ensures that braces are either preceded \ + by a single space and on the same line as the declaration or on a separate line after the declaration \ + itself. Comments between the declaration and the opening brace are respected. + """, kind: .style, nonTriggeringExamples: OpeningBraceRuleExamples.nonTriggeringExamples, triggeringExamples: OpeningBraceRuleExamples.triggeringExamples, @@ -144,6 +150,12 @@ private extension OpeningBraceRule { violations.append( ReasonedRuleViolation( position: bracedItem.openingPosition, + reason: configuration.braceOnNewLine + ? "Opening brace should be on a separate line" + : """ + Opening braces should be preceded by a single space and on the same line \ + as the declaration + """, correction: correction ) ) @@ -159,6 +171,18 @@ private extension OpeningBraceRule { let triviaBetween = previousToken.trailingTrivia + leftBrace.leadingTrivia let previousLocation = previousToken.endLocation(converter: locationConverter) let leftBraceLocation = leftBrace.startLocation(converter: locationConverter) + if configuration.braceOnNewLine { + let parentStartColumn = node.parent?.startLocation(converter: locationConverter).column ?? 1 + if previousLocation.line + 1 == leftBraceLocation.line, leftBraceLocation.column == parentStartColumn { + return nil + } + let comment = triviaBetween.description.trimmingTrailingCharacters(in: .whitespacesAndNewlines) + return .init( + start: previousToken.endPositionBeforeTrailingTrivia + SourceLength(of: comment), + end: openingPosition, + replacement: "\n" + String(repeating: " ", count: parentStartColumn - 1) + ) + } if previousLocation.line != leftBraceLocation.line { return .init( start: previousToken.endPositionBeforeTrailingTrivia, diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index e41dc09977..9d663d2e6b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -58,6 +58,18 @@ struct OpeningBraceRuleExamples { return } """), + Example(""" + if c + { + // code here + } + """, configuration: ["brace_on_new_line": true]), + Example(""" + @MyProperty struct S + { + // code here + } + """, configuration: ["brace_on_new_line": true]), ] static let triggeringExamples = [ @@ -217,6 +229,17 @@ struct OpeningBraceRuleExamples { if c ↓{} else /* comment */ ↓{} """), + Example(""" + if c + ↓{ + // code here + } + """, configuration: ["brace_on_new_line": true]), + Example(""" + @MyProperty struct S ↓{ + // code here + } + """, configuration: ["brace_on_new_line": true]), ] static let corrections = [ @@ -581,5 +604,61 @@ struct OpeningBraceRuleExamples { // code here } """), + Example(""" + if c + { + // code here + } + """, configuration: ["brace_on_new_line": true]): Example(""" + if c + { + // code here + } + """), + Example(""" + @MyProperty struct S { + // code here + } + """, configuration: ["brace_on_new_line": true]): Example(""" + @MyProperty struct S + { + // code here + } + """), + Example(""" + private func f() + + { + let a = 1 + } + """, configuration: ["brace_on_new_line": true]): Example(""" + private func f() + { + let a = 1 + } + """), + Example(""" + private func f() + // comment + { + let a = 1 + } + """, configuration: ["brace_on_new_line": true]): Example(""" + private func f() + // comment + { + let a = 1 + } + """), + Example(""" + while true /* endless loop */ { + // nothing + } + """, configuration: ["brace_on_new_line": true]): Example(""" + while true /* endless loop */ + { + // nothing + } + """), ] } diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 990c7b2e64..ae99c4e9a0 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -376,6 +376,7 @@ one_declaration_per_file: opening_brace: severity: warning allow_multiline_func: false + brace_on_new_line: false operator_usage_whitespace: severity: warning lines_look_around: 2 From 5f804d005b3537df339f3a8b30187cb7cb1e1e6e Mon Sep 17 00:00:00 2001 From: UIApplicationMain Date: Wed, 31 Jul 2024 12:40:21 -0400 Subject: [PATCH 145/265] Remove extra case statement in example (#5717) --- .../Rules/Style/EmptyEnumArgumentsRule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift index f6d5409b95..fc58da0b89 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift @@ -17,7 +17,7 @@ private func wrapInFunc(_ str: String, file: StaticString = #filePath, line: UIn Example(""" func example(foo: Foo) { switch foo { - case \(str): + \(str): break } } From 75d3a87e968a2512f78f75005f9ec3d5d45fff9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 31 Jul 2024 23:01:39 +0200 Subject: [PATCH 146/265] Treat specialized imports with attributes as unique (#5718) --- CHANGELOG.md | 5 ++++ .../Idiomatic/DuplicateImportsRule.swift | 30 ++++++++++++++----- .../DuplicateImportsRuleExamples.swift | 10 +++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e13e2e49a3..d9ad638b29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,6 +91,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5592](https://github.com/realm/SwiftLint/issues/5592) +* Don't consider specialized imports with attributes as duplicates in + `duplicate_imports` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5716](https://github.com/realm/SwiftLint/issues/5716) + * Use correct types and relative paths in SARIF reporter output. Generally avoid escaping slashes in JSON output as well. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift index 190e8e0b6d..69514185f5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRule.swift @@ -42,16 +42,26 @@ struct DuplicateImportsRule: SwiftSyntaxCorrectableRule { // MARK: - Private +private struct Import { + let position: AbsolutePosition + let path: [String] + let hasAttributes: Bool +} + private final class ImportPathVisitor: SyntaxVisitor { - var importPaths = [AbsolutePosition: [String]]() - var sortedImportPaths: [(position: AbsolutePosition, path: [String])] { - importPaths - .sorted { $0.key < $1.key } - .map { (position: $0, path: $1) } + var importPaths = [Import]() + var sortedImportPaths: [Import] { + importPaths.sorted { $0.position < $1.position } } override func visitPost(_ node: ImportDeclSyntax) { - importPaths[node.positionAfterSkippingLeadingTrivia] = node.path.map(\.name.text) + importPaths.append( + .init( + position: node.positionAfterSkippingLeadingTrivia, + path: node.path.map(\.name.text), + hasAttributes: node.attributes.contains { $0.is(AttributeSyntax.self) } + ) + ) } } @@ -100,7 +110,9 @@ private extension SwiftLintFile { var seen = Set() // Exact matches - for (position, path) in importPaths { + for `import` in importPaths { + let path = `import`.path + let position = `import`.position let rangesForPosition = ranges(for: position) defer { @@ -127,7 +139,9 @@ private extension SwiftLintFile { } // Partial matches - for (position, path) in importPaths { + for `import` in importPaths where !`import`.hasAttributes { + let path = `import`.path + let position = `import`.position let violation = importPaths.contains { other in let otherPath = other.path guard path.starts(with: otherPath), otherPath != path else { return false } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift index 848c082da6..4a0613fc88 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/DuplicateImportsRuleExamples.swift @@ -33,6 +33,10 @@ internal struct DuplicateImportsRuleExamples { func test() { } """), + Example(""" + import Foo + @testable import struct Foo.Bar + """), ] static let triggeringExamples = Array(corrections.keys.sorted()) @@ -127,6 +131,12 @@ internal struct DuplicateImportsRuleExamples { """), Example(""" + @testable import Foo + import struct Foo.Bar + """): Example(""" + @testable import Foo + """), + Example(""" ↓import A.B.C ↓import A.B import A From 9309f178254868e2261ae6a261620fc6ecdd1e1c Mon Sep 17 00:00:00 2001 From: wanxiangchwng Date: Fri, 2 Aug 2024 02:14:16 +0900 Subject: [PATCH 147/265] Fix some typos (#5719) Signed-off-by: wanxiangchwng --- Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift | 2 +- Source/SwiftLintCore/Models/Configuration.swift | 4 ++-- Source/SwiftLintCore/Models/RuleIdentifier.swift | 2 +- .../RuleConfigurations/SeverityLevelsConfiguration.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift index a685b55777..d279bb1dae 100644 --- a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift @@ -193,7 +193,7 @@ extension SourceKittenDictionary { /// Block executed for every encountered entity during traversal of a dictionary. public typealias TraverseBlock = (_ parent: SourceKittenDictionary, _ entity: SourceKittenDictionary) -> T? - /// Traversing all substuctures of the dictionary hierarchically, calling `traverseBlock` on each node. + /// Traversing all substructures of the dictionary hierarchically, calling `traverseBlock` on each node. /// Traversing using depth first strategy, so deepest substructures will be passed to `traverseBlock` first. /// /// - parameter traverseBlock: block that will be called for each substructure in the dictionary. diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 35a86abfe5..47401ed79e 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -130,7 +130,7 @@ public struct Configuration { /// - parameter allRulesWrapped: The rules with their own configurations already applied. /// - parameter ruleList: The list of all rules. Used for alias resolving and as a fallback /// if `allRulesWrapped` is nil. - /// - parameter filePath The underlaying file graph. If `nil` is specified, a empty file graph + /// - parameter filePath The underlying file graph. If `nil` is specified, a empty file graph /// with the current working directory as the `rootDirectory` will be used. /// - parameter includedPaths: Included paths to lint. /// - parameter excludedPaths: Excluded paths to not lint. @@ -138,7 +138,7 @@ public struct Configuration { /// - parameter warningThreshold: The threshold for the number of warnings to tolerate before treating the /// lint as having failed. /// - parameter reporter: The identifier for the `Reporter` to use to report style violations. - /// - parameter cachePath: The location of the persisted cache to use whith this configuration. + /// - parameter cachePath: The location of the persisted cache to use with this configuration. /// - parameter pinnedVersion: The SwiftLint version defined in this configuration. /// - parameter allowZeroLintableFiles: Allow SwiftLint to exit successfully when passed ignored or unlintable /// files. diff --git a/Source/SwiftLintCore/Models/RuleIdentifier.swift b/Source/SwiftLintCore/Models/RuleIdentifier.swift index 9908adf668..c4ee97f5ba 100644 --- a/Source/SwiftLintCore/Models/RuleIdentifier.swift +++ b/Source/SwiftLintCore/Models/RuleIdentifier.swift @@ -14,7 +14,7 @@ public enum RuleIdentifier: Hashable, ExpressibleByStringLiteral { private static let allStringRepresentation = "all" - /// The spelling of the string for this idenfitier. + /// The spelling of the string for this identifier. public var stringRepresentation: String { switch self { case .all: diff --git a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift index 7ea3de8ed3..4761a0f011 100644 --- a/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/SeverityLevelsConfiguration.swift @@ -7,7 +7,7 @@ public struct SeverityLevelsConfiguration: RuleConfiguration, Inli @ConfigurationElement(key: "error") public var error: Int? - /// Create a `SeverityLevelsConfiguration` based on the sepecified `warning` and `error` thresholds. + /// Create a `SeverityLevelsConfiguration` based on the specified `warning` and `error` thresholds. /// /// - parameter warning: The threshold for a violation to be a warning. /// - parameter error: The threshold for a violation to be an error. From b8a8c954faed372fd395ce57264de1a95a666936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 3 Aug 2024 00:01:28 +0200 Subject: [PATCH 148/265] Update Bazel dependencies (#5720) --- MODULE.bazel | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index bbf3cb70c7..91a2ba3b29 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,15 +5,15 @@ module( repo_name = "SwiftLint", ) -bazel_dep(name = "apple_support", version = "1.13.0", repo_name = "build_bazel_apple_support") -bazel_dep(name = "bazel_skylib", version = "1.5.0") -bazel_dep(name = "platforms", version = "0.0.8") -bazel_dep(name = "rules_apple", version = "3.3.0", repo_name = "build_bazel_rules_apple") -bazel_dep(name = "rules_swift", version = "1.16.0", repo_name = "build_bazel_rules_swift") +bazel_dep(name = "apple_support", version = "1.16.0", repo_name = "build_bazel_apple_support") +bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "platforms", version = "0.0.10") +bazel_dep(name = "rules_apple", version = "3.6.0", repo_name = "build_bazel_rules_apple") +bazel_dep(name = "rules_swift", version = "1.18.0", repo_name = "build_bazel_rules_swift") bazel_dep(name = "sourcekitten", version = "0.35.0", repo_name = "com_github_jpsim_sourcekitten") bazel_dep(name = "swift-syntax", version = "600.0.0-prerelease-2024-07-24", repo_name = "SwiftSyntax") bazel_dep(name = "swift_argument_parser", version = "1.3.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") -bazel_dep(name = "yams", version = "5.0.6", repo_name = "sourcekitten_com_github_jpsim_yams") +bazel_dep(name = "yams", version = "5.1.3", repo_name = "sourcekitten_com_github_jpsim_yams") swiftlint_repos = use_extension("//bazel:repos.bzl", "swiftlint_repos_bzlmod") use_repo( From a657438cafbb3e58cceb7cc2ab3c775413af0921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 3 Aug 2024 00:05:28 +0200 Subject: [PATCH 149/265] Add new `prefer_key_path` rule (#5548) --- .swiftlint.yml | 1 + CHANGELOG.md | 5 + .../Models/BuiltInRules.swift | 1 + .../Rules/Idiomatic/PreferKeyPathRule.swift | 221 ++++++++++++++++++ .../PreferKeyPathConfiguration.swift | 11 + Tests/GeneratedTests/GeneratedTests.swift | 6 + .../default_rule_configurations.yml | 3 + 7 files changed, 248 insertions(+) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift create mode 100644 Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PreferKeyPathConfiguration.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index fc5d5cd6db..836a6680eb 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -37,6 +37,7 @@ disabled_rules: - no_grouping_extension - no_magic_numbers - one_declaration_per_file + - prefer_key_path - prefer_nimble - prefixed_toplevel_constant - required_deinit diff --git a/CHANGELOG.md b/CHANGELOG.md index d9ad638b29..9a31cd4d3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,11 @@ [woxtu](https://github.com/woxtu) [SimplyDanny](https://github.com/SimplyDanny) +* Add new `prefer_key_path` rule that triggers when a trailing closure on a function + call is only hosting a (chained) member access expression since the closure can be + replaced with a key path argument. + [SimplyDanny](https://github.com/SimplyDanny) + * Adds `baseline` and `write_baseline` configuration file settings, equivalent to the `--baseline` and `--write-baseline` command line options. [Martin Redington](https://github.com/mildm8nnered) diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 2db9b04f44..e0da36c3ca 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -147,6 +147,7 @@ public let builtInRules: [any Rule.Type] = [ OverrideInExtensionRule.self, PatternMatchingKeywordsRule.self, PeriodSpacingRule.self, + PreferKeyPathRule.self, PreferNimbleRule.self, PreferSelfInStaticReferencesRule.self, PreferSelfTypeOverTypeOfSelfRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift new file mode 100644 index 0000000000..1c5d8d70f1 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift @@ -0,0 +1,221 @@ +import SwiftLintCore +import SwiftSyntax + +@SwiftSyntaxRule(explicitRewriter: true) +struct PreferKeyPathRule: OptInRule { + var configuration = PreferKeyPathConfiguration() + + private static let checkAllClosures = ["restrict_to_standard_functions": false] + + static var description = RuleDescription( + identifier: "prefer_key_path", + name: "Prefer Key Path", + description: "Use a key path argument instead of a closure with property access", + kind: .idiomatic, + minSwiftVersion: .fiveDotTwo, + nonTriggeringExamples: [ + Example("f {}"), + Example("f { $0 }"), + Example("f { $0.a }"), + Example("let f = { $0.a }(b)"), + Example("f {}", configuration: checkAllClosures), + Example("f { $0 }", configuration: checkAllClosures), + Example("f() { g() }", configuration: checkAllClosures), + Example("f { a.b.c }", configuration: checkAllClosures), + Example("f { a in a }", configuration: checkAllClosures), + Example("f { a, b in a.b }", configuration: checkAllClosures), + Example("f { (a, b) in a.b }", configuration: checkAllClosures), + Example("f { $0.a } g: { $0.b }", configuration: checkAllClosures), + Example("[1, 2, 3].reduce(1) { $0 + $1 }", configuration: checkAllClosures), + ], + triggeringExamples: [ + Example("f.map ↓{ $0.a }"), + Example("f.filter ↓{ $0.a }"), + Example("f.first ↓{ $0.a }"), + Example("f.contains ↓{ $0.a }"), + Example("f.contains(where: ↓{ $0.a })"), + Example("f ↓{ $0.a }", configuration: checkAllClosures), + Example("f ↓{ a in a.b }", configuration: checkAllClosures), + Example("f ↓{ a in a.b.c }", configuration: checkAllClosures), + Example("f ↓{ (a: A) in a.b }", configuration: checkAllClosures), + Example("f ↓{ (a b: A) in b.c }", configuration: checkAllClosures), + Example("f ↓{ $0.0.a }", configuration: checkAllClosures), + Example("f(a: ↓{ $0.b })", configuration: checkAllClosures), + Example("f ↓{ $0.a.b }", configuration: checkAllClosures), + Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: checkAllClosures), + ], + corrections: [ + Example("f.map { $0.a }"): + Example("f.map(\\.a)"), + Example(""" + // begin + f.map { $0.a } // end + """): + Example(""" + // begin + f.map(\\.a) // end + """), + Example("f.map({ $0.a })"): + Example("f.map(\\.a)"), + Example("f { $0.a }", configuration: checkAllClosures): + Example("f(\\.a)"), + Example("f() { $0.a }", configuration: checkAllClosures): + Example("f(\\.a)"), + Example("let f = /* begin */ { $0.a } // end", configuration: checkAllClosures): + Example("let f = /* begin */ \\.a // end"), + Example("let f = { $0.a }(b)"): + Example("let f = { $0.a }(b)"), + Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: checkAllClosures): + Example("let f: (Int) -> Int = \\.bigEndian"), + Example("f ↓{ $0.a.b }", configuration: checkAllClosures): + Example("f(\\.a.b)"), + Example("f.contains ↓{ $0.a.b }", configuration: checkAllClosures): + Example("f.contains(where: \\.a.b)"), + Example("f.first ↓{ element in element.a }", configuration: checkAllClosures): + Example("f.first(where: \\.a)"), + ] + ) +} + +private extension PreferKeyPathRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: ClosureExprSyntax) { + if node.isInvalid(standardFunctionsOnly: configuration.restrictToStandardFunctions) { + return + } + if node.onlyExprStmt?.accesses(identifier: node.onlyParameter) == true { + violations.append(node.positionAfterSkippingLeadingTrivia) + } + } + } + + final class Rewriter: ViolationsSyntaxRewriter { + override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { + if configuration.restrictToStandardFunctions, !node.isStandardFunction { + return super.visit(node) + } + guard node.additionalTrailingClosures.isEmpty, + let closure = node.trailingClosure, + let expr = closure.onlyExprStmt, + expr.accesses(identifier: closure.onlyParameter) == true, + let declName = expr.as(MemberAccessExprSyntax.self) else { + return super.visit(node) + } + correctionPositions.append(closure.positionAfterSkippingLeadingTrivia) + var node = node.with(\.calledExpression, node.calledExpression.with(\.trailingTrivia, [])) + if node.leftParen == nil { + node = node.with(\.leftParen, .leftParenToken()) + } + let newArg = LabeledExprSyntax( + label: ["contains", "first"].contains(node.calleeName) ? "where" : nil, + expression: declName.asKeyPath + ) + node = node.with( + \.arguments, + node.arguments + [newArg] + ) + if node.rightParen == nil { + node = node.with(\.rightParen, .rightParenToken()) + } + node = node + .with(\.trailingClosure, nil) + .with(\.trailingTrivia, node.trailingTrivia) + return super.visit(node) + } + + override func visit(_ node: ClosureExprSyntax) -> ExprSyntax { + if node.isInvalid(standardFunctionsOnly: configuration.restrictToStandardFunctions) { + return super.visit(node) + } + if let expr = node.onlyExprStmt, + expr.accesses(identifier: node.onlyParameter) == true, + let declName = expr.as(MemberAccessExprSyntax.self) { + correctionPositions.append(node.positionAfterSkippingLeadingTrivia) + let node = declName.asKeyPath + .with(\.leadingTrivia, node.leadingTrivia) + .with(\.trailingTrivia, node.trailingTrivia) + return super.visit(node) + } + return super.visit(node) + } + } +} + +private extension ExprSyntax { + func accesses(identifier: String?) -> Bool { + if let base = `as`(MemberAccessExprSyntax.self)?.base { + if let declRef = base.as(DeclReferenceExprSyntax.self) { + return declRef.baseName.text == identifier ?? "$0" + } + return base.accesses(identifier: identifier) + } + return false + } +} + +private extension ClosureExprSyntax { + var onlyParameter: String? { + switch signature?.parameterClause { + case let .simpleInput(params): + return params.onlyElement?.name.text + case let .parameterClause(params): + let param = params.parameters.onlyElement + return param?.secondName?.text ?? param?.firstName.text + case nil: return nil + } + } + + var onlyExprStmt: ExprSyntax? { + if case let .expr(expr) = statements.onlyElement?.item { + return expr + } + return nil + } + + private var surroundingFunction: FunctionCallExprSyntax? { + parent?.as(FunctionCallExprSyntax.self) + ?? parent?.as(LabeledExprSyntax.self)?.parent?.parent?.as(FunctionCallExprSyntax.self) + } + + func isInvalid(standardFunctionsOnly: Bool) -> Bool { + keyPathInParent == \FunctionCallExprSyntax.calledExpression + || parent?.is(MultipleTrailingClosureElementSyntax.self) == true + || surroundingFunction?.additionalTrailingClosures.isNotEmpty == true + || standardFunctionsOnly && surroundingFunction?.isStandardFunction == false + } +} + +private extension FunctionCallExprSyntax { + var isStandardFunction: Bool { + if let calleeName { + return [ + "allSatisfy", + "contains", + "filter", + "first", + "flatMap", + "map", + ].contains(calleeName) + } + return false + } + + var calleeName: String? { + (calledExpression.as(DeclReferenceExprSyntax.self) + ?? calledExpression.as(MemberAccessExprSyntax.self)?.declName)?.baseName.text + } +} + +private extension MemberAccessExprSyntax { + var asKeyPath: ExprSyntax { + var this = base + var elements = [declName] + while this?.is(DeclReferenceExprSyntax.self) != true { + if let memberAccess = this?.as(MemberAccessExprSyntax.self) { + elements.append(memberAccess.declName) + this = memberAccess.base + } + } + return "\\.\(raw: elements.reversed().map(\.baseName.text).joined(separator: "."))" as ExprSyntax + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PreferKeyPathConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PreferKeyPathConfiguration.swift new file mode 100644 index 0000000000..1df784c41e --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/PreferKeyPathConfiguration.swift @@ -0,0 +1,11 @@ +import SwiftLintCore + +@AutoConfigParser +struct PreferKeyPathConfiguration: SeverityBasedRuleConfiguration { + typealias Parent = PreferKeyPathRule + + @ConfigurationElement(key: "severity") + private(set) var severityConfiguration = SeverityConfiguration(.warning) + @ConfigurationElement(key: "restrict_to_standard_functions") + private(set) var restrictToStandardFunctions = true +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 84f639a8ff..b2e2fc912f 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -871,6 +871,12 @@ final class PeriodSpacingRuleGeneratedTests: SwiftLintTestCase { } } +final class PreferKeyPathRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(PreferKeyPathRule.description) + } +} + final class PreferNimbleRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PreferNimbleRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index ae99c4e9a0..51167c21db 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -398,6 +398,9 @@ pattern_matching_keywords: severity: warning period_spacing: severity: warning +prefer_key_path: + severity: warning + restrict_to_standard_functions: true prefer_nimble: severity: warning prefer_self_in_static_references: From 88191fe58e247b5c95faf8c988cc4dc9d8229380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 3 Aug 2024 14:21:47 +0200 Subject: [PATCH 150/265] Enable `prefer_key_path` rule and fix all violations (#5721) --- .swiftlint.yml | 1 - .../Rules/Idiomatic/ObjectLiteralRule.swift | 4 +--- .../Idiomatic/XCTSpecificMatcherRule.swift | 2 +- .../Lint/AccessibilityLabelForImageRule.swift | 4 ++-- .../Rules/Lint/BlanketDisableCommandRule.swift | 2 +- .../Rules/Lint/DuplicateConditionsRule.swift | 2 +- .../Rules/Lint/DuplicateEnumCasesRule.swift | 2 +- .../Rules/Lint/ExpiringTodoRule.swift | 2 +- .../Rules/Lint/UnusedDeclarationRule.swift | 2 +- .../Rules/Lint/UnusedImportRule.swift | 6 +++--- .../Rules/Metrics/LineLengthRule.swift | 2 +- .../MissingDocsConfiguration.swift | 2 +- .../Rules/Style/FileTypesOrderRule.swift | 2 +- .../Rules/Style/ModifierOrderRule.swift | 2 +- .../Rules/Style/MultilineArgumentsRule.swift | 2 +- .../Style/MultilineFunctionChainsRule.swift | 4 ++-- .../Rules/Style/SortedImportsRule.swift | 2 +- .../Rules/Style/StatementPositionRule.swift | 2 +- .../Rules/Style/TypeContentsOrderRule.swift | 2 +- .../Rules/Style/UnusedOptionalBindingRule.swift | 4 +--- .../Documentation/RuleListDocumentation.swift | 2 +- .../Extensions/Configuration+Parsing.swift | 2 +- .../Extensions/Configuration+RulesWrapper.swift | 17 ++++++++--------- .../Extensions/Dictionary+SwiftLint.swift | 2 +- .../Extensions/SwiftLintFile+Cache.swift | 2 +- .../Extensions/SwiftLintFile+Regex.swift | 8 ++++---- Source/SwiftLintCore/Models/Baseline.swift | 2 +- Source/SwiftLintCore/Models/Linter.swift | 8 ++++---- Source/SwiftLintCore/Models/Region.swift | 4 ++-- .../Models/RuleConfigurationDescription.swift | 2 +- Source/SwiftLintCore/Models/RuleList.swift | 3 ++- .../Models/SwiftLintSyntaxMap.swift | 2 +- .../Models/SwiftLintSyntaxToken.swift | 2 +- .../SwiftLintCore/Reporters/HTMLReporter.swift | 2 +- .../Reporters/SummaryReporter.swift | 4 ++-- .../RuleConfigurations/RegexConfiguration.swift | 2 +- Source/SwiftLintCore/Rules/CustomRules.swift | 2 +- .../DeclaredIdentifiersTrackingVisitor.swift | 4 +--- .../Extensions/Configuration+CommandLine.swift | 2 +- .../SwiftLintFrameworkTests/BaselineTests.swift | 2 +- .../SwiftLintFrameworkTests/CommandTests.swift | 6 ++---- .../ConfigurationAliasesTests.swift | 2 +- .../ConfigurationTests.swift | 6 +++--- Tests/SwiftLintTestHelpers/TestHelpers.swift | 8 ++++---- 44 files changed, 69 insertions(+), 78 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 836a6680eb..fc5d5cd6db 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -37,7 +37,6 @@ disabled_rules: - no_grouping_extension - no_magic_numbers - one_declaration_per_file - - prefer_key_path - prefer_nimble - prefixed_toplevel_constant - required_deinit diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift index 44696dc92f..4cb5a9eaa2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ObjectLiteralRule.swift @@ -66,9 +66,7 @@ private extension ObjectLiteralRule { return false } - return node.arguments.allSatisfy { elem in - elem.expression.canBeExpressedAsColorLiteralParams - } + return node.arguments.allSatisfy(\.expression.canBeExpressedAsColorLiteralParams) } private func inits(forClasses names: [String]) -> [String] { diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift index f99ed60dcb..2a762a01b9 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/XCTSpecificMatcherRule.swift @@ -122,7 +122,7 @@ private enum TwoArgsXCTAssert: String { // let arguments = node.arguments .prefix(2) - .map { $0.expression.trimmedDescription } + .map(\.expression.trimmedDescription) .sorted { arg1, _ -> Bool in protectedArguments.contains(arg1) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift index 1c59e13568..c946cef5e4 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AccessibilityLabelForImageRule.swift @@ -98,7 +98,7 @@ private extension SourceKittenDictionary { // Image(decorative: "myImage").resizable().frame // --> Image(decorative: "myImage").resizable // --> Image - return substructure.contains(where: { $0.isImage }) + return substructure.contains(where: \.isImage) } /// Whether or not the dictionary represents a SwiftUI Image using the `Image(decorative:)` constructor (hides @@ -119,7 +119,7 @@ private extension SourceKittenDictionary { // Image(decorative: "myImage").resizable().frame // --> Image(decorative: "myImage").resizable // --> Image - return substructure.contains(where: { $0.isDecorativeOrLabeledImage }) + return substructure.contains(where: \.isDecorativeOrLabeledImage) } /// Whether or not the dictionary represents a SwiftUI View with an `accesibilityLabel(_:)` diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift index 87d37e5d65..2a576740f7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/BlanketDisableCommandRule.swift @@ -167,7 +167,7 @@ struct BlanketDisableCommandRule: Rule, SourceKitFreeRule { } for command in file.commands { - let ruleIdentifiers: Set = Set(command.ruleIdentifiers.map { $0.stringRepresentation }) + let ruleIdentifiers: Set = Set(command.ruleIdentifiers.map(\.stringRepresentation)) let intersection = ruleIdentifiers.intersection(configuration.alwaysBlanketDisableRuleIdentifiers) if command.action == .enable { violations.append(contentsOf: intersection.map { diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift index b947c024f3..04c5f512ce 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateConditionsRule.swift @@ -174,7 +174,7 @@ private extension DuplicateConditionsRule { let positionsByConditions = statementChain .reduce(into: [Set: [AbsolutePosition]]()) { acc, elt in - let conditions = elt.conditions.map { $0.condition.trimmedDescription } + let conditions = elt.conditions.map(\.condition.trimmedDescription) let location = elt.conditions.positionAfterSkippingLeadingTrivia acc[Set(conditions), default: []].append(location) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift index 0e26dec2bc..616db6f70c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DuplicateEnumCasesRule.swift @@ -76,7 +76,7 @@ private extension DuplicateEnumCasesRule { let duplicatedElementPositions = elementsByName .filter { $0.value.count > 1 } - .flatMap { $0.value } + .flatMap(\.value) violations.append(contentsOf: duplicatedElementPositions) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift index 1e09ba3db0..c64c93c681 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ExpiringTodoRule.swift @@ -56,7 +56,7 @@ struct ExpiringTodoRule: OptInRule { return file.matchesAndSyntaxKinds(matching: regex).compactMap { checkingResult, syntaxKinds in guard - syntaxKinds.allSatisfy({ $0.isCommentLike }), + syntaxKinds.allSatisfy(\.isCommentLike), checkingResult.numberOfRanges > 1, case let range = checkingResult.range(at: 1), let violationLevel = violationLevel(for: expiryDate(file: file, range: range)), diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index d2d8ac966b..3e8cf1d1c1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -73,7 +73,7 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { // 2. minus all references declaredUSRs .filter { !allReferencedUSRs.contains($0.usr) } - .map { $0.nameOffset } + .map(\.nameOffset) .sorted() } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift index 0e342fabd7..e61203ef3a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift @@ -28,7 +28,7 @@ struct UnusedImportRule: CorrectableRule, AnalyzerRule { func correct(file: SwiftLintFile, compilerArguments: [String]) -> [Correction] { let importUsages = importUsage(in: file, compilerArguments: compilerArguments) - let matches = file.ruleEnabled(violatingRanges: importUsages.compactMap({ $0.violationRange }), for: self) + let matches = file.ruleEnabled(violatingRanges: importUsages.compactMap(\.violationRange), for: self) var contents = file.stringView.nsString let description = Self.description @@ -113,7 +113,7 @@ private extension SwiftLintFile { unusedImports.subtract( operatorImports( arguments: compilerArguments, - processedTokenOffsets: Set(syntaxMap.tokens.map { $0.offset }) + processedTokenOffsets: Set(syntaxMap.tokens.map(\.offset)) ) ) } @@ -134,7 +134,7 @@ private extension SwiftLintFile { let modulesAllowedToImportCurrentModule = configuration.allowedTransitiveImports .filter { !unusedImports.contains($0.importedModule) } .filter { $0.transitivelyImportedModules.contains(module) } - .map { $0.importedModule } + .map(\.importedModule) return modulesAllowedToImportCurrentModule.isEmpty || imports.isDisjoint(with: modulesAllowedToImportCurrentModule) diff --git a/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift b/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift index f044995d31..161378b01a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Metrics/LineLengthRule.swift @@ -26,7 +26,7 @@ struct LineLengthRule: Rule { ) func validate(file: SwiftLintFile) -> [StyleViolation] { - let minValue = configuration.params.map({ $0.value }).min() ?? .max + let minValue = configuration.params.map(\.value).min() ?? .max let swiftDeclarationKindsByLine = Lazy(file.swiftDeclarationKindsByLine() ?? []) let syntaxKindsByLine = Lazy(file.syntaxKindsByLine() ?? []) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift index ee410d80e6..f1466c1503 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MissingDocsConfiguration.swift @@ -82,7 +82,7 @@ struct MissingDocsConfiguration: RuleConfiguration { } } - guard parameters.count == parameters.map({ $0.value }).unique.count else { + guard parameters.count == parameters.map(\.value).unique.count else { throw Issue.invalidConfiguration(ruleID: Parent.identifier) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRule.swift index 202dc76a34..0b39623f2a 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/FileTypesOrderRule.swift @@ -74,7 +74,7 @@ struct FileTypesOrderRule: OptInRule { let fileTypeOffset = orderedFileTypeOffsets[index] let fileType = fileTypeOffset.fileType.rawValue - let expected = expectedTypes.map { $0.rawValue }.joined(separator: ",") + let expected = expectedTypes.map(\.rawValue).joined(separator: ",") let article = ["a", "e", "i", "o", "u"].contains(fileType.substring(from: 0, length: 1)) ? "An" : "A" let styleViolation = StyleViolation( diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift index cf88b1aaa5..9e4909706e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ModifierOrderRule.swift @@ -119,7 +119,7 @@ struct ModifierOrderRule: ASTRule, OptInRule, CorrectableRule { let prioritizedModifiers = self.prioritizedModifiers(violatableModifiers: violatableModifiers) let sortedByPriorityModifiers = prioritizedModifiers .sorted { $0.priority < $1.priority } - .map { $0.modifier } + .map(\.modifier) return zip(sortedByPriorityModifiers, violatableModifiers).filter { $0 != $1 } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRule.swift index 724a46a2ba..a5e50b31a7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineArgumentsRule.swift @@ -70,7 +70,7 @@ private extension MultilineArgumentsRule { private func removeViolationsBeforeFirstClosure(arguments: [Argument], violations: [Argument]) -> [Argument] { - guard let firstClosure = arguments.first(where: { $0.isClosure }), + guard let firstClosure = arguments.first(where: \.isClosure), let firstArgument = arguments.first else { return violations } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift index b38b330ef2..2d048013ba 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineFunctionChainsRule.swift @@ -116,7 +116,7 @@ struct MultilineFunctionChainsRule: ASTRule, OptInRule { return (dotLine: line, dotOffset: offset, range: range) } - let uniqueLines = calls.map { $0.dotLine }.unique + let uniqueLines = calls.map(\.dotLine).unique if uniqueLines.count == 1 { return [] } @@ -127,7 +127,7 @@ struct MultilineFunctionChainsRule: ASTRule, OptInRule { !callHasLeadingNewline(file: file, callRange: line.range) } - return noLeadingNewlineViolations.map { $0.dotOffset } + return noLeadingNewlineViolations.map(\.dotOffset) } private static let whitespaceDotRegex = regex("\\s*\\.") diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift index 6f206c8487..d0f0b16506 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SortedImportsRule.swift @@ -142,7 +142,7 @@ struct SortedImportsRule: CorrectableRule, OptInRule { guard let first = group.first?.contentRange else { continue } - let result = group.map { $0.content }.joined(separator: "\n") + let result = group.map(\.content).joined(separator: "\n") let union = group.dropFirst().reduce(first) { result, line in NSUnionRange(result, line.contentRange) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift index c30bbd0d65..9a99e7a276 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/StatementPositionRule.swift @@ -176,7 +176,7 @@ private extension StatementPositionRule { let validator = Self.uncuddledMatchValidator(contents: contents) let filterMatches = Self.uncuddledMatchFilter(contents: contents, syntaxMap: syntaxMap) - return matches.compactMap(validator).filter(filterMatches).map({ $0.range }) + return matches.compactMap(validator).filter(filterMatches).map(\.range) } func uncuddledCorrect(file: SwiftLintFile) -> [Correction] { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift index 0cba45cf3d..daae7c6252 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TypeContentsOrderRule.swift @@ -51,7 +51,7 @@ struct TypeContentsOrderRule: OptInRule { let typeContentOffset = orderedTypeContentOffsets[index] let content = typeContentOffset.typeContent.rawValue - let expected = expectedTypesContents.map { $0.rawValue }.joined(separator: ",") + let expected = expectedTypesContents.map(\.rawValue).joined(separator: ",") let article = ["a", "e", "i", "o", "u"].contains(content.substring(from: 0, length: 1)) ? "An" : "A" let styleViolation = StyleViolation( diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift index a394a3d2f4..a635b5c554 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/UnusedOptionalBindingRule.swift @@ -56,9 +56,7 @@ private extension ExprSyntax { return true } if let tuple = self.as(TupleExprSyntax.self) { - return tuple.elements.allSatisfy { elem in - elem.expression.isDiscardExpression - } + return tuple.elements.allSatisfy(\.expression.isDiscardExpression) } return false diff --git a/Source/SwiftLintCore/Documentation/RuleListDocumentation.swift b/Source/SwiftLintCore/Documentation/RuleListDocumentation.swift index 2f707e54c6..eef3a75af7 100644 --- a/Source/SwiftLintCore/Documentation/RuleListDocumentation.swift +++ b/Source/SwiftLintCore/Documentation/RuleListDocumentation.swift @@ -35,7 +35,7 @@ public struct RuleListDocumentation { private var indexContents: String { let defaultRuleDocumentations = ruleDocumentations.filter { !$0.isOptInRule } let optInRuleDocumentations = ruleDocumentations.filter { $0.isOptInRule && !$0.isAnalyzerRule } - let analyzerRuleDocumentations = ruleDocumentations.filter { $0.isAnalyzerRule } + let analyzerRuleDocumentations = ruleDocumentations.filter(\.isAnalyzerRule) return """ # Rule Directory diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 7c0ed67331..232cf0ae72 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -25,7 +25,7 @@ extension Configuration { } // MARK: - Properties - private static let validGlobalKeys: Set = Set(Key.allCases.map { $0.rawValue }) + private static let validGlobalKeys: Set = Set(Key.allCases.map(\.rawValue)) // MARK: - Initializers /// Creates a Configuration value based on the specified parameters. diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift index ac008e9958..18cdfc42b6 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift @@ -14,7 +14,7 @@ internal extension Configuration { let regularRuleIdentifiers = allRulesWrapped.map { type(of: $0.rule).description.identifier } let configurationCustomRulesIdentifiers = (allRulesWrapped.first { $0.rule is CustomRules }?.rule as? CustomRules)? - .configuration.customRuleConfigurations.map { $0.identifier } ?? [] + .configuration.customRuleConfigurations.map(\.identifier) ?? [] return Set(regularRuleIdentifiers + configurationCustomRulesIdentifiers) } @@ -37,14 +37,14 @@ internal extension Configuration { switch mode { case .allEnabled: customRulesFilter = { _ in true } - resultingRules = allRulesWrapped.map { $0.rule } + resultingRules = allRulesWrapped.map(\.rule) case var .only(onlyRulesRuleIdentifiers): customRulesFilter = { onlyRulesRuleIdentifiers.contains($0.identifier) } onlyRulesRuleIdentifiers = validate(ruleIds: onlyRulesRuleIdentifiers, valid: validRuleIdentifiers) resultingRules = allRulesWrapped.filter { tuple in onlyRulesRuleIdentifiers.contains(type(of: tuple.rule).description.identifier) - }.map { $0.rule } + }.map(\.rule) case var .default(disabledRuleIdentifiers, optInRuleIdentifiers): customRulesFilter = { !disabledRuleIdentifiers.contains($0.identifier) } @@ -54,7 +54,7 @@ internal extension Configuration { let id = type(of: tuple.rule).description.identifier return !disabledRuleIdentifiers.contains(id) && (!(tuple.rule is any OptInRule) || optInRuleIdentifiers.contains(id)) - }.map { $0.rule } + }.map(\.rule) } // Filter custom rules @@ -178,15 +178,14 @@ internal extension Configuration { private func mergedAllRulesWrapped(with child: RulesWrapper) -> [ConfigurationRuleWrapper] { let mainConfigSet = Set(allRulesWrapped.map(HashableConfigurationRuleWrapperWrapper.init)) let childConfigSet = Set(child.allRulesWrapped.map(HashableConfigurationRuleWrapperWrapper.init)) - let childConfigRulesWithConfig = childConfigSet.filter { - $0.configurationRuleWrapper.initializedWithNonEmptyConfiguration - } + let childConfigRulesWithConfig = childConfigSet + .filter(\.configurationRuleWrapper.initializedWithNonEmptyConfiguration) let rulesUniqueToChildConfig = childConfigSet.subtracting(mainConfigSet) return childConfigRulesWithConfig // Include, if rule is configured in child .union(rulesUniqueToChildConfig) // Include, if rule is in child config only .union(mainConfigSet) // Use configurations from parent for remaining rules - .map { $0.configurationRuleWrapper } + .map(\.configurationRuleWrapper) } private func mergedCustomRules( @@ -248,7 +247,7 @@ internal extension Configuration { as? CustomRules { onlyRules = onlyRules.union( Set( - childCustomRulesRule.configuration.customRuleConfigurations.map { $0.identifier } + childCustomRulesRule.configuration.customRuleConfigurations.map(\.identifier) ) ) } diff --git a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift index d279bb1dae..c9221ccebf 100644 --- a/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Dictionary+SwiftLint.swift @@ -130,7 +130,7 @@ public struct SourceKittenDictionary { /// The `SwiftDeclarationAttributeKind` values associated with this dictionary. public var enclosedSwiftAttributes: [SwiftDeclarationAttributeKind] { - swiftAttributes.compactMap { $0.attribute } + swiftAttributes.compactMap(\.attribute) .compactMap(SwiftDeclarationAttributeKind.init(rawValue:)) } diff --git a/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift b/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift index a90867e184..26d5175789 100644 --- a/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift +++ b/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift @@ -165,7 +165,7 @@ extension SwiftLintFile { public var locationConverter: SourceLocationConverter { locationConverterCache.get(self) } - public var commands: [Command] { commandsCache.get(self).filter { $0.isValid } } + public var commands: [Command] { commandsCache.get(self).filter(\.isValid) } public var invalidCommands: [Command] { commandsCache.get(self).filter { !$0.isValid } } diff --git a/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift b/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift index f833e94553..c8fe43d36d 100644 --- a/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift +++ b/Source/SwiftLintCore/Extensions/SwiftLintFile+Regex.swift @@ -96,7 +96,7 @@ extension SwiftLintFile { public func match(pattern: String, with syntaxKinds: [SyntaxKind], range: NSRange? = nil) -> [NSRange] { match(pattern: pattern, range: range) .filter { $0.1 == syntaxKinds } - .map { $0.0 } + .map(\.0) } public func matchesAndTokens(matching pattern: String, @@ -185,7 +185,7 @@ extension SwiftLintFile { return nil } - return tokens.map { $0.kinds } + return tokens.map(\.kinds) } /** @@ -205,7 +205,7 @@ extension SwiftLintFile { captureGroup: Int = 0) -> [NSRange] { match(pattern: pattern, range: range, captureGroup: captureGroup) .filter { syntaxKinds.isDisjoint(with: $0.1) } - .map { $0.0 } + .map(\.0) } public typealias MatchMapping = (NSTextCheckingResult) -> NSRange @@ -214,7 +214,7 @@ extension SwiftLintFile { range: NSRange? = nil, excludingSyntaxKinds: Set, excludingPattern: String, - exclusionMapping: MatchMapping = { $0.range }) -> [NSRange] { + exclusionMapping: MatchMapping = \.range) -> [NSRange] { let matches = match(pattern: pattern, excludingSyntaxKinds: excludingSyntaxKinds) if matches.isEmpty { return [] diff --git a/Source/SwiftLintCore/Models/Baseline.swift b/Source/SwiftLintCore/Models/Baseline.swift index 145a15439c..62aa573e2f 100644 --- a/Source/SwiftLintCore/Models/Baseline.swift +++ b/Source/SwiftLintCore/Models/Baseline.swift @@ -176,7 +176,7 @@ private extension Sequence where Element == BaselineViolation { } var violationsWithAbsolutePaths: [StyleViolation] { - map { $0.violation.withAbsolutePath } + map(\.violation.withAbsolutePath) } func groupedByFile() -> ViolationsPerFile { diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index be8a440ac5..c18ce0ad1a 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -115,7 +115,7 @@ private extension Rule { return violation } } else { - enabledViolations = enabledViolationsAndRegions.map { $0.0 } + enabledViolations = enabledViolationsAndRegions.map(\.0) } let deprecatedToValidIDPairs = disabledViolationsAndRegions.flatMap { _, region -> [(String, String)] in let identifiers = region?.deprecatedAliasesDisabling(rule: self) ?? [] @@ -245,10 +245,10 @@ public struct CollectedLinter { regions: regions, configuration: configuration, superfluousDisableCommandRule: superfluousDisableCommandRule) - let violations = validationResults.flatMap { $0.violations } + undefinedSuperfluousCommandViolations - let ruleTimes = validationResults.compactMap { $0.ruleTime } + let violations = validationResults.flatMap(\.violations) + undefinedSuperfluousCommandViolations + let ruleTimes = validationResults.compactMap(\.ruleTime) var deprecatedToValidIdentifier = [String: String]() - for (key, value) in validationResults.flatMap({ $0.deprecatedToValidIDPairs }) { + for (key, value) in validationResults.flatMap(\.deprecatedToValidIDPairs) { deprecatedToValidIdentifier[key] = value } diff --git a/Source/SwiftLintCore/Models/Region.swift b/Source/SwiftLintCore/Models/Region.swift index 4a2606ed25..ae2df0fcba 100644 --- a/Source/SwiftLintCore/Models/Region.swift +++ b/Source/SwiftLintCore/Models/Region.swift @@ -58,7 +58,7 @@ public struct Region: Equatable { if disabledRuleIdentifiers.contains(.all) { return true } - let regionIdentifiers = Set(disabledRuleIdentifiers.map { $0.stringRepresentation }) + let regionIdentifiers = Set(disabledRuleIdentifiers.map(\.stringRepresentation)) return !regionIdentifiers.isDisjoint(with: ruleIDs) } @@ -70,7 +70,7 @@ public struct Region: Equatable { /// - returns: Deprecated rule aliases. public func deprecatedAliasesDisabling(rule: some Rule) -> Set { let identifiers = type(of: rule).description.deprecatedAliases - return Set(disabledRuleIdentifiers.map { $0.stringRepresentation }).intersection(identifiers) + return Set(disabledRuleIdentifiers.map(\.stringRepresentation)).intersection(identifiers) } /// Converts this `Region` to a SwiftSyntax `SourceRange`. diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index b793f94188..7ba0dbfae3 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -276,7 +276,7 @@ public struct RuleConfigurationDescriptionBuilder { /// :nodoc: public static func buildArray(_ components: [Description]) -> Description { - Description(options: components.flatMap { $0.options }) + Description(options: components.flatMap(\.options)) } } diff --git a/Source/SwiftLintCore/Models/RuleList.swift b/Source/SwiftLintCore/Models/RuleList.swift index e81533e9c8..e8dd55b5c8 100644 --- a/Source/SwiftLintCore/Models/RuleList.swift +++ b/Source/SwiftLintCore/Models/RuleList.swift @@ -85,7 +85,8 @@ public struct RuleList { extension RuleList: Equatable { public static func == (lhs: RuleList, rhs: RuleList) -> Bool { - lhs.list.map { $0.0 } == rhs.list.map { $0.0 } + lhs.list.map(\.0) == rhs.list.map(\.0) + // swiftlint:disable:next prefer_key_path && lhs.list.map { $0.1.description } == rhs.list.map { $0.1.description } && lhs.aliases == rhs.aliases } diff --git a/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift b/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift index 5eb0878675..96d5f5e1fc 100644 --- a/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift +++ b/Source/SwiftLintCore/Models/SwiftLintSyntaxMap.swift @@ -49,6 +49,6 @@ public struct SwiftLintSyntaxMap { /// /// - returns: The syntax kinds in the specified byte range. public func kinds(inByteRange byteRange: ByteRange) -> [SyntaxKind] { - tokens(inByteRange: byteRange).compactMap { $0.kind } + tokens(inByteRange: byteRange).compactMap(\.kind) } } diff --git a/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift b/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift index 1ad8f353c2..d0032b03db 100644 --- a/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift +++ b/Source/SwiftLintCore/Models/SwiftLintSyntaxToken.swift @@ -35,6 +35,6 @@ public struct SwiftLintSyntaxToken { public extension Array where Element == SwiftLintSyntaxToken { /// The kinds for these tokens. var kinds: [SyntaxKind] { - compactMap { $0.kind } + compactMap(\.kind) } } diff --git a/Source/SwiftLintCore/Reporters/HTMLReporter.swift b/Source/SwiftLintCore/Reporters/HTMLReporter.swift index 778c2e78ae..37916a3d4f 100644 --- a/Source/SwiftLintCore/Reporters/HTMLReporter.swift +++ b/Source/SwiftLintCore/Reporters/HTMLReporter.swift @@ -28,7 +28,7 @@ struct HTMLReporter: Reporter { .map { generateSingleRow(for: $1, at: $0 + 1) } .joined(separator: "\n") - let fileCount = Set(violations.compactMap({ $0.location.file })).count + let fileCount = Set(violations.compactMap(\.location.file)).count let warningCount = violations.filter({ $0.severity == .warning }).count let errorCount = violations.filter({ $0.severity == .error }).count diff --git a/Source/SwiftLintCore/Reporters/SummaryReporter.swift b/Source/SwiftLintCore/Reporters/SummaryReporter.swift index fb939fcef3..24b8fa3501 100644 --- a/Source/SwiftLintCore/Reporters/SummaryReporter.swift +++ b/Source/SwiftLintCore/Reporters/SummaryReporter.swift @@ -65,7 +65,7 @@ private extension TextTable { totalNumberOfWarnings += numberOfWarnings totalNumberOfErrors += numberOfErrors let ruleViolations = ruleIdentifiersToViolationsMap[ruleIdentifier] ?? [] - let numberOfFiles = Set(ruleViolations.map { $0.location.file }).count + let numberOfFiles = Set(ruleViolations.map(\.location.file)).count addRow(values: [ ruleIdentifier, @@ -80,7 +80,7 @@ private extension TextTable { } let totalNumberOfViolations = totalNumberOfWarnings + totalNumberOfErrors - let totalNumberOfFiles = Set(violations.map { $0.location.file }).count + let totalNumberOfFiles = Set(violations.map(\.location.file)).count addRow(values: [ "Total", "", diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index 4c21be0dd4..e44c25a307 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -34,7 +34,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, included.map(\.pattern).joined(separator: ","), excluded.map(\.pattern).joined(separator: ","), SyntaxKind.allKinds.subtracting(excludedMatchKinds) - .map({ $0.rawValue }).sorted(by: <).joined(separator: ","), + .map(\.rawValue).sorted(by: <).joined(separator: ","), severity.rawValue, ] if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject) { diff --git a/Source/SwiftLintCore/Rules/CustomRules.swift b/Source/SwiftLintCore/Rules/CustomRules.swift index d6a3e4d9d0..c43e191f5e 100644 --- a/Source/SwiftLintCore/Rules/CustomRules.swift +++ b/Source/SwiftLintCore/Rules/CustomRules.swift @@ -9,7 +9,7 @@ struct CustomRulesConfiguration: RuleConfiguration, CacheDescriptionProvider { var cacheDescription: String { customRuleConfigurations .sorted { $0.identifier < $1.identifier } - .map { $0.cacheDescription } + .map(\.cacheDescription) .joined(separator: "\n") } var customRuleConfigurations = [RegexConfiguration]() diff --git a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift index 76b8938809..c7576d7bc8 100644 --- a/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift +++ b/Source/SwiftLintCore/Visitors/DeclaredIdentifiersTrackingVisitor.swift @@ -164,9 +164,7 @@ open class DeclaredIdentifiersTrackingVisitor: .compactMap { pattern -> FunctionCallExprSyntax? in pattern.as(ExpressionPatternSyntax.self)?.expression.asFunctionCall } - .map { call -> LabeledExprListSyntax in - call.arguments - } + .map(\.arguments) .flatMap { $0 } .compactMap { labeledExpr -> PatternExprSyntax? in labeledExpr.expression.as(PatternExprSyntax.self) diff --git a/Source/swiftlint/Extensions/Configuration+CommandLine.swift b/Source/swiftlint/Extensions/Configuration+CommandLine.swift index 048a6edfe3..84a7119374 100644 --- a/Source/swiftlint/Extensions/Configuration+CommandLine.swift +++ b/Source/swiftlint/Extensions/Configuration+CommandLine.swift @@ -222,7 +222,7 @@ extension Configuration { return files } - let scriptInputPaths = files.compactMap { $0.path } + let scriptInputPaths = files.compactMap(\.path) if visitor.useExcludingByPrefix { return filterExcludedPathsByPrefix(in: scriptInputPaths) diff --git a/Tests/SwiftLintFrameworkTests/BaselineTests.swift b/Tests/SwiftLintFrameworkTests/BaselineTests.swift index 732d9e6f79..aefcca06aa 100644 --- a/Tests/SwiftLintFrameworkTests/BaselineTests.swift +++ b/Tests/SwiftLintFrameworkTests/BaselineTests.swift @@ -196,7 +196,7 @@ private extension [StyleViolation] { XCTFail("Shift must be positive") return self } - var lines = SwiftLintFile(path: path)?.lines.map({ $0.content }) ?? [] + var lines = SwiftLintFile(path: path)?.lines.map(\.content) ?? [] lines = [String](repeating: "", count: shift) + lines if let data = lines.joined(separator: "\n").data(using: .utf8) { try data.write(to: URL(fileURLWithPath: path)) diff --git a/Tests/SwiftLintFrameworkTests/CommandTests.swift b/Tests/SwiftLintFrameworkTests/CommandTests.swift index 5633ee186d..5532fc0fa2 100644 --- a/Tests/SwiftLintFrameworkTests/CommandTests.swift +++ b/Tests/SwiftLintFrameworkTests/CommandTests.swift @@ -238,7 +238,7 @@ final class CommandTests: SwiftLintTestCase { func testSuperfluousDisableCommands() { XCTAssertEqual( - violations(Example("// swiftlint:disable nesting\nprint(123)\n")).map { $0.ruleIdentifier }, + violations(Example("// swiftlint:disable nesting\nprint(123)\n")).map(\.ruleIdentifier), ["blanket_disable_command", "superfluous_disable_command"] ) XCTAssertEqual( @@ -297,9 +297,7 @@ final class CommandTests: SwiftLintTestCase { func testSuperfluousDisableCommandsIgnoreDelimiter() { let longComment = "Comment with a large number of words that shouldn't register as superfluous" XCTAssertEqual( - violations(Example("// swiftlint:disable nesting - \(longComment)\nprint(123)\n")).map { - $0.ruleIdentifier - }, + violations(Example("// swiftlint:disable nesting - \(longComment)\nprint(123)\n")).map(\.ruleIdentifier), ["blanket_disable_command", "superfluous_disable_command"] ) XCTAssertEqual( diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift index 26ac0c28b0..7f9367dcef 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift @@ -7,7 +7,7 @@ final class ConfigurationAliasesTests: SwiftLintTestCase { func testConfiguresCorrectlyFromDeprecatedAlias() throws { let ruleConfiguration = [1, 2] let config = ["mock": ruleConfiguration] - let rules = try testRuleList.allRulesWrapped(configurationDict: config).map { $0.rule } + let rules = try testRuleList.allRulesWrapped(configurationDict: config).map(\.rule) // swiftlint:disable:next xct_specific_matcher XCTAssertTrue(rules == [try RuleWithLevelsMock(configuration: ruleConfiguration)]) } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 27d67e8561..16fe56e7cf 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -5,7 +5,7 @@ import XCTest // swiftlint:disable file_length -private let optInRules = RuleRegistry.shared.list.list.filter({ $0.1.init() is any OptInRule }).map({ $0.0 }) +private let optInRules = RuleRegistry.shared.list.list.filter({ $0.1.init() is any OptInRule }).map(\.0) final class ConfigurationTests: SwiftLintTestCase { // MARK: Setup & Teardown @@ -425,14 +425,14 @@ final class ConfigurationTests: SwiftLintTestCase { func testConfiguresCorrectlyFromDict() throws { let ruleConfiguration = [1, 2] let config = [RuleWithLevelsMock.description.identifier: ruleConfiguration] - let rules = try testRuleList.allRulesWrapped(configurationDict: config).map { $0.rule } + let rules = try testRuleList.allRulesWrapped(configurationDict: config).map(\.rule) // swiftlint:disable:next xct_specific_matcher XCTAssertTrue(rules == [try RuleWithLevelsMock(configuration: ruleConfiguration)]) } func testConfigureFallsBackCorrectly() throws { let config = [RuleWithLevelsMock.description.identifier: ["a", "b"]] - let rules = try testRuleList.allRulesWrapped(configurationDict: config).map { $0.rule } + let rules = try testRuleList.allRulesWrapped(configurationDict: config).map(\.rule) // swiftlint:disable:next xct_specific_matcher XCTAssertTrue(rules == [RuleWithLevelsMock()]) } diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index 032fad3c36..6a3293133f 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -164,7 +164,7 @@ private func cleanedContentsAndMarkerOffsets(from contents: String) -> (String, } private func render(violations: [StyleViolation], in contents: String) -> String { - var contents = StringView(contents).lines.map { $0.content } + var contents = StringView(contents).lines.map(\.content) for violation in violations.sorted(by: { $0.location > $1.location }) { guard let line = violation.location.line, let character = violation.location.character else { continue } @@ -189,7 +189,7 @@ private func render(violations: [StyleViolation], in contents: String) -> String } private func render(locations: [Location], in contents: String) -> String { - var contents = StringView(contents).lines.map { $0.content } + var contents = StringView(contents).lines.map(\.content) for location in locations.sorted(by: > ) { guard let line = location.line, let character = location.character else { continue } let content = NSMutableString(string: contents[line - 1]) @@ -420,7 +420,7 @@ public extension XCTestCase { // Disabled rule doesn't violate and disable command isn't superfluous for command in disableCommands { let disabledTriggers = triggers - .filter { $0.testDisableCommand } + .filter(\.testDisableCommand) .map { $0.with(code: command + $0.code) } for trigger in disabledTriggers { @@ -513,7 +513,7 @@ public extension XCTestCase { } // Assert locations missing violation - let violatedLocations = triggerViolations.map { $0.location } + let violatedLocations = triggerViolations.map(\.location) let locationsWithoutViolation = expectedLocations .filter { !violatedLocations.contains($0) } if !locationsWithoutViolation.isEmpty { From 87bc82e7b5c480597dfade86752aad2ad95a4a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 3 Aug 2024 17:01:40 +0200 Subject: [PATCH 151/265] Restrict `prefer_key_path` to standard functions and function arguments (#5722) By default, the rule triggers on and corrects closures used in functions it "knows". With the option extending the rule, it now also triggers on closures used in "safe" contexts, where "safe" means that a correction would not lead to uncompilable code (ideally). --- .swiftlint.yml | 2 + CHANGELOG.md | 6 +- .../Rules/Idiomatic/PreferKeyPathRule.swift | 122 ++++++++++-------- .../Rules/Style/LetVarWhitespaceRule.swift | 4 +- .../Rules/Style/TrailingClosureRule.swift | 2 +- 5 files changed, 73 insertions(+), 63 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index fc5d5cd6db..e3420d3ed6 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -78,6 +78,8 @@ identifier_name: large_tuple: 3 number_separator: minimum_length: 5 +prefer_key_path: + restrict_to_standard_functions: false redundant_type_annotation: consider_default_literal_types_redundant: true single_test_class: *unit_test_configuration diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a31cd4d3f..eaa74c9680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,9 +33,9 @@ [woxtu](https://github.com/woxtu) [SimplyDanny](https://github.com/SimplyDanny) -* Add new `prefer_key_path` rule that triggers when a trailing closure on a function - call is only hosting a (chained) member access expression since the closure can be - replaced with a key path argument. +* Add new `prefer_key_path` rule that triggers when a trailing closure on a standard + function call is only hosting a (chained) member access expression since the closure + can be replaced with a key path argument. Likewise, it triggers on closure arguments. [SimplyDanny](https://github.com/SimplyDanny) * Adds `baseline` and `write_baseline` configuration file settings, equivalent diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift index 1c5d8d70f1..9bf05ee4b8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift @@ -5,7 +5,7 @@ import SwiftSyntax struct PreferKeyPathRule: OptInRule { var configuration = PreferKeyPathConfiguration() - private static let checkAllClosures = ["restrict_to_standard_functions": false] + private static let extendedMode = ["restrict_to_standard_functions": false] static var description = RuleDescription( identifier: "prefer_key_path", @@ -18,15 +18,17 @@ struct PreferKeyPathRule: OptInRule { Example("f { $0 }"), Example("f { $0.a }"), Example("let f = { $0.a }(b)"), - Example("f {}", configuration: checkAllClosures), - Example("f { $0 }", configuration: checkAllClosures), - Example("f() { g() }", configuration: checkAllClosures), - Example("f { a.b.c }", configuration: checkAllClosures), - Example("f { a in a }", configuration: checkAllClosures), - Example("f { a, b in a.b }", configuration: checkAllClosures), - Example("f { (a, b) in a.b }", configuration: checkAllClosures), - Example("f { $0.a } g: { $0.b }", configuration: checkAllClosures), - Example("[1, 2, 3].reduce(1) { $0 + $1 }", configuration: checkAllClosures), + Example("f {}", configuration: extendedMode), + Example("f { $0 }", configuration: extendedMode), + Example("f() { g() }", configuration: extendedMode), + Example("f { a.b.c }", configuration: extendedMode), + Example("f { a in a }", configuration: extendedMode), + Example("f { a, b in a.b }", configuration: extendedMode), + Example("f { (a, b) in a.b }", configuration: extendedMode), + Example("f { $0.a } g: { $0.b }", configuration: extendedMode), + Example("[1, 2, 3].reduce(1) { $0 + $1 }", configuration: extendedMode), + Example("f.map(1) { $0.a }"), + Example("f.filter({ $0.a }, x)"), ], triggeringExamples: [ Example("f.map ↓{ $0.a }"), @@ -34,15 +36,15 @@ struct PreferKeyPathRule: OptInRule { Example("f.first ↓{ $0.a }"), Example("f.contains ↓{ $0.a }"), Example("f.contains(where: ↓{ $0.a })"), - Example("f ↓{ $0.a }", configuration: checkAllClosures), - Example("f ↓{ a in a.b }", configuration: checkAllClosures), - Example("f ↓{ a in a.b.c }", configuration: checkAllClosures), - Example("f ↓{ (a: A) in a.b }", configuration: checkAllClosures), - Example("f ↓{ (a b: A) in b.c }", configuration: checkAllClosures), - Example("f ↓{ $0.0.a }", configuration: checkAllClosures), - Example("f(a: ↓{ $0.b })", configuration: checkAllClosures), - Example("f ↓{ $0.a.b }", configuration: checkAllClosures), - Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: checkAllClosures), + Example("f(↓{ $0.a })", configuration: extendedMode), + Example("f(a: ↓{ $0.b })", configuration: extendedMode), + Example("f(a: ↓{ a in a.b }, x)", configuration: extendedMode), + Example("f.map ↓{ a in a.b.c }"), + Example("f.allSatisfy ↓{ (a: A) in a.b }"), + Example("f.first ↓{ (a b: A) in b.c }"), + Example("f.contains ↓{ $0.0.a }"), + Example("f.flatMap ↓{ $0.a.b }"), + Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: extendedMode), ], corrections: [ Example("f.map { $0.a }"): @@ -57,22 +59,24 @@ struct PreferKeyPathRule: OptInRule { """), Example("f.map({ $0.a })"): Example("f.map(\\.a)"), - Example("f { $0.a }", configuration: checkAllClosures): + Example("f(a: { $0.a })", configuration: extendedMode): + Example("f(a: \\.a)"), + Example("f({ $0.a })", configuration: extendedMode): Example("f(\\.a)"), - Example("f() { $0.a }", configuration: checkAllClosures): - Example("f(\\.a)"), - Example("let f = /* begin */ { $0.a } // end", configuration: checkAllClosures): + Example("let f = /* begin */ { $0.a } // end", configuration: extendedMode): Example("let f = /* begin */ \\.a // end"), Example("let f = { $0.a }(b)"): Example("let f = { $0.a }(b)"), - Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: checkAllClosures): + Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: extendedMode): Example("let f: (Int) -> Int = \\.bigEndian"), - Example("f ↓{ $0.a.b }", configuration: checkAllClosures): - Example("f(\\.a.b)"), - Example("f.contains ↓{ $0.a.b }", configuration: checkAllClosures): + Example("f.partition ↓{ $0.a.b }"): + Example("f.partition(by: \\.a.b)"), + Example("f.contains ↓{ $0.a.b }"): Example("f.contains(where: \\.a.b)"), - Example("f.first ↓{ element in element.a }", configuration: checkAllClosures): + Example("f.first ↓{ element in element.a }"): Example("f.first(where: \\.a)"), + Example("f.drop ↓{ element in element.a }"): + Example("f.drop(while: \\.a)"), ] ) } @@ -80,7 +84,7 @@ struct PreferKeyPathRule: OptInRule { private extension PreferKeyPathRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: ClosureExprSyntax) { - if node.isInvalid(standardFunctionsOnly: configuration.restrictToStandardFunctions) { + if node.isInvalid(restrictToStandardFunctions: configuration.restrictToStandardFunctions) { return } if node.onlyExprStmt?.accesses(identifier: node.onlyParameter) == true { @@ -91,14 +95,13 @@ private extension PreferKeyPathRule { final class Rewriter: ViolationsSyntaxRewriter { override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax { - if configuration.restrictToStandardFunctions, !node.isStandardFunction { - return super.visit(node) - } guard node.additionalTrailingClosures.isEmpty, let closure = node.trailingClosure, + !closure.isInvalid(restrictToStandardFunctions: configuration.restrictToStandardFunctions), let expr = closure.onlyExprStmt, expr.accesses(identifier: closure.onlyParameter) == true, - let declName = expr.as(MemberAccessExprSyntax.self) else { + let declName = expr.as(MemberAccessExprSyntax.self), + let calleeName = node.calleeName else { return super.visit(node) } correctionPositions.append(closure.positionAfterSkippingLeadingTrivia) @@ -107,12 +110,10 @@ private extension PreferKeyPathRule { node = node.with(\.leftParen, .leftParenToken()) } let newArg = LabeledExprSyntax( - label: ["contains", "first"].contains(node.calleeName) ? "where" : nil, + label: argumentLabelByStandardFunction[calleeName, default: nil], expression: declName.asKeyPath ) - node = node.with( - \.arguments, - node.arguments + [newArg] + node = node.with(\.arguments, [newArg] ) if node.rightParen == nil { node = node.with(\.rightParen, .rightParenToken()) @@ -124,7 +125,7 @@ private extension PreferKeyPathRule { } override func visit(_ node: ClosureExprSyntax) -> ExprSyntax { - if node.isInvalid(standardFunctionsOnly: configuration.restrictToStandardFunctions) { + if node.isInvalid(restrictToStandardFunctions: configuration.restrictToStandardFunctions) { return super.visit(node) } if let expr = node.onlyExprStmt, @@ -172,30 +173,37 @@ private extension ClosureExprSyntax { return nil } - private var surroundingFunction: FunctionCallExprSyntax? { - parent?.as(FunctionCallExprSyntax.self) - ?? parent?.as(LabeledExprSyntax.self)?.parent?.parent?.as(FunctionCallExprSyntax.self) - } - - func isInvalid(standardFunctionsOnly: Bool) -> Bool { - keyPathInParent == \FunctionCallExprSyntax.calledExpression - || parent?.is(MultipleTrailingClosureElementSyntax.self) == true - || surroundingFunction?.additionalTrailingClosures.isNotEmpty == true - || standardFunctionsOnly && surroundingFunction?.isStandardFunction == false + func isInvalid(restrictToStandardFunctions: Bool) -> Bool { + if keyPathInParent == \FunctionCallExprSyntax.calledExpression { + return true + } + if parent?.is(MultipleTrailingClosureElementSyntax.self) == true { + return true + } + if let call = parent?.as(LabeledExprSyntax.self)?.parent?.parent?.as(FunctionCallExprSyntax.self) { + // Closure is function argument. + return restrictToStandardFunctions && !call.isStandardFunction + } + return parent?.as(FunctionCallExprSyntax.self)?.isStandardFunction == false } } +private let argumentLabelByStandardFunction: [String: String?] = [ + "allSatisfy": nil, + "contains": "where", + "drop": "while", + "filter": nil, + "first": "where", + "flatMap": nil, + "map": nil, + "partition": "by", + "prefix": "while", +] + private extension FunctionCallExprSyntax { var isStandardFunction: Bool { - if let calleeName { - return [ - "allSatisfy", - "contains", - "filter", - "first", - "flatMap", - "map", - ].contains(calleeName) + if let calleeName, argumentLabelByStandardFunction.keys.contains(calleeName) { + return arguments.count + (trailingClosure == nil ? 0 : 1) == 1 } return false } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift index e80977416b..018ad886e1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/LetVarWhitespaceRule.swift @@ -215,12 +215,12 @@ struct LetVarWhitespaceRule: OptInRule { private extension LetVarWhitespaceRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: MemberBlockItemListSyntax) { - collectViolations(from: node, using: { $0.decl }) + collectViolations(from: node, using: { $0.decl }) // swiftlint:disable:this prefer_key_path } override func visitPost(_ node: CodeBlockItemListSyntax) { if node.isInValidContext { - collectViolations(from: node, using: { $0.unwrap }) + collectViolations(from: node, using: \.unwrap) } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift index 99d462a613..204d602568 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/TrailingClosureRule.swift @@ -256,7 +256,7 @@ private extension Trivia { func removingLeadingNewlines() -> Self { if startsWithNewline { - Trivia(pieces: pieces.drop(while: { $0.isNewline })) + Trivia(pieces: pieces.drop(while: \.isNewline)) } else { self } From 73cbb82a07f1171b3e6476e75f003cef8b62403d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 3 Aug 2024 17:29:46 +0200 Subject: [PATCH 152/265] Update issue templates --- .github/ISSUE_TEMPLATE/bug-report.md | 40 ++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 42 -------------------------- .github/ISSUE_TEMPLATE/proposal.md | 15 +++++++++ .github/ISSUE_TEMPLATE/rule-request.md | 9 +++--- 4 files changed, 59 insertions(+), 47 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/proposal.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000000..7a704c91b4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,40 @@ +--- +name: Bug Report +about: Create a report to help us improve. + +--- + +### New Issue Checklist + +- [ ] I've Updated SwiftLint to the latest version. +- [ ] I've searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues). + +### Bug Description + +A clear and concise description of what the bug is. Ideally, provide a small (but compilable) example code snippet that +can be used to reproduce the issue. + +```swift +// This triggers a violation: +let foo = try! bar() +``` + +Mention the command or other SwiftLint integration method that caused the issue. Include stack traces or command output. + +```bash +$ swiftlint lint [--no-cache] [--fix] +``` + +### Environment + +* SwiftLint version (run `swiftlint version` to be sure) +* Xcode version (run `xcodebuild -version` to be sure) +* Installation method used (Homebrew, CocoaPods, building from source, etc) +* Configuration file: + +```yml +# insert yaml contents here +``` + +Are you using [nested configurations](https://github.com/realm/SwiftLint#nested-configurations)? If so, paste their +relative paths and respective contents. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 000b5bdea1..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve - ---- - -### New Issue Checklist - -- [ ] Updated SwiftLint to the latest version -- [ ] I searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues) - -### Describe the bug - -A clear and concise description of what the bug is. - -##### Complete output when running SwiftLint, including the stack trace and command used - -```bash -$ swiftlint lint -``` - -### Environment - -* SwiftLint version (run `swiftlint version` to be sure)? -* Installation method used (Homebrew, CocoaPods, building from source, etc)? -* Paste your configuration file: - -```yml -# insert yaml contents here -``` - -* Are you using [nested configurations](https://github.com/realm/SwiftLint#nested-configurations)? - If so, paste their relative paths and respective contents. -* Which Xcode version are you using (check `xcodebuild -version`)? -* Do you have a sample that shows the issue? Run `echo "[string here]" | swiftlint lint --no-cache --use-stdin --enable-all-rules` - to quickly test if your example is really demonstrating the issue. If your example is more - complex, you can use `swiftlint lint --path [file here] --no-cache --enable-all-rules`. - -```swift -// This triggers a violation: -let foo = try! bar() -``` diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md new file mode 100644 index 0000000000..096971879a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/proposal.md @@ -0,0 +1,15 @@ +--- +name: Feature Request or Enhancement Proposal +about: Let us know about a feature idea or propose an improvement. + +--- + +### New Issue Checklist + +- [ ] I've Updated SwiftLint to the latest version. +- [ ] I've searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues). + +### Feature Request or Enhancement Proposal + +Describe you idea or proposal here. This can be a new feature, an enhancement to an existing feature, or a change to the +project's behavior. Be sure to include the rationale behind the proposal and any relevant context or examples. diff --git a/.github/ISSUE_TEMPLATE/rule-request.md b/.github/ISSUE_TEMPLATE/rule-request.md index fedc4e92fd..1736669bae 100644 --- a/.github/ISSUE_TEMPLATE/rule-request.md +++ b/.github/ISSUE_TEMPLATE/rule-request.md @@ -1,6 +1,6 @@ --- -name: Rule request -about: Share your idea for a new rule +name: Rule Request +about: Share your idea for a new rule. --- @@ -9,10 +9,9 @@ about: Share your idea for a new rule - [ ] Updated SwiftLint to the latest version - [ ] I searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues) -### New rule request +### New Rule Request -Please describe the rule idea, format -this issue's title as `Rule Request: [Rule Name]` and describe: +Please describe the rule idea, format this issue's title as `Rule Request: [Rule Name]` and describe: 1. Why should this rule be added? Share links to existing discussion about what the community thinks about this. From b67e82a8323e0d7c5dc6427ff509fc881d2cd1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 3 Aug 2024 18:03:41 +0200 Subject: [PATCH 153/265] Extract new `contrasted_opening_brace` rule from `opening_brace` rule (#5723) --- .swiftlint.yml | 1 + CHANGELOG.md | 2 +- .../Models/BuiltInRules.swift | 1 + .../OpeningBraceConfiguration.swift | 2 - .../Style/ContrastedOpeningBraceRule.swift | 83 ++++ .../ContrastedOpeningBraceRuleExamples.swift | 416 ++++++++++++++++++ .../Rules/Style/OpeningBraceRule.swift | 120 +---- .../Style/OpeningBraceRuleExamples.swift | 79 ---- .../Visitors/CodeBlockVisitor.swift | 105 +++++ Tests/GeneratedTests/GeneratedTests.swift | 6 + .../default_rule_configurations.yml | 3 +- 11 files changed, 623 insertions(+), 195 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift create mode 100644 Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift create mode 100644 Source/SwiftLintBuiltInRules/Visitors/CodeBlockVisitor.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index e3420d3ed6..05b56bc77a 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -17,6 +17,7 @@ disabled_rules: - anonymous_argument_in_multiline_closure - anyobject_protocol - conditional_returns_on_newline + - contrasted_opening_brace - convenience_type - discouraged_optional_collection - explicit_acl diff --git a/CHANGELOG.md b/CHANGELOG.md index eaa74c9680..ed8841c985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,7 @@ [Ueeek](https://github.com/Ueeek) [#5615](https://github.com/realm/SwiftLint/issues/5615) -* Add new `brace_on_new_line` option to `opening_brace` rule that enforces opening +* Add new `contrasted_opening_brace` rule that enforces opening braces to be on a separate line after the preceding declaration. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index e0da36c3ca..86105239e6 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -31,6 +31,7 @@ public let builtInRules: [any Rule.Type] = [ ContainsOverFilterIsEmptyRule.self, ContainsOverFirstNotNilRule.self, ContainsOverRangeNilComparisonRule.self, + ContrastedOpeningBraceRule.self, ControlStatementRule.self, ConvenienceTypeRule.self, CyclomaticComplexityRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift index bac9426c26..1e72688009 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift @@ -8,6 +8,4 @@ struct OpeningBraceConfiguration: SeverityBasedRuleConfiguration { private(set) var severityConfiguration = SeverityConfiguration(.warning) @ConfigurationElement(key: "allow_multiline_func") private(set) var allowMultilineFunc = false - @ConfigurationElement(key: "brace_on_new_line") - private(set) var braceOnNewLine = false } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift new file mode 100644 index 0000000000..5d1921c32f --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift @@ -0,0 +1,83 @@ +import SwiftLintCore +import SwiftSyntax + +@SwiftSyntaxRule +struct ContrastedOpeningBraceRule: SwiftSyntaxCorrectableRule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "contrasted_opening_brace", + name: "Contrasted Opening Brace", + description: """ + The correct positioning of braces that introduce a block of code or member list is highly controversial. \ + No matter which style is preferred, consistency is key. Apart from different tastes, \ + the positioning of braces can also have a significant impact on the readability of the code, \ + especially for visually impaired developers. This rule ensures that braces are on a separate line \ + after the declaration to contrast the code block from the rest of the declaration. Comments between the \ + declaration and the opening brace are respected. Check out the `opening_brace` rule for a different style. + """, + kind: .style, + nonTriggeringExamples: ContrastedOpeningBraceRuleExamples.nonTriggeringExamples, + triggeringExamples: ContrastedOpeningBraceRuleExamples.triggeringExamples, + corrections: ContrastedOpeningBraceRuleExamples.corrections + ) +} + +private extension ContrastedOpeningBraceRule { + final class Visitor: CodeBlockVisitor { + override func collectViolations(for bracedItem: (some BracedSyntax)?) { + if let bracedItem, let correction = violationCorrection(bracedItem) { + violations.append( + ReasonedRuleViolation( + position: bracedItem.openingPosition, + reason: "Opening brace should be on a separate line", + correction: correction + ) + ) + } + } + + private func violationCorrection(_ node: some BracedSyntax) -> ReasonedRuleViolation.ViolationCorrection? { + let leftBrace = node.leftBrace + guard let previousToken = leftBrace.previousToken(viewMode: .sourceAccurate) else { + return nil + } + let openingPosition = node.openingPosition + let triviaBetween = previousToken.trailingTrivia + leftBrace.leadingTrivia + let previousLocation = previousToken.endLocation(converter: locationConverter) + let leftBraceLocation = leftBrace.startLocation(converter: locationConverter) + let parentStartColumn = node + .indentationDecidingParent? + .startLocation(converter: locationConverter) + .column ?? 1 + if previousLocation.line + 1 == leftBraceLocation.line, leftBraceLocation.column == parentStartColumn { + return nil + } + let comment = triviaBetween.description.trimmingTrailingCharacters(in: .whitespacesAndNewlines) + return .init( + start: previousToken.endPositionBeforeTrailingTrivia + SourceLength(of: comment), + end: openingPosition, + replacement: "\n" + String(repeating: " ", count: parentStartColumn - 1) + ) + } + } +} + +private extension BracedSyntax { + var openingPosition: AbsolutePosition { + leftBrace.positionAfterSkippingLeadingTrivia + } + + var indentationDecidingParent: (any SyntaxProtocol)? { + if let catchClause = parent?.as(CatchClauseSyntax.self) { + return catchClause.parent?.as(CatchClauseListSyntax.self)?.parent?.as(DoStmtSyntax.self) + } + if parent?.as(IfExprSyntax.self)?.keyPathInParent == \IfExprSyntax.elseBody { + return parent?.parent + } + if let binding = parent?.as(PatternBindingSyntax.self) { + return binding.parent?.as(PatternBindingListSyntax.self)?.parent?.as(VariableDeclSyntax.self) + } + return parent + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift new file mode 100644 index 0000000000..bd9238c077 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift @@ -0,0 +1,416 @@ +// swiftlint:disable file_length + +// swiftlint:disable:next type_body_length +struct ContrastedOpeningBraceRuleExamples { + static let nonTriggeringExamples = [ + Example(""" + func abc() + { + } + """), + Example(""" + [].map() + { + $0 + } + """), + Example(""" + [].map( + { + } + ) + """), + Example(""" + if let a = b + { + } + """), + Example(""" + while a == b + { + } + """), + Example(""" + guard let a = b else + { + } + """), + Example(""" + struct Rule + { + } + """), + Example(""" + struct Parent + { + struct Child + { + let foo: Int + } + } + """), + Example(""" + func f(rect: CGRect) + { + { + let centre = CGPoint(x: rect.midX, y: rect.midY) + print(centre) + }() + } + """), + Example(""" + func f(rect: CGRect) -> () -> Void + { + { + let centre = CGPoint(x: rect.midX, y: rect.midY) + print(centre) + } + } + """), + Example(""" + func f() -> () -> Void + { + {} + } + """), + Example(""" + @MyProperty class Rule: + NSObject + { + var a: String + { + return "" + } + } + """), + Example(""" + self.foo( + ( + "String parameter", + { "Do something here" } + ) + ) + """), + Example(##"let pattern = #/(\{(?\w+)\})/#"##), + Example(""" + if c + {} + else + {} + """), + Example(""" + if c /* comment */ + { + return + } + """), + ] + + static let triggeringExamples = [ + Example(""" + func abc()↓{ + } + """), + Example(""" + func abc() { } + """), + Example(""" + func abc(a: A, + b: B) {} + """), + Example(""" + [].map { $0 } + """), + Example(""" + struct OldContentView: View ↓{ + @State private var showOptions = false + + var body: some View ↓{ + Button(action: { + self.showOptions.toggle() + })↓{ + Image(systemName: "gear") + } label: ↓{ + Image(systemName: "gear") + } + } + } + """), + Example(""" + class Rule + { + var a: String↓{ + return "" + } + } + """), + Example(""" + @MyProperty class Rule + { + var a: String + { + willSet↓{ + + } + didSet ↓{ + + } + } + } + """), + Example(""" + precedencegroup Group ↓{ + assignment: true + } + """), + Example(""" + class TestFile + { + func problemFunction() ↓{ + #if DEBUG + #endif + } + + func openingBraceViolation() + { + print("Brackets") + } + } + """, excludeFromDocumentation: true), + Example(""" + if + "test".isEmpty ↓{ + // code here + } + """), + Example(""" + if c ↓{} + else /* comment */ ↓{} + """), + Example(""" + if c + ↓{ + // code here + } + """), + ] + + static let corrections = [ + Example(""" + struct Rule{} + """): Example(""" + struct Rule + {} + """), + Example(""" + struct Parent { + struct Child { + let foo: Int + } + } + """): Example(""" + struct Parent + { + struct Child + { + let foo: Int + } + } + """), + Example(""" + [].map(){ $0 } + """): Example(""" + [].map() + { $0 } + """), + Example(""" + if a == b{ } + """): Example(""" + if a == b + { } + """), + Example(""" + @MyProperty actor MyActor { + + } + """): Example(""" + @MyProperty actor MyActor + { + + } + """), + Example(""" + actor MyActor where T: U { + + } + """): Example(""" + actor MyActor where T: U + { + + } + """), + Example(""" + do { + + } catch { + + } + """): Example(""" + do + { + + } catch + { + + } + """), + Example(""" + do { + + } catch MyError.unknown { + + } + """): Example(""" + do + { + + } catch MyError.unknown + { + + } + """), + Example(""" + defer { + + } + """): Example(""" + defer + { + + } + """), + Example(""" + for a in b where a == c { + + } + """): Example(""" + for a in b where a == c + { + + } + """), + Example(""" + if varDecl.parent?.is(CodeBlockItemSyntax.self) == true // Local variable declaration + || varDecl.bindings.onlyElement?.accessor != nil // Computed property + || !node.type.is(SimpleTypeIdentifierSyntax.self) { // Complex or collection type + return .visitChildren + } + """): Example(""" + if varDecl.parent?.is(CodeBlockItemSyntax.self) == true // Local variable declaration + || varDecl.bindings.onlyElement?.accessor != nil // Computed property + || !node.type.is(SimpleTypeIdentifierSyntax.self) + { // Complex or collection type + return .visitChildren + } + """), + Example(""" + @MyProperty class Rule + { + var a: String { + didSet { + + } + } + } + """): Example(""" + @MyProperty class Rule + { + var a: String + { + didSet + { + + } + } + } + """), + Example(""" + precedencegroup Group{ + assignment: true + } + """): Example(""" + precedencegroup Group + { + assignment: true + } + """), + Example(""" + if c /* comment */ { + return + } + """): Example(""" + if c /* comment */ + { + return + } + """), + Example(""" + func foo() { + if q1, q2 { + do1() + } else if q3, q4 { + do2() + } + } + """): Example(""" + func foo() + { + if q1, q2 + { + do1() + } else if q3, q4 + { + do2() + } + } + """), + Example(""" + if + "test".isEmpty + // swiftlint:disable:next contrasted_opening_brace + { + // code here + } + """): Example(""" + if + "test".isEmpty + // swiftlint:disable:next contrasted_opening_brace + { + // code here + } + """), + Example(""" + private func f() + // comment + { + let a = 1 + } + """): Example(""" + private func f() + // comment + { + let a = 1 + } + """), + Example(""" + while true /* endless loop */ { + // nothing + } + """): Example(""" + while true /* endless loop */ + { + // nothing + } + """), + ] +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index 79818a2dc3..3dbbaeb9ef 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -12,9 +12,9 @@ struct OpeningBraceRule: SwiftSyntaxCorrectableRule { The correct positioning of braces that introduce a block of code or member list is highly controversial. \ No matter which style is preferred, consistency is key. Apart from different tastes, \ the positioning of braces can also have a significant impact on the readability of the code, \ - especially for visually impaired developers. This rule ensures that braces are either preceded \ - by a single space and on the same line as the declaration or on a separate line after the declaration \ - itself. Comments between the declaration and the opening brace are respected. + especially for visually impaired developers. This rule ensures that braces are preceded \ + by a single space and on the same line as the declaration. Comments between the declaration and the \ + opening brace are respected. Check out the `contrasted_opening_brace` rule for a different style. """, kind: .style, nonTriggeringExamples: OpeningBraceRuleExamples.nonTriggeringExamples, @@ -24,97 +24,7 @@ struct OpeningBraceRule: SwiftSyntaxCorrectableRule { } private extension OpeningBraceRule { - final class Visitor: ViolationsSyntaxVisitor { - override func visitPost(_ node: ActorDeclSyntax) { - collectViolation(for: node.memberBlock) - } - - override func visitPost(_ node: ClassDeclSyntax) { - collectViolation(for: node.memberBlock) - } - - override func visitPost(_ node: EnumDeclSyntax) { - collectViolation(for: node.memberBlock) - } - - override func visitPost(_ node: ExtensionDeclSyntax) { - collectViolation(for: node.memberBlock) - } - - override func visitPost(_ node: ProtocolDeclSyntax) { - collectViolation(for: node.memberBlock) - } - - override func visitPost(_ node: StructDeclSyntax) { - collectViolation(for: node.memberBlock) - } - - override func visitPost(_ node: CatchClauseSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: DeferStmtSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: DoStmtSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: ForStmtSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: GuardStmtSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: IfExprSyntax) { - collectViolation(for: node.body) - if case let .codeBlock(body) = node.elseBody { - collectViolation(for: body) - } - } - - override func visitPost(_ node: RepeatStmtSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: WhileStmtSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: SwitchExprSyntax) { - collectViolation(for: node) - } - - override func visitPost(_ node: AccessorDeclSyntax) { - collectViolation(for: node.body) - } - - override func visitPost(_ node: PatternBindingSyntax) { - collectViolation(for: node.accessorBlock) - } - - override func visitPost(_ node: PrecedenceGroupDeclSyntax) { - collectViolation(for: node) - } - - override func visitPost(_ node: ClosureExprSyntax) { - guard let parent = node.parent else { - return - } - if parent.is(LabeledExprSyntax.self) { - // Function parameter - return - } - if parent.is(FunctionCallExprSyntax.self) || parent.is(MultipleTrailingClosureElementSyntax.self), - node.keyPathInParent != \FunctionCallExprSyntax.calledExpression { - // Trailing closure - collectViolation(for: node) - } - } - + final class Visitor: CodeBlockVisitor { override func visitPost(_ node: FunctionDeclSyntax) { guard let body = node.body else { return @@ -122,7 +32,7 @@ private extension OpeningBraceRule { if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.funcKeyword) { return } - collectViolation(for: body) + collectViolations(for: body) } override func visitPost(_ node: InitializerDeclSyntax) { @@ -132,7 +42,7 @@ private extension OpeningBraceRule { if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.initKeyword) { return } - collectViolation(for: body) + collectViolations(for: body) } private func refersToMultilineFunction(_ body: CodeBlockSyntax, functionIndicator: TokenSyntax) -> Bool { @@ -145,14 +55,12 @@ private extension OpeningBraceRule { return startLocation.line != endLocation.line && endLocation.line != braceLocation.line } - private func collectViolation(for bracedItem: (some BracedSyntax)?) { + override func collectViolations(for bracedItem: (some BracedSyntax)?) { if let bracedItem, let correction = violationCorrection(bracedItem) { violations.append( ReasonedRuleViolation( position: bracedItem.openingPosition, - reason: configuration.braceOnNewLine - ? "Opening brace should be on a separate line" - : """ + reason: """ Opening braces should be preceded by a single space and on the same line \ as the declaration """, @@ -171,18 +79,6 @@ private extension OpeningBraceRule { let triviaBetween = previousToken.trailingTrivia + leftBrace.leadingTrivia let previousLocation = previousToken.endLocation(converter: locationConverter) let leftBraceLocation = leftBrace.startLocation(converter: locationConverter) - if configuration.braceOnNewLine { - let parentStartColumn = node.parent?.startLocation(converter: locationConverter).column ?? 1 - if previousLocation.line + 1 == leftBraceLocation.line, leftBraceLocation.column == parentStartColumn { - return nil - } - let comment = triviaBetween.description.trimmingTrailingCharacters(in: .whitespacesAndNewlines) - return .init( - start: previousToken.endPositionBeforeTrailingTrivia + SourceLength(of: comment), - end: openingPosition, - replacement: "\n" + String(repeating: " ", count: parentStartColumn - 1) - ) - } if previousLocation.line != leftBraceLocation.line { return .init( start: previousToken.endPositionBeforeTrailingTrivia, diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index 9d663d2e6b..e41dc09977 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -58,18 +58,6 @@ struct OpeningBraceRuleExamples { return } """), - Example(""" - if c - { - // code here - } - """, configuration: ["brace_on_new_line": true]), - Example(""" - @MyProperty struct S - { - // code here - } - """, configuration: ["brace_on_new_line": true]), ] static let triggeringExamples = [ @@ -229,17 +217,6 @@ struct OpeningBraceRuleExamples { if c ↓{} else /* comment */ ↓{} """), - Example(""" - if c - ↓{ - // code here - } - """, configuration: ["brace_on_new_line": true]), - Example(""" - @MyProperty struct S ↓{ - // code here - } - """, configuration: ["brace_on_new_line": true]), ] static let corrections = [ @@ -604,61 +581,5 @@ struct OpeningBraceRuleExamples { // code here } """), - Example(""" - if c - { - // code here - } - """, configuration: ["brace_on_new_line": true]): Example(""" - if c - { - // code here - } - """), - Example(""" - @MyProperty struct S { - // code here - } - """, configuration: ["brace_on_new_line": true]): Example(""" - @MyProperty struct S - { - // code here - } - """), - Example(""" - private func f() - - { - let a = 1 - } - """, configuration: ["brace_on_new_line": true]): Example(""" - private func f() - { - let a = 1 - } - """), - Example(""" - private func f() - // comment - { - let a = 1 - } - """, configuration: ["brace_on_new_line": true]): Example(""" - private func f() - // comment - { - let a = 1 - } - """), - Example(""" - while true /* endless loop */ { - // nothing - } - """, configuration: ["brace_on_new_line": true]): Example(""" - while true /* endless loop */ - { - // nothing - } - """), ] } diff --git a/Source/SwiftLintBuiltInRules/Visitors/CodeBlockVisitor.swift b/Source/SwiftLintBuiltInRules/Visitors/CodeBlockVisitor.swift new file mode 100644 index 0000000000..07184901d7 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Visitors/CodeBlockVisitor.swift @@ -0,0 +1,105 @@ +import SwiftLintCore +import SwiftSyntax + +class CodeBlockVisitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: AccessorDeclSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: ActorDeclSyntax) { + collectViolations(for: node.memberBlock) + } + + override func visitPost(_ node: CatchClauseSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: ClassDeclSyntax) { + collectViolations(for: node.memberBlock) + } + + override func visitPost(_ node: ClosureExprSyntax) { + guard let parent = node.parent else { + return + } + if parent.is(LabeledExprSyntax.self) { + // Function parameter + return + } + if parent.is(FunctionCallExprSyntax.self) || parent.is(MultipleTrailingClosureElementSyntax.self), + node.keyPathInParent != \FunctionCallExprSyntax.calledExpression { + // Trailing closure + collectViolations(for: node) + } + } + + override func visitPost(_ node: DeferStmtSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: DoStmtSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: EnumDeclSyntax) { + collectViolations(for: node.memberBlock) + } + + override func visitPost(_ node: ExtensionDeclSyntax) { + collectViolations(for: node.memberBlock) + } + + override func visitPost(_ node: FunctionDeclSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: ForStmtSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: GuardStmtSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: IfExprSyntax) { + collectViolations(for: node.body) + if case let .codeBlock(body) = node.elseBody { + collectViolations(for: body) + } + } + override func visitPost(_ node: InitializerDeclSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: PatternBindingSyntax) { + collectViolations(for: node.accessorBlock) + } + + override func visitPost(_ node: PrecedenceGroupDeclSyntax) { + collectViolations(for: node) + } + + override func visitPost(_ node: ProtocolDeclSyntax) { + collectViolations(for: node.memberBlock) + } + + override func visitPost(_ node: RepeatStmtSyntax) { + collectViolations(for: node.body) + } + + override func visitPost(_ node: StructDeclSyntax) { + collectViolations(for: node.memberBlock) + } + + override func visitPost(_ node: SwitchExprSyntax) { + collectViolations(for: node) + } + + override func visitPost(_ node: WhileStmtSyntax) { + collectViolations(for: node.body) + } + + func collectViolations(for _: (some BracedSyntax)?) { + // Intended to be overridden. + } +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index b2e2fc912f..2c212346f3 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -175,6 +175,12 @@ final class ContainsOverRangeNilComparisonRuleGeneratedTests: SwiftLintTestCase } } +final class ContrastedOpeningBraceRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(ContrastedOpeningBraceRule.description) + } +} + final class ControlStatementRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ControlStatementRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 51167c21db..3edd735e5a 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -66,6 +66,8 @@ contains_over_first_not_nil: severity: warning contains_over_range_nil_comparison: severity: warning +contrasted_opening_brace: + severity: warning control_statement: severity: warning convenience_type: @@ -376,7 +378,6 @@ one_declaration_per_file: opening_brace: severity: warning allow_multiline_func: false - brace_on_new_line: false operator_usage_whitespace: severity: warning lines_look_around: 2 From 6fa25a2a44d6bb045e71bee858305593405483ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 4 Aug 2024 16:38:16 +0200 Subject: [PATCH 154/265] Migrate Azure builds to Swift 5.10 (#5727) --- Gemfile | 2 +- Gemfile.lock | 12 ++++++------ azure-pipelines.yml | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index d613241b20..e19d589da9 100644 --- a/Gemfile +++ b/Gemfile @@ -2,4 +2,4 @@ source 'https://rubygems.org' gem 'cocoapods' gem 'danger' -gem 'jazzy', '~> 0.14.4' +gem 'jazzy', '~> 0.15.1' diff --git a/Gemfile.lock b/Gemfile.lock index a7b45bde06..6058ee2b83 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -92,12 +92,12 @@ GEM httpclient (2.8.3) i18n (1.14.1) concurrent-ruby (~> 1.0) - jazzy (0.14.4) + jazzy (0.15.1) cocoapods (~> 1.5) mustache (~> 1.1) open4 (~> 1.3) redcarpet (~> 3.4) - rexml (~> 3.2) + rexml (>= 3.2.7, < 4.0) rouge (>= 2.0.6, < 5.0) sassc (~> 2.1) sqlite3 (~> 1.3) @@ -124,7 +124,7 @@ GEM redcarpet (3.6.0) rexml (3.2.8) strscan (>= 3.0.9) - rouge (4.2.0) + rouge (4.3.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) sassc (2.4.0) @@ -132,8 +132,8 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) - sqlite3 (1.7.2-arm64-darwin) - sqlite3 (1.7.2-x86_64-linux) + sqlite3 (1.7.3-arm64-darwin) + sqlite3 (1.7.3-x86_64-linux) strscan (3.1.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -161,7 +161,7 @@ PLATFORMS DEPENDENCIES cocoapods danger - jazzy (~> 0.14.4) + jazzy (~> 0.15.1) BUNDLED WITH 2.4.12 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 60d981f294..17f5eea128 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,8 +8,8 @@ jobs: strategy: maxParallel: 10 matrix: - swift59: - containerImage: swift:5.9 + swift-5.10.1: + containerImage: swift:5.10.1 container: $[ variables['containerImage'] ] steps: - script: swift test --parallel -Xswiftc -DDISABLE_FOCUSED_EXAMPLES @@ -33,9 +33,9 @@ jobs: # displayName: xcodebuild test - job: CocoaPods pool: - vmImage: 'macOS-13' + vmImage: 'macOS-14' variables: - DEVELOPER_DIR: /Applications/Xcode_15.0.app + DEVELOPER_DIR: /Applications/Xcode_15.4.app steps: - script: bundle install --path vendor/bundle displayName: bundle install @@ -46,9 +46,9 @@ jobs: - job: jazzy pool: - vmImage: 'macOS-13' + vmImage: 'macOS-14' variables: - DEVELOPER_DIR: /Applications/Xcode_15.0.app + DEVELOPER_DIR: /Applications/Xcode_15.4.app steps: - script: swift run swiftlint generate-docs displayName: Run swiftlint generate-docs From 1d26f4c0effaef973809b20024c4d97a2795be65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 5 Aug 2024 23:09:50 +0200 Subject: [PATCH 155/265] Let descriptions be immutable (#5729) --- .../Rules/Idiomatic/PreferKeyPathRule.swift | 2 +- .../SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift | 2 +- .../Rules/Performance/FinalTestCaseRule.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift index 9bf05ee4b8..d996119a65 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift @@ -7,7 +7,7 @@ struct PreferKeyPathRule: OptInRule { private static let extendedMode = ["restrict_to_standard_functions": false] - static var description = RuleDescription( + static let description = RuleDescription( identifier: "prefer_key_path", name: "Prefer Key Path", description: "Use a key path argument instead of a closure with property access", diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift index 91816cb712..cc97758ccf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift @@ -5,7 +5,7 @@ import SwiftSyntaxBuilder struct ToggleBoolRule: OptInRule { var configuration = SeverityConfiguration(.warning) - static var description = RuleDescription( + static let description = RuleDescription( identifier: "toggle_bool", name: "Toggle Bool", description: "Prefer `someBool.toggle()` over `someBool = !someBool`", diff --git a/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift index 066b9daaea..5afde4bc10 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Performance/FinalTestCaseRule.swift @@ -5,7 +5,7 @@ import SwiftSyntax struct FinalTestCaseRule: OptInRule { var configuration = FinalTestCaseConfiguration() - static var description = RuleDescription( + static let description = RuleDescription( identifier: "final_test_case", name: "Final Test Case", description: "Test cases should be final", From 78b665d53697ab729eeb1f8df52dcc984879b29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 5 Aug 2024 23:48:50 +0200 Subject: [PATCH 156/265] Unroll parsing code to make `Version` a struct (#5730) --- .../Rules/Lint/DeploymentTargetRule.swift | 4 +- .../DeploymentTargetConfiguration.swift | 83 +++++++++++-------- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift index e31ad3ed9c..45a18ed6a7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/DeploymentTargetRule.swift @@ -1,7 +1,7 @@ import SwiftSyntax @SwiftSyntaxRule -struct DeploymentTargetRule { +struct DeploymentTargetRule: Rule { fileprivate typealias Version = DeploymentTargetConfiguration.Version var configuration = DeploymentTargetConfiguration() @@ -108,7 +108,7 @@ private extension DeploymentTargetRule { return nil } - guard let version = try? Version(platform: platform, rawValue: versionString), + guard let version = try? Version(platform: platform, value: versionString), version <= minVersion else { return nil } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift index 9fef4a4c8e..6c7cd87ee1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift @@ -16,18 +16,18 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { rawValue + "_deployment_target" } - var appExtensionCounterpart: Self? { + var appExtensionCounterpart: WritableKeyPath? { switch self { - case .iOS: return Self.iOSApplicationExtension - case .macOS: return Self.macOSApplicationExtension - case .watchOS: return Self.watchOSApplicationExtension - case .tvOS: return Self.tvOSApplicationExtension - default: return nil + case .iOS: \DeploymentTargetConfiguration.iOSAppExtensionDeploymentTarget + case .macOS: \DeploymentTargetConfiguration.macOSAppExtensionDeploymentTarget + case .watchOS: \DeploymentTargetConfiguration.watchOSAppExtensionDeploymentTarget + case .tvOS: \DeploymentTargetConfiguration.tvOSAppExtensionDeploymentTarget + default: nil } } } - class Version: Equatable, Comparable { + struct Version: Equatable, Comparable { let platform: Platform var major: Int var minor: Int @@ -47,16 +47,13 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { self.patch = patch } - convenience init(platform: Platform, rawValue: String) throws { - let (major, minor, patch) = try Self.parseVersion(string: rawValue) + init(platform: Platform, value: Any) throws { + let (major, minor, patch) = try Self.parseVersion(string: String(describing: value)) self.init(platform: platform, major: major, minor: minor, patch: patch) } - fileprivate func update(using value: Any) throws { - let (major, minor, patch) = try Self.parseVersion(string: String(describing: value)) - self.major = major - self.minor = minor - self.patch = patch + var configurationKey: String { + platform.configurationKey } private static func parseVersion(string: String) throws -> (Int, Int, Int) { @@ -80,11 +77,11 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { } } - static func == (lhs: Version, rhs: Version) -> Bool { + static func == (lhs: Self, rhs: Self) -> Bool { lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch == rhs.patch } - static func < (lhs: Version, rhs: Version) -> Bool { + static func < (lhs: Self, rhs: Self) -> Bool { if lhs.major != rhs.major { return lhs.major < rhs.major } @@ -107,17 +104,8 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { private(set) var severityConfiguration = SeverityConfiguration(.warning) - private let targets: [String: Version] - var parameterDescription: RuleConfigurationDescription? { - severityConfiguration - for (platform, target) in targets.sorted(by: { $0.key < $1.key }) { - platform => .symbol(target.stringValue) - } - } - - init() { - self.targets = Dictionary(uniqueKeysWithValues: [ + let targets = Dictionary(uniqueKeysWithValues: [ iOSDeploymentTarget, iOSAppExtensionDeploymentTarget, macOSDeploymentTarget, @@ -127,8 +115,13 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { tvOSDeploymentTarget, tvOSAppExtensionDeploymentTarget, ].map { ($0.platform.configurationKey, $0) }) + severityConfiguration + for (platform, target) in targets.sorted(by: { $0.key < $1.key }) { + platform => .symbol(target.stringValue) + } } + // swiftlint:disable:next cyclomatic_complexity mutating func apply(configuration: Any) throws { guard let configuration = configuration as? [String: Any] else { throw Issue.invalidConfiguration(ruleID: Parent.identifier) @@ -138,15 +131,37 @@ struct DeploymentTargetConfiguration: SeverityBasedRuleConfiguration { try severityConfiguration.apply(configuration: value) continue } - guard let target = targets[key] else { - throw Issue.invalidConfiguration(ruleID: Parent.identifier) - } - try target.update(using: value) - if let extensionConfigurationKey = target.platform.appExtensionCounterpart?.configurationKey, - configuration[extensionConfigurationKey] == nil, - let child = targets[extensionConfigurationKey] { - try child.update(using: value) + switch key { + case iOSDeploymentTarget.platform.configurationKey: + try apply(value: value, to: \.iOSDeploymentTarget, from: configuration) + case iOSAppExtensionDeploymentTarget.platform.configurationKey: + iOSAppExtensionDeploymentTarget = try Version(platform: .iOSApplicationExtension, value: value) + case macOSDeploymentTarget.platform.configurationKey: + try apply(value: value, to: \.macOSDeploymentTarget, from: configuration) + case macOSAppExtensionDeploymentTarget.platform.configurationKey: + macOSAppExtensionDeploymentTarget = try Version(platform: .macOSApplicationExtension, value: value) + case watchOSDeploymentTarget.platform.configurationKey: + try apply(value: value, to: \.watchOSDeploymentTarget, from: configuration) + case watchOSAppExtensionDeploymentTarget.platform.configurationKey: + watchOSAppExtensionDeploymentTarget = try Version(platform: .watchOSApplicationExtension, value: value) + case tvOSDeploymentTarget.platform.configurationKey: + try apply(value: value, to: \.tvOSDeploymentTarget, from: configuration) + case tvOSAppExtensionDeploymentTarget.platform.configurationKey: + tvOSAppExtensionDeploymentTarget = try Version(platform: .tvOSApplicationExtension, value: value) + default: throw Issue.invalidConfiguration(ruleID: Parent.identifier) } } } + + private mutating func apply(value: Any, + to target: WritableKeyPath, + from configuration: [String: Any]) throws { + let platform = self[keyPath: target].platform + self[keyPath: target] = try Version(platform: platform, value: value) + if let counterpart = platform.appExtensionCounterpart, + case let counterPlatform = self[keyPath: counterpart].platform, + configuration[counterPlatform.configurationKey] == nil { + self[keyPath: counterpart] = try Version(platform: counterPlatform, value: value) + } + } } From 5d473ba6d78b457e48ae343ab43d96a800a84834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 6 Aug 2024 21:41:16 +0200 Subject: [PATCH 157/265] Shorten template title --- .github/ISSUE_TEMPLATE/proposal.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md index 096971879a..92b30675fc 100644 --- a/.github/ISSUE_TEMPLATE/proposal.md +++ b/.github/ISSUE_TEMPLATE/proposal.md @@ -1,5 +1,5 @@ --- -name: Feature Request or Enhancement Proposal +name: Feature or Enhancement Proposal about: Let us know about a feature idea or propose an improvement. --- @@ -9,7 +9,7 @@ about: Let us know about a feature idea or propose an improvement. - [ ] I've Updated SwiftLint to the latest version. - [ ] I've searched for [existing GitHub issues](https://github.com/realm/SwiftLint/issues). -### Feature Request or Enhancement Proposal +### Feature or Enhancement Proposal Describe you idea or proposal here. This can be a new feature, an enhancement to an existing feature, or a change to the project's behavior. Be sure to include the rationale behind the proposal and any relevant context or examples. From 22bdffef4a0cf1fce641445d4981ddc88675bc59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 6 Aug 2024 22:36:06 +0200 Subject: [PATCH 158/265] Update template to accommodate recent changes in target struct --- tools/Version.swift.template | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/Version.swift.template b/tools/Version.swift.template index bee640a048..685d37697e 100644 --- a/tools/Version.swift.template +++ b/tools/Version.swift.template @@ -1,8 +1,20 @@ /// A type describing the SwiftLint version. -public struct Version { +public struct Version: VersionComparable { /// The string value for this version. public let value: String + /// An alias for `value` required for protocol conformance. + public var rawValue: String { + value + } + /// The current SwiftLint version. - public static let current = Version(value: "__VERSION__") + public static let current = Self(value: "__VERSION__") + + /// Public initializer. + /// + /// - parameter value: The string value for this version. + public init(value: String) { + self.value = value + } } From 3ed1391e1d140fa9e9468b8ecba0d0f76b9752bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 6 Aug 2024 22:37:33 +0200 Subject: [PATCH 159/265] Release 0.56.0 --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed8841c985..78f14c1e9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Main +## 0.56.0: Heat Pump Dryer #### Breaking diff --git a/MODULE.bazel b/MODULE.bazel index 91a2ba3b29..68e2cce1f5 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "swiftlint", - version = "0.55.1", + version = "0.56.0", compatibility_level = 1, repo_name = "SwiftLint", ) diff --git a/Package.swift b/Package.swift index af32be06c4..ac6636796d 100644 --- a/Package.swift +++ b/Package.swift @@ -172,8 +172,8 @@ let package = Package( package.targets.append( .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.55.1/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "722a705de1cf4e0e07f2b7d2f9f631f3a8b2635a0c84cce99f9677b38aa4a1d6" + url: "https://github.com/realm/SwiftLint/releases/download/0.56.0/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "dcf90197f60b9fe4533544a9a3ec0538c9308cadbce2d5b20f5966376c53579a" ) ) #endif diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index ed7b6cd984..4662563e10 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -9,7 +9,7 @@ public struct Version: VersionComparable { } /// The current SwiftLint version. - public static let current = Self(value: "0.55.1") + public static let current = Self(value: "0.56.0") /// Public initializer. /// From fe4f5591178f9f8a1ed4aa00545bdc23d5ee2d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 6 Aug 2024 22:38:44 +0200 Subject: [PATCH 160/265] Add new changelog section --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f14c1e9e..861137312f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Main + +#### Breaking + +* None. + +#### Experimental + +* None. + +#### Enhancements + +* None. + +#### Bug Fixes + +* None. + ## 0.56.0: Heat Pump Dryer #### Breaking From 248ffafd83352c12608ee9a77503d2ece548756e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 7 Aug 2024 01:02:45 +0200 Subject: [PATCH 161/265] Make `contrasted_opening_brace` opt-in --- .../Rules/Style/ContrastedOpeningBraceRule.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift index 5d1921c32f..318d6590b6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift @@ -2,7 +2,7 @@ import SwiftLintCore import SwiftSyntax @SwiftSyntaxRule -struct ContrastedOpeningBraceRule: SwiftSyntaxCorrectableRule { +struct ContrastedOpeningBraceRule: OptInRule, SwiftSyntaxCorrectableRule { var configuration = SeverityConfiguration(.warning) static let description = RuleDescription( From da9406bbb980b928b6880e5505a7ca34bdc5ae39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 7 Aug 2024 01:07:37 +0200 Subject: [PATCH 162/265] Add changelog entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 861137312f..7c7db0be75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ #### Bug Fixes -* None. +* Let `contrasted_opening_brace` be an opt-in rule. + [SimplyDanny](https://github.com/SimplyDanny) ## 0.56.0: Heat Pump Dryer From 586dd54db496cbcc03c1aaddb3078bab19de5739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 7 Aug 2024 01:09:36 +0200 Subject: [PATCH 163/265] Release 0.56.1 --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7db0be75..6181566b0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Main +## 0.56.1: Heat Pump Dryer #### Breaking diff --git a/MODULE.bazel b/MODULE.bazel index 68e2cce1f5..84ed011044 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "swiftlint", - version = "0.56.0", + version = "0.56.1", compatibility_level = 1, repo_name = "SwiftLint", ) diff --git a/Package.swift b/Package.swift index ac6636796d..9d0c88c9c4 100644 --- a/Package.swift +++ b/Package.swift @@ -172,8 +172,8 @@ let package = Package( package.targets.append( .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.56.0/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "dcf90197f60b9fe4533544a9a3ec0538c9308cadbce2d5b20f5966376c53579a" + url: "https://github.com/realm/SwiftLint/releases/download/0.56.1/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "146ef723e83d301b9f1ef647dc924a55dae293887e633618e76f8cb526292f0c" ) ) #endif diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index 4662563e10..0edafff9d3 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -9,7 +9,7 @@ public struct Version: VersionComparable { } /// The current SwiftLint version. - public static let current = Self(value: "0.56.0") + public static let current = Self(value: "0.56.1") /// Public initializer. /// From 4a83c365b13f21928a340a2959ff6bfeef203be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 7 Aug 2024 01:11:30 +0200 Subject: [PATCH 164/265] Add new changelog section --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6181566b0a..2750761f45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Main + +#### Breaking + +* None. + +#### Experimental + +* None. + +#### Enhancements + +* None. + +#### Bug Fixes + +* None. + ## 0.56.1: Heat Pump Dryer #### Breaking From d1923573080cda6336eba6bd199cdf0d63b945a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 8 Aug 2024 20:06:15 +0200 Subject: [PATCH 165/265] Update "Publish to BCR" config --- .bcr/config.yml | 3 --- .bcr/metadata.template.json | 5 +++++ .bcr/presubmit.yml | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 .bcr/config.yml diff --git a/.bcr/config.yml b/.bcr/config.yml deleted file mode 100644 index 89045ecc3b..0000000000 --- a/.bcr/config.yml +++ /dev/null @@ -1,3 +0,0 @@ -fixedReleaser: - login: jpsim - email: jp@jpsim.com diff --git a/.bcr/metadata.template.json b/.bcr/metadata.template.json index 907734edc3..84b6013c36 100644 --- a/.bcr/metadata.template.json +++ b/.bcr/metadata.template.json @@ -5,6 +5,11 @@ "email": "jp@jpsim.com", "github": "jpsim", "name": "JP Simard" + }, + { + "email": "danny.moesch@icloud.com", + "github": "SimplyDanny", + "name": "Danny Mösch" } ], "repository": [ diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml index e1febf595f..80a746c9ad 100644 --- a/.bcr/presubmit.yml +++ b/.bcr/presubmit.yml @@ -9,7 +9,7 @@ tasks: platform: ubuntu2004 environment: CC: "clang" - SWIFT_VERSION: "5.8.1" + SWIFT_VERSION: "5.10" SWIFT_HOME: "$HOME/swift-$SWIFT_VERSION" PATH: "$PATH:$SWIFT_HOME/usr/bin" shell_commands: *shell_commands From cffb33100957b75b701cccaa9f5f77b0ef04bcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 18 Aug 2024 22:53:57 +0200 Subject: [PATCH 166/265] Fix spurious Bazel build errors (#5756) --- .buildkite/pipeline.yml | 2 - .../Rules/Lint/ArrayInitRule.swift | 2 +- .../Rules/Lint/UnusedDeclarationRule.swift | 44 +++++++++---------- tools/add-preconcurrency-imports.sh | 14 ------ 4 files changed, 23 insertions(+), 39 deletions(-) delete mode 100755 tools/add-preconcurrency-imports.sh diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 4fcb804d9d..22fb23aafe 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -7,8 +7,6 @@ steps: - bazel test --test_output=errors //Tests/... - label: "Build With Strict Concurrency" commands: - - echo "+++ Add @preconcurrency imports" - - ./tools/add-preconcurrency-imports.sh - echo "+++ Build" - bazel build --define strict_concurrency_builtin_rules=true :swiftlint - echo "--- Clean up" diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift index 088c3a878b..9d36b2c15d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/ArrayInitRule.swift @@ -1,7 +1,7 @@ import SwiftSyntax @SwiftSyntaxRule -struct ArrayInitRule: OptInRule { +struct ArrayInitRule: OptInRule, @unchecked Sendable { var configuration = SeverityConfiguration(.warning) static let description = RuleDescription( diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index 3e8cf1d1c1..d851ab72c0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -121,6 +121,20 @@ private extension SwiftLintFile { editorOpen: SourceKittenDictionary, compilerArguments: [String], configuration: UnusedDeclarationConfiguration) -> UnusedDeclarationRule.DeclaredUSR? { + // Skip initializers, deinit, enum cases and subscripts since we can't reliably detect if they're used. + let declarationKindsToSkip: Set = [ + .enumelement, + .extensionProtocol, + .extension, + .extensionEnum, + .extensionClass, + .extensionStruct, + .functionConstructor, + .functionDestructor, + .functionSubscript, + .genericTypeParam, + ] + guard let stringKind = indexEntity.kind, stringKind.starts(with: "source.lang.swift.decl."), !stringKind.contains(".accessor."), @@ -196,6 +210,14 @@ private extension SwiftLintFile { } private func shouldIgnoreEntity(_ indexEntity: SourceKittenDictionary, relatedUSRsToSkip: Set) -> Bool { + let declarationAttributesToSkip: Set = [ + .ibaction, + .main, + .nsApplicationMain, + .override, + .uiApplicationMain, + ] + if indexEntity.shouldSkipIndexEntityToWorkAroundSR11985() || indexEntity.shouldSkipRelated(relatedUSRsToSkip: relatedUSRsToSkip) || indexEntity.enclosedSwiftAttributes.contains(where: declarationAttributesToSkip.contains) || @@ -321,25 +343,3 @@ private extension SourceKittenDictionary { return nil } } - -// Skip initializers, deinit, enum cases and subscripts since we can't reliably detect if they're used. -private let declarationKindsToSkip: Set = [ - .enumelement, - .extensionProtocol, - .extension, - .extensionEnum, - .extensionClass, - .extensionStruct, - .functionConstructor, - .functionDestructor, - .functionSubscript, - .genericTypeParam, -] - -private let declarationAttributesToSkip: Set = [ - .ibaction, - .main, - .nsApplicationMain, - .override, - .uiApplicationMain, -] diff --git a/tools/add-preconcurrency-imports.sh b/tools/add-preconcurrency-imports.sh deleted file mode 100755 index e65de3a03c..0000000000 --- a/tools/add-preconcurrency-imports.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -files=( -"Source/SwiftLintBuiltInRules/Rules/Idiomatic/PrivateOverFilePrivateRule.swift" -"Source/SwiftLintBuiltInRules/Rules/Idiomatic/ToggleBoolRule.swift" -"Source/SwiftLintBuiltInRules/Rules/Lint/UnusedClosureParameterRule.swift" -"Source/SwiftLintBuiltInRules/Rules/Style/EmptyEnumArgumentsRule.swift" -"Source/SwiftLintBuiltInRules/Rules/Style/OptionalEnumCaseMatchingRule.swift" -"Source/SwiftLintBuiltInRules/Rules/Style/TrailingCommaRule.swift" -) - -for file in "${files[@]}"; do - sed -i '' -e 's/import SwiftSyntax$/@preconcurrency import SwiftSyntax/g' "$file" -done From fac959989ea36a4b6063c5485a27642f491cef24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 18 Aug 2024 23:14:17 +0200 Subject: [PATCH 167/265] Add Swift builds running on macOS 13 (#5734) --- azure-pipelines.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 17f5eea128..992185d397 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,6 +15,15 @@ jobs: - script: swift test --parallel -Xswiftc -DDISABLE_FOCUSED_EXAMPLES displayName: swift test +- job: macOS13 + pool: + vmImage: 'macOS-13' + strategy: + maxParallel: 10 + steps: + - script: swift test --parallel -Xswiftc -DDISABLE_FOCUSED_EXAMPLES + displayName: swift test + # TODO: Re-enable when FB11648454 is fixed # - job: Xcode # pool: @@ -44,7 +53,7 @@ jobs: - script: bundle exec pod lib lint --platforms=macos --verbose displayName: pod lib lint -- job: jazzy +- job: Jazzy pool: vmImage: 'macOS-14' variables: From a0a69a63091aec3e1d41b4a842f18e1ca80d5fff Mon Sep 17 00:00:00 2001 From: Luis Padron Date: Sun, 18 Aug 2024 17:21:34 -0400 Subject: [PATCH 168/265] Update Bazel bzlmod dependencies for `rules_swift` 2.x support (#5736) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- MODULE.bazel | 12 ++++++------ Package.resolved | 4 ++-- Package.swift | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 84ed011044..c1055f246d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,11 +8,11 @@ module( bazel_dep(name = "apple_support", version = "1.16.0", repo_name = "build_bazel_apple_support") bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "platforms", version = "0.0.10") -bazel_dep(name = "rules_apple", version = "3.6.0", repo_name = "build_bazel_rules_apple") -bazel_dep(name = "rules_swift", version = "1.18.0", repo_name = "build_bazel_rules_swift") -bazel_dep(name = "sourcekitten", version = "0.35.0", repo_name = "com_github_jpsim_sourcekitten") -bazel_dep(name = "swift-syntax", version = "600.0.0-prerelease-2024-07-24", repo_name = "SwiftSyntax") -bazel_dep(name = "swift_argument_parser", version = "1.3.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") +bazel_dep(name = "rules_apple", version = "3.8.0", repo_name = "build_bazel_rules_apple") +bazel_dep(name = "rules_swift", version = "2.1.1", repo_name = "build_bazel_rules_swift") +bazel_dep(name = "sourcekitten", version = "0.36.0", repo_name = "com_github_jpsim_sourcekitten") +bazel_dep(name = "swift-syntax", version = "600.0.0-prerelease-2024-08-14", repo_name = "SwiftSyntax") +bazel_dep(name = "swift_argument_parser", version = "1.3.1.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") bazel_dep(name = "yams", version = "5.1.3", repo_name = "sourcekitten_com_github_jpsim_yams") swiftlint_repos = use_extension("//bazel:repos.bzl", "swiftlint_repos_bzlmod") @@ -31,4 +31,4 @@ use_repo(apple_cc_configure, "local_config_apple_cc") # Dev Dependencies -bazel_dep(name = "rules_xcodeproj", version = "1.13.0", dev_dependency = True) +bazel_dep(name = "rules_xcodeproj", version = "2.6.1", dev_dependency = True) diff --git a/Package.resolved b/Package.resolved index 30811f5487..204129e258 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "82a453c2dfa335c7e778695762438dfe72b328d2", - "version" : "600.0.0-prerelease-2024-07-24" + "revision" : "515f79b522918f83483068d99c68daeb5116342d", + "version" : "600.0.0-prerelease-2024-08-14" } }, { diff --git a/Package.swift b/Package.swift index 9d0c88c9c4..34fec6bfef 100644 --- a/Package.swift +++ b/Package.swift @@ -29,7 +29,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), - .package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "600.0.0-prerelease-2024-07-24"), + .package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "600.0.0-prerelease-2024-08-14"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), From 5454bc373cd58ea77f8292d49eb962fc532b9392 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 18 Aug 2024 21:41:07 +0000 Subject: [PATCH 169/265] Bump `rexml` from 3.2.8 to 3.3.3 (#5757) Bumps the bundler group with 1 update in the / directory: [rexml](https://github.com/ruby/rexml). Updates `rexml` from 3.2.8 to 3.3.3 - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.2.8...v3.3.3) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect dependency-group: bundler ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6058ee2b83..f09505a870 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -122,8 +122,8 @@ GEM public_suffix (4.0.7) rchardet (1.8.0) redcarpet (3.6.0) - rexml (3.2.8) - strscan (>= 3.0.9) + rexml (3.3.3) + strscan rouge (4.3.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) @@ -144,13 +144,13 @@ GEM unicode-display_width (2.4.2) xcinvoke (0.3.0) liferaft (~> 0.0.6) - xcodeproj (1.22.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) PLATFORMS arm64-darwin-21 From 21b1a03e2bc1e70c6f3e26ed5b2b851375f98505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 19 Aug 2024 20:56:32 +0200 Subject: [PATCH 170/265] Ignore initializers with attributes in `unneeded_synthesized_initializer` rule (#5758) --- CHANGELOG.md | 4 +++- .../Idiomatic/UnneededSynthesizedInitializerRule.swift | 6 ++---- .../UnneededSynthesizedInitializerRuleExamples.swift | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2750761f45..7d1e4d0c68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,9 @@ #### Bug Fixes -* None. +* Ignore initializers with attributes in `unneeded_synthesized_initializer` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5153](https://github.com/realm/SwiftLint/issues/5153) ## 0.56.1: Heat Pump Dryer diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift index d64e30da22..ddd73209a8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRule.swift @@ -112,7 +112,7 @@ private extension StructDeclSyntax { self.initializerParameters($0.parameterList, match: varDecls) && (($0.parameterList.isEmpty && hasNoSideEffects($0.body)) || initializerBody($0.body, matches: varDecls)) && - initializerModifiers($0.modifiers, match: varDecls) && !$0.isInlinable + initializerModifiers($0.modifiers, match: varDecls) && $0.attributes.isEmpty } } @@ -236,9 +236,7 @@ private extension InitializerDeclSyntax { var hasThrowsOrRethrowsKeyword: Bool { signature.effectSpecifiers?.throwsClause?.throwsSpecifier != nil } - var isInlinable: Bool { - attributes.contains(attributeNamed: "inlinable") - } + var parameterList: FunctionParameterListSyntax { signature.parameterClause.parameters } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift index 66c19ebee9..ebeec84c4e 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/UnneededSynthesizedInitializerRuleExamples.swift @@ -244,6 +244,12 @@ enum UnneededSynthesizedInitializerRuleExamples { init() {} } """, excludeFromDocumentation: true), + Example(""" + struct Foo { + @available(*, unavailable) + init() {} + } + """), ] static let triggering = [ From 314c91f426cfc41f0e5e51b284c03b3aad4fb66a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 19 Aug 2024 21:42:10 +0200 Subject: [PATCH 171/265] Check all nested `if` expressions in `contrasted_opening_brace` rule (#5759) --- CHANGELOG.md | 4 ++++ .../Style/ContrastedOpeningBraceRule.swift | 13 +++++++++-- .../ContrastedOpeningBraceRuleExamples.swift | 22 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d1e4d0c68..cb15dd41b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5153](https://github.com/realm/SwiftLint/issues/5153) +* Check `if` expressions nested arbitrarily deep in `contrasted_opening_brace` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5752](https://github.com/realm/SwiftLint/issues/5752) + ## 0.56.1: Heat Pump Dryer #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift index 318d6590b6..b186c2b51f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift @@ -72,8 +72,8 @@ private extension BracedSyntax { if let catchClause = parent?.as(CatchClauseSyntax.self) { return catchClause.parent?.as(CatchClauseListSyntax.self)?.parent?.as(DoStmtSyntax.self) } - if parent?.as(IfExprSyntax.self)?.keyPathInParent == \IfExprSyntax.elseBody { - return parent?.parent + if let ifExpr = parent?.as(IfExprSyntax.self) { + return ifExpr.indentationDecidingParent } if let binding = parent?.as(PatternBindingSyntax.self) { return binding.parent?.as(PatternBindingListSyntax.self)?.parent?.as(VariableDeclSyntax.self) @@ -81,3 +81,12 @@ private extension BracedSyntax { return parent } } + +private extension IfExprSyntax { + var indentationDecidingParent: any SyntaxProtocol { + if keyPathInParent == \IfExprSyntax.elseBody, let parent = parent?.as(IfExprSyntax.self) { + return parent.indentationDecidingParent + } + return self + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift index bd9238c077..41d915d9e6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift @@ -104,6 +104,18 @@ struct ContrastedOpeningBraceRuleExamples { return } """), + Example(""" + if c1 + { + return + } else if c2 + { + return + } else if c3 + { + return + } + """), ] static let triggeringExamples = [ @@ -193,6 +205,16 @@ struct ContrastedOpeningBraceRuleExamples { // code here } """), + Example(""" + if c1 ↓{ + return + } else if c2↓{ + return + } else if c3 + ↓{ + return + } + """), ] static let corrections = [ From d5f7f9c29a67c093a4fd570d07e91cfb082aecc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 19 Aug 2024 22:19:57 +0200 Subject: [PATCH 172/265] Align left closure brace with associated parent function call (#5760) --- CHANGELOG.md | 4 ++++ .../Style/ContrastedOpeningBraceRule.swift | 12 ++++++++++ .../ContrastedOpeningBraceRuleExamples.swift | 22 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb15dd41b5..92a9b7bc63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,10 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5752](https://github.com/realm/SwiftLint/issues/5752) +* Align left closure brace with associated parent function call in `contrasted_opening_brace` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5752](https://github.com/realm/SwiftLint/issues/5752) + ## 0.56.1: Heat Pump Dryer #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift index b186c2b51f..fdd1a939db 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift @@ -78,6 +78,18 @@ private extension BracedSyntax { if let binding = parent?.as(PatternBindingSyntax.self) { return binding.parent?.as(PatternBindingListSyntax.self)?.parent?.as(VariableDeclSyntax.self) } + if let closure = `as`(ClosureExprSyntax.self), + closure.keyPathInParent == \FunctionCallExprSyntax.trailingClosure { + var indentationDecidingToken = closure.leftBrace + repeat { + if let previousToken = indentationDecidingToken.previousToken(viewMode: .sourceAccurate) { + indentationDecidingToken = previousToken + } else { + break + } + } while indentationDecidingToken.leadingTrivia.containsNewlines() == false + return indentationDecidingToken + } return parent } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift index 41d915d9e6..681bc3dd14 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift @@ -116,6 +116,12 @@ struct ContrastedOpeningBraceRuleExamples { return } """), + Example(""" + let a = f.map + { a in + a + } + """), ] static let triggeringExamples = [ @@ -215,6 +221,13 @@ struct ContrastedOpeningBraceRuleExamples { return } """), + Example(""" + func f() + { + return a.map + ↓{ $0 } + } + """), ] static let corrections = [ @@ -434,5 +447,14 @@ struct ContrastedOpeningBraceRuleExamples { // nothing } """), + Example(""" + a.b { $0 } + .c { $1 } + """): Example(""" + a.b + { $0 } + .c + { $1 } + """), ] } From 74f47780701c4768935a5013b8493f20bcec496b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 19 Aug 2024 23:26:48 +0200 Subject: [PATCH 173/265] Align left brace of additional trailing closures with right brace of previous trailing closure (#5761) --- CHANGELOG.md | 5 ++++ .../Style/ContrastedOpeningBraceRule.swift | 27 ++++++++++++------- .../ContrastedOpeningBraceRuleExamples.swift | 22 +++++++++++++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a9b7bc63..610cd812e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5752](https://github.com/realm/SwiftLint/issues/5752) +* Align left brace of additional trailing closures with right brace of previous trailing closure + in `contrasted_opening_brace` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5752](https://github.com/realm/SwiftLint/issues/5752) + ## 0.56.1: Heat Pump Dryer #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift index fdd1a939db..ba4ceb083b 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRule.swift @@ -80,20 +80,29 @@ private extension BracedSyntax { } if let closure = `as`(ClosureExprSyntax.self), closure.keyPathInParent == \FunctionCallExprSyntax.trailingClosure { - var indentationDecidingToken = closure.leftBrace - repeat { - if let previousToken = indentationDecidingToken.previousToken(viewMode: .sourceAccurate) { - indentationDecidingToken = previousToken - } else { - break - } - } while indentationDecidingToken.leadingTrivia.containsNewlines() == false - return indentationDecidingToken + return closure.leftBrace.previousIndentationDecidingToken + } + if let closureLabel = parent?.as(MultipleTrailingClosureElementSyntax.self)?.label { + return closureLabel.previousIndentationDecidingToken } return parent } } +private extension TokenSyntax { + var previousIndentationDecidingToken: TokenSyntax { + var indentationDecidingToken = self + repeat { + if let previousToken = indentationDecidingToken.previousToken(viewMode: .sourceAccurate) { + indentationDecidingToken = previousToken + } else { + break + } + } while !indentationDecidingToken.leadingTrivia.containsNewlines() + return indentationDecidingToken + } +} + private extension IfExprSyntax { var indentationDecidingParent: any SyntaxProtocol { if keyPathInParent == \IfExprSyntax.elseBody, let parent = parent?.as(IfExprSyntax.self) { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift index 681bc3dd14..5caf1fda74 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ContrastedOpeningBraceRuleExamples.swift @@ -228,6 +228,13 @@ struct ContrastedOpeningBraceRuleExamples { ↓{ $0 } } """), + Example(""" + a ↓{ + $0 + } b: ↓{ + $1 + } + """), ] static let corrections = [ @@ -456,5 +463,20 @@ struct ContrastedOpeningBraceRuleExamples { .c { $1 } """), + Example(""" + a { + $0 + } b: { + $1 + } + """): Example(""" + a + { + $0 + } b: + { + $1 + } + """), ] } From 9d0711070d082b53497994594bd867a30c727351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 20 Aug 2024 22:28:30 +0200 Subject: [PATCH 174/265] Trigger on empty closure blocks in `no_empty_block` rule (#5763) --- CHANGELOG.md | 4 +++ .../Rules/Idiomatic/NoEmptyBlockRule.swift | 29 ++++++++++++++++++- .../NoEmptyBlockConfiguration.swift | 1 + .../Extensions/QueuedPrint.swift | 5 +++- .../Extensions/SwiftLintFile+Cache.swift | 2 +- .../Models/RuleConfigurationDescription.swift | 4 +-- .../NoEmptyBlockConfigurationTests.swift | 2 +- 7 files changed, 41 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 610cd812e5..a2639c4c57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,10 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5752](https://github.com/realm/SwiftLint/issues/5752) +* Trigger on empty closure blocks in `no_empty_block` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5762](https://github.com/realm/SwiftLint/issues/5762) + ## 0.56.1: Heat Pump Dryer #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift index 51efc92461..3691a708b6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoEmptyBlockRule.swift @@ -92,6 +92,18 @@ struct NoEmptyBlockRule: OptInRule { while i < 10 {} """, configuration: ["disabled_block_types": ["statement_blocks"]]), + Example(""" + f { _ in /* comment */ } + f { _ in // comment + } + f { _ in + // comment + } + """), + Example(""" + f {} + {}() + """, configuration: ["disabled_block_types": ["closure_blocks"]]), ], triggeringExamples: [ Example(""" @@ -130,6 +142,12 @@ struct NoEmptyBlockRule: OptInRule { while i < 10 ↓{} """), + Example(""" + f ↓{} + """), + Example(""" + Button ↓{} label: ↓{} + """), ] ) } @@ -142,7 +160,14 @@ private extension NoEmptyBlockRule { } } - func validate(node: CodeBlockSyntax) { + override func visitPost(_ node: ClosureExprSyntax) { + if configuration.enabledBlockTypes.contains(.closureBlocks), + node.signature?.inKeyword.trailingTrivia.containsComments != true { + validate(node: node) + } + } + + func validate(node: some BracedSyntax & WithStatementsSyntax) { guard node.statements.isEmpty, !node.leftBrace.trailingTrivia.containsComments, !node.rightBrace.leadingTrivia.containsComments else { @@ -162,6 +187,8 @@ private extension CodeBlockSyntax { .initializerBodies case .forStmt, .doStmt, .whileStmt, .repeatStmt, .ifExpr, .catchClause, .deferStmt: .statementBlocks + case .closureExpr: + .closureBlocks case .guardStmt: // No need to handle this case since Empty Block of `guard` is compile error. nil diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift index a09221fc0b..a367a45575 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/NoEmptyBlockConfiguration.swift @@ -9,6 +9,7 @@ struct NoEmptyBlockConfiguration: SeverityBasedRuleConfiguration { case functionBodies = "function_bodies" case initializerBodies = "initializer_bodies" case statementBlocks = "statement_blocks" + case closureBlocks = "closure_blocks" static let all = Set(allCases) } diff --git a/Source/SwiftLintCore/Extensions/QueuedPrint.swift b/Source/SwiftLintCore/Extensions/QueuedPrint.swift index f4be8d4172..bc898c5b5d 100644 --- a/Source/SwiftLintCore/Extensions/QueuedPrint.swift +++ b/Source/SwiftLintCore/Extensions/QueuedPrint.swift @@ -17,7 +17,10 @@ private let outputQueue: DispatchQueue = { private func setupAtExitHandler() { atexit { - outputQueue.sync(flags: .barrier) {} + // Ensure all queued output is written before exiting. + outputQueue.sync(flags: .barrier) { + // Just wait. + } } } diff --git a/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift b/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift index 26d5175789..65a9bf58bd 100644 --- a/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift +++ b/Source/SwiftLintCore/Extensions/SwiftLintFile+Cache.swift @@ -29,7 +29,7 @@ private let syntaxTreeCache = Cache { file -> SourceFileSyntax in } private let foldedSyntaxTreeCache = Cache { file -> SourceFileSyntax? in OperatorTable.standardOperators - .foldAll(file.syntaxTree) { _ in } + .foldAll(file.syntaxTree) { _ in /* Don't handle errors. */ } .as(SourceFileSyntax.self) } private let locationConverterCache = Cache { file -> SourceLocationConverter in diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index 7ba0dbfae3..b09b4a914e 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -463,7 +463,7 @@ public struct ConfigurationElement Void = { _ in }) { + postprocessor: @escaping (inout T) -> Void = { _ in }) { // swiftlint:disable:this no_empty_block self.init( wrappedValue: value, key: key, @@ -511,7 +511,7 @@ public struct ConfigurationElement Void = { _ in }) { + postprocessor: @escaping (inout T) -> Void = { _ in }) { // swiftlint:disable:this no_empty_block self.wrappedValue = wrappedValue self.key = key self.inline = inline diff --git a/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift index 39168dfd30..851f358587 100644 --- a/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift @@ -18,7 +18,7 @@ final class NoEmptyBlockConfigurationTests: SwiftLintTestCase { ] as [String: any Sendable] ) XCTAssertEqual(config.severityConfiguration.severity, .error) - XCTAssertEqual(config.enabledBlockTypes, Set([.initializerBodies, .statementBlocks])) + XCTAssertEqual(config.enabledBlockTypes, Set([.initializerBodies, .statementBlocks, .closureBlocks])) } func testInvalidKeyInCustomConfiguration() { From f3bdd27626f4af93a0c2a313e9306f40ce971bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 21 Aug 2024 18:56:51 +0200 Subject: [PATCH 175/265] Silence `unneeded_override` rule on methods and initializers with attributes (#5764) --- CHANGELOG.md | 4 ++++ .../Rules/Lint/UnneededOverrideRule.swift | 4 ++-- .../Rules/Lint/UnneededOverrideRuleExamples.swift | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2639c4c57..e1381e8fce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,10 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5762](https://github.com/realm/SwiftLint/issues/5762) +* Silence `unneeded_override` rule on methods and initializers with attributes. + [SimplyDanny](https://github.com/SimplyDanny) + [#5753](https://github.com/realm/SwiftLint/issues/5753) + ## 0.56.1: Heat Pump Dryer #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift index 58ef48cf16..3a00e4e22f 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRule.swift @@ -89,8 +89,8 @@ private extension OverridableDecl { return false } - // Assume having @available changes behavior. - if attributes.contains(attributeNamed: "available") { + // Assume attributes change behavior. + guard attributes.isEmpty else { return false } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift index 1109108422..87f0e94947 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnneededOverrideRuleExamples.swift @@ -17,6 +17,13 @@ struct UnneededOverrideRuleExamples { } """), Example(""" + class Foo { + @objc override func bar() { + super.bar() + } + } + """), + Example(""" class Foo { override func bar() { super.bar() From c8a9065428166b9f968ebe7062b7fc2976c1892f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 21 Aug 2024 19:07:39 +0200 Subject: [PATCH 176/265] Silence `prefer_key_path` rule on macro expansion expressions (#5765) --- CHANGELOG.md | 4 ++++ .../Rules/Idiomatic/PreferKeyPathRule.swift | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1381e8fce..853a4778de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5153](https://github.com/realm/SwiftLint/issues/5153) +* Silence `prefer_key_path` rule on macro expansion expressions. + [SimplyDanny](https://github.com/SimplyDanny) + [#5744](https://github.com/realm/SwiftLint/issues/5744) + * Check `if` expressions nested arbitrarily deep in `contrasted_opening_brace` rule. [SimplyDanny](https://github.com/SimplyDanny) [#5752](https://github.com/realm/SwiftLint/issues/5752) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift index d996119a65..127564620d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift @@ -29,6 +29,7 @@ struct PreferKeyPathRule: OptInRule { Example("[1, 2, 3].reduce(1) { $0 + $1 }", configuration: extendedMode), Example("f.map(1) { $0.a }"), Example("f.filter({ $0.a }, x)"), + Example("#Predicate { $0.a }"), ], triggeringExamples: [ Example("f.map ↓{ $0.a }"), @@ -174,10 +175,9 @@ private extension ClosureExprSyntax { } func isInvalid(restrictToStandardFunctions: Bool) -> Bool { - if keyPathInParent == \FunctionCallExprSyntax.calledExpression { - return true - } - if parent?.is(MultipleTrailingClosureElementSyntax.self) == true { + guard keyPathInParent != \FunctionCallExprSyntax.calledExpression, + let parentKind = parent?.kind, + ![.macroExpansionExpr, .multipleTrailingClosureElement].contains(parentKind) else { return true } if let call = parent?.as(LabeledExprSyntax.self)?.parent?.parent?.as(FunctionCallExprSyntax.self) { From a24488f26e60247d8fff7bbb03d51910af3dc91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 22 Aug 2024 13:20:18 +0200 Subject: [PATCH 177/265] Release 0.56.2 --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 853a4778de..9c4244e0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Main +## 0.56.2: Heat Pump Dryer #### Breaking diff --git a/MODULE.bazel b/MODULE.bazel index c1055f246d..0ce621122c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "swiftlint", - version = "0.56.1", + version = "0.56.2", compatibility_level = 1, repo_name = "SwiftLint", ) diff --git a/Package.swift b/Package.swift index 34fec6bfef..22207c767e 100644 --- a/Package.swift +++ b/Package.swift @@ -172,8 +172,8 @@ let package = Package( package.targets.append( .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.56.1/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "146ef723e83d301b9f1ef647dc924a55dae293887e633618e76f8cb526292f0c" + url: "https://github.com/realm/SwiftLint/releases/download/0.56.2/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "197df93d7f5041d8cd46d6902a34ad57914efe1b5b50635995f3b9065f2c3ffd" ) ) #endif diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index 0edafff9d3..60cbe4057f 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -9,7 +9,7 @@ public struct Version: VersionComparable { } /// The current SwiftLint version. - public static let current = Self(value: "0.56.1") + public static let current = Self(value: "0.56.2") /// Public initializer. /// From fb8551f3a3866d52b7c9b6f7fb8303f71b4cfac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 22 Aug 2024 13:23:07 +0200 Subject: [PATCH 178/265] Add new changelog section --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c4244e0f1..32573e71ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Main + +#### Breaking + +* None. + +#### Experimental + +* None. + +#### Enhancements + +* None. + +#### Bug Fixes + +* None. + ## 0.56.2: Heat Pump Dryer #### Breaking From 7d539acac6ac0ae0dfd1a622ee93e730e07d2e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 22 Aug 2024 13:46:20 +0200 Subject: [PATCH 179/265] Add fixed releaser It should actually work without this config as long as the releaser is not a bot. However, the BCR publishing step wasn't triggered. So perhaps this config is required ... We'll see in the next round. --- .bcr/config.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .bcr/config.yml diff --git a/.bcr/config.yml b/.bcr/config.yml new file mode 100644 index 0000000000..c35c48cf09 --- /dev/null +++ b/.bcr/config.yml @@ -0,0 +1,3 @@ +fixedReleaser: + login: SimplyDanny + email: danny.moesch@icloud.com From 13315081ae2fcb8fc37c09c2464e1148cb9526d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:18:32 -0400 Subject: [PATCH 180/265] Bump rexml from 3.3.3 to 3.3.6 (#5767) Bumps the bundler group with 1 update in the / directory: [rexml](https://github.com/ruby/rexml). Updates `rexml` from 3.3.3 to 3.3.6 - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.3...v3.3.6) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect dependency-group: bundler ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index f09505a870..5e6967364c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -122,7 +122,7 @@ GEM public_suffix (4.0.7) rchardet (1.8.0) redcarpet (3.6.0) - rexml (3.3.3) + rexml (3.3.6) strscan rouge (4.3.0) ruby-macho (2.5.1) From 9f4cb9240bb516b3589f3f0aa576230cad0c3320 Mon Sep 17 00:00:00 2001 From: ikelax <163678144+ikelax@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:48:38 +0200 Subject: [PATCH 181/265] Swift type checking using is (#5561) --- CHANGELOG.md | 5 ++ .../Models/BuiltInRules.swift | 1 + .../Idiomatic/PreferTypeCheckingRule.swift | 87 +++++++++++++++++++ Tests/GeneratedTests/GeneratedTests.swift | 6 ++ .../default_rule_configurations.yml | 2 + 5 files changed, 101 insertions(+) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 32573e71ab..928ff5cfba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -475,6 +475,11 @@ `let s: String = ""` as redundant. [Garric Nahapetian](https://github.com/garricn) +* Add new `prefer_type_checking` rule to prefer `a is X` over `a as? X != nil`. + [ikelax](https://github.com/ikelax) + [mildm8nnered](https://github.com/mildm8nnered) + [#5295](https://github.com/realm/SwiftLint/issues/5295) + #### Bug Fixes * Invalid keys in a configuration don't lead to the default configuration being diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 86105239e6..06613a00ad 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -152,6 +152,7 @@ public let builtInRules: [any Rule.Type] = [ PreferNimbleRule.self, PreferSelfInStaticReferencesRule.self, PreferSelfTypeOverTypeOfSelfRule.self, + PreferTypeCheckingRule.self, PreferZeroOverExplicitInitRule.self, PrefixedTopLevelConstantRule.self, PrivateActionRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift new file mode 100644 index 0000000000..c0ae6731d7 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift @@ -0,0 +1,87 @@ +import SwiftSyntax +import SwiftSyntaxBuilder + +@SwiftSyntaxRule(foldExpressions: true, explicitRewriter: true) +struct PreferTypeCheckingRule: Rule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "prefer_type_checking", + name: "Prefer Type Checking", + description: "Prefer `a is X` to `a as? X != nil`", + kind: .idiomatic, + nonTriggeringExamples: [ + Example("let foo = bar as? Foo"), + Example("bar is Foo"), + Example("2*x is X"), + Example(""" + if foo is Bar { + doSomeThing() + } + """), + Example(""" + if let bar = foo as? Bar { + foo.run() + } + """), + ], + triggeringExamples: [ + Example("bar ↓as? Foo != nil"), + Example("2*x as? X != nil"), + Example(""" + if foo ↓as? Bar != nil { + doSomeThing() + } + """), + ], + corrections: [ + Example("bar ↓as? Foo != nil"): Example("bar is Foo"), + Example("2*x ↓as? X != nil"): Example("2*x is X"), + Example(""" + if foo ↓as? Bar != nil { + doSomeThing() + } + """): Example(""" + if foo is Bar { + doSomeThing() + } + """), + ] + ) +} + +private extension PreferTypeCheckingRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: InfixOperatorExprSyntax) { + if node.typeChecksWithAsCasting, let asExpr = node.leftOperand.as(AsExprSyntax.self) { + violations.append(asExpr.asKeyword.positionAfterSkippingLeadingTrivia) + } + } + } + + final class Rewriter: ViolationsSyntaxRewriter { + override func visit(_ node: InfixOperatorExprSyntax) -> ExprSyntax { + guard node.typeChecksWithAsCasting, + let asExpr = node.leftOperand.as(AsExprSyntax.self) else { + return super.visit(node) + } + + correctionPositions.append(asExpr.asKeyword.positionAfterSkippingLeadingTrivia) + + let expression = asExpr.expression.trimmed + let type = asExpr.type.trimmed + + return ExprSyntax(stringLiteral: "\(expression) is \(type)") + .with(\.leadingTrivia, node.leadingTrivia) + .with(\.trailingTrivia, node.trailingTrivia) + } + } +} + +private extension InfixOperatorExprSyntax { + var typeChecksWithAsCasting: Bool { + self.leftOperand.is(AsExprSyntax.self) + && self.operator.as(BinaryOperatorExprSyntax.self)?.operator.tokenKind == .binaryOperator("!=") + && self.rightOperand.is(NilLiteralExprSyntax.self) + } +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 2c212346f3..d46eff77b4 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -901,6 +901,12 @@ final class PreferSelfTypeOverTypeOfSelfRuleGeneratedTests: SwiftLintTestCase { } } +final class PreferTypeCheckingRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(PreferTypeCheckingRule.description) + } +} + final class PreferZeroOverExplicitInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PreferZeroOverExplicitInitRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 3edd735e5a..0c75d9ac43 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -408,6 +408,8 @@ prefer_self_in_static_references: severity: warning prefer_self_type_over_type_of_self: severity: warning +prefer_type_checking: + severity: warning prefer_zero_over_explicit_init: severity: warning prefixed_toplevel_constant: From 60a1d342f43808a9d669cd53706688f9d717b970 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 24 Aug 2024 09:51:04 +0100 Subject: [PATCH 182/265] Remove `anyobject_protocol` rule (#5770) --- .swiftlint.yml | 1 - CHANGELOG.md | 4 +- .../Models/BuiltInRules.swift | 1 - .../Rules/Lint/AnyObjectProtocolRule.swift | 77 ------------------- Tests/GeneratedTests/GeneratedTests.swift | 6 -- .../default_rule_configurations.yml | 2 - 6 files changed, 3 insertions(+), 88 deletions(-) delete mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 05b56bc77a..8dc4c564ed 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -15,7 +15,6 @@ opt_in_rules: - all disabled_rules: - anonymous_argument_in_multiline_closure - - anyobject_protocol - conditional_returns_on_newline - contrasted_opening_brace - convenience_type diff --git a/CHANGELOG.md b/CHANGELOG.md index 928ff5cfba..e42e2ca5f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ #### Breaking -* None. +* The deprecated `anyobject_protocol` rule has now been removed. + [Martin Redington](https://github.com/mildm8nnered) + [#5769](https://github.com/realm/SwiftLint/issues/5769) #### Experimental diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 06613a00ad..73f981ab41 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -6,7 +6,6 @@ public let builtInRules: [any Rule.Type] = [ AccessibilityLabelForImageRule.self, AccessibilityTraitForButtonRule.self, AnonymousArgumentInMultilineClosureRule.self, - AnyObjectProtocolRule.self, ArrayInitRule.self, AttributesRule.self, BalancedXCTestLifecycleRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift deleted file mode 100644 index 3d8ded4ae5..0000000000 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/AnyObjectProtocolRule.swift +++ /dev/null @@ -1,77 +0,0 @@ -import SwiftSyntax - -// TODO: [09/07/2024] Remove deprecation warning after ~2 years. -private let warnDeprecatedOnceImpl: Void = { - Issue.ruleDeprecated(ruleID: AnyObjectProtocolRule.description.identifier).print() -}() - -private func warnDeprecatedOnce() { - _ = warnDeprecatedOnceImpl -} - -struct AnyObjectProtocolRule: SwiftSyntaxCorrectableRule, OptInRule { - var configuration = SeverityConfiguration(.warning) - - static let description = RuleDescription( - identifier: "anyobject_protocol", - name: "AnyObject Protocol", - description: "Prefer using `AnyObject` over `class` for class-only protocols", - kind: .lint, - nonTriggeringExamples: [ - Example("protocol SomeProtocol {}"), - Example("protocol SomeClassOnlyProtocol: AnyObject {}"), - Example("protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), - Example("@objc protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), - ], - triggeringExamples: [ - Example("protocol SomeClassOnlyProtocol: ↓class {}"), - Example("protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"), - Example("@objc protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"), - ], - corrections: [ - Example("protocol SomeClassOnlyProtocol: ↓class {}"): - Example("protocol SomeClassOnlyProtocol: AnyObject {}"), - Example("protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"): - Example("protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), - Example("@objc protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}"): - Example("@objc protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}"), - ] - ) - - func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor { - warnDeprecatedOnce() - return Visitor(configuration: configuration, file: file) - } - - func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? { - Rewriter(configuration: configuration, file: file) - } -} - -private extension AnyObjectProtocolRule { - final class Visitor: ViolationsSyntaxVisitor { - override func visitPost(_ node: ClassRestrictionTypeSyntax) { - violations.append(node.positionAfterSkippingLeadingTrivia) - } - } - - final class Rewriter: ViolationsSyntaxRewriter { - override func visit(_ node: InheritedTypeSyntax) -> InheritedTypeSyntax { - let typeName = node.type - guard typeName.is(ClassRestrictionTypeSyntax.self) else { - return super.visit(node) - } - correctionPositions.append(node.positionAfterSkippingLeadingTrivia) - return super.visit( - node.with( - \.type, - TypeSyntax( - IdentifierTypeSyntax(name: .identifier("AnyObject"), genericArgumentClause: nil) - .with(\.leadingTrivia, typeName.leadingTrivia) - .with(\.trailingTrivia, typeName.trailingTrivia) - ) - ) - ) - } - } -} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index d46eff77b4..1b506913c1 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -25,12 +25,6 @@ final class AnonymousArgumentInMultilineClosureRuleGeneratedTests: SwiftLintTest } } -final class AnyObjectProtocolRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(AnyObjectProtocolRule.description) - } -} - final class ArrayInitRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ArrayInitRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 0c75d9ac43..969ca71aa8 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -4,8 +4,6 @@ accessibility_trait_for_button: severity: warning anonymous_argument_in_multiline_closure: severity: warning -anyobject_protocol: - severity: warning array_init: severity: warning attributes: From 3bb80147822850fb82f0044fa6512ab729720106 Mon Sep 17 00:00:00 2001 From: Leonardo de Sousa Rodrigues <63623604+leonardosrodrigues0@users.noreply.github.com> Date: Sat, 24 Aug 2024 19:44:33 +1000 Subject: [PATCH 183/265] Add options to `opening_brace` rule that silence it on multiline statements and types (#5521) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 7 +- .../OpeningBraceConfiguration.swift | 14 +- .../Rules/Style/OpeningBraceRule.swift | 112 +++++++++++++-- .../default_rule_configurations.yml | 3 + .../OpeningBraceRuleTests.swift | 132 ++++++++++++++++-- 5 files changed, 241 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e42e2ca5f3..72f6c71a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,12 @@ #### Enhancements -* None. +* Add `ignore_multiline_type_headers` and `ignore_multiline_statement_conditions` + options to `opening_brace` rule to allow opening braces to be on a new line after + multiline type headers or statement conditions. Rename `allow_multiline_func` to + `ignore_multiline_function_signatures`. + [leonardosrodrigues0](https://github.com/leonardosrodrigues0) + [#3720](https://github.com/realm/SwiftLint/issues/3720) #### Bug Fixes diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift index 1e72688009..a136f1d300 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift @@ -6,6 +6,18 @@ struct OpeningBraceConfiguration: SeverityBasedRuleConfiguration { @ConfigurationElement(key: "severity") private(set) var severityConfiguration = SeverityConfiguration(.warning) - @ConfigurationElement(key: "allow_multiline_func") + @ConfigurationElement(key: "ignore_multiline_type_headers") + private(set) var ignoreMultilineTypeHeaders = false + @ConfigurationElement(key: "ignore_multiline_statement_conditions") + private(set) var ignoreMultilineStatementConditions = false + @ConfigurationElement(key: "ignore_multiline_function_signatures") + private(set) var ignoreMultilineFunctionSignatures = false + // TODO: [08/23/2026] Remove deprecation warning after ~2 years. + @ConfigurationElement(key: "allow_multiline_func", deprecationNotice: .suggestAlternative( + ruleID: Parent.identifier, name: "ignore_multiline_function_signatures")) private(set) var allowMultilineFunc = false + + var shouldIgnoreMultilineFunctionSignatures: Bool { + ignoreMultilineFunctionSignatures || allowMultilineFunc + } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index 3dbbaeb9ef..4e3e46b864 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -25,31 +25,123 @@ struct OpeningBraceRule: SwiftSyntaxCorrectableRule { private extension OpeningBraceRule { final class Visitor: CodeBlockVisitor { - override func visitPost(_ node: FunctionDeclSyntax) { - guard let body = node.body else { + // MARK: - Type Declarations + + override func visitPost(_ node: ActorDeclSyntax) { + if configuration.ignoreMultilineTypeHeaders, + hasMultilinePredecessors(node.memberBlock, keyword: node.actorKeyword) { return } - if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.funcKeyword) { + + super.visitPost(node) + } + + override func visitPost(_ node: ClassDeclSyntax) { + if configuration.ignoreMultilineTypeHeaders, + hasMultilinePredecessors(node.memberBlock, keyword: node.classKeyword) { return } - collectViolations(for: body) + + super.visitPost(node) } - override func visitPost(_ node: InitializerDeclSyntax) { - guard let body = node.body else { + override func visitPost(_ node: EnumDeclSyntax) { + if configuration.ignoreMultilineTypeHeaders, + hasMultilinePredecessors(node.memberBlock, keyword: node.enumKeyword) { + return + } + + super.visitPost(node) + } + + override func visitPost(_ node: ExtensionDeclSyntax) { + if configuration.ignoreMultilineTypeHeaders, + hasMultilinePredecessors(node.memberBlock, keyword: node.extensionKeyword) { + return + } + + super.visitPost(node) + } + + override func visitPost(_ node: ProtocolDeclSyntax) { + if configuration.ignoreMultilineTypeHeaders, + hasMultilinePredecessors(node.memberBlock, keyword: node.protocolKeyword) { return } - if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.initKeyword) { + + super.visitPost(node) + } + + override func visitPost(_ node: StructDeclSyntax) { + if configuration.ignoreMultilineTypeHeaders, + hasMultilinePredecessors(node.memberBlock, keyword: node.structKeyword) { return } - collectViolations(for: body) + + super.visitPost(node) } - private func refersToMultilineFunction(_ body: CodeBlockSyntax, functionIndicator: TokenSyntax) -> Bool { + // MARK: - Conditional Statements + + override func visitPost(_ node: ForStmtSyntax) { + if configuration.ignoreMultilineStatementConditions, + hasMultilinePredecessors(node.body, keyword: node.forKeyword) { + return + } + + super.visitPost(node) + } + + override func visitPost(_ node: IfExprSyntax) { + if configuration.ignoreMultilineStatementConditions, + hasMultilinePredecessors(node.body, keyword: node.ifKeyword) { + return + } + + super.visitPost(node) + } + + override func visitPost(_ node: WhileStmtSyntax) { + if configuration.ignoreMultilineStatementConditions, + hasMultilinePredecessors(node.body, keyword: node.whileKeyword) { + return + } + + super.visitPost(node) + } + + // MARK: - Functions and Initializers + + override func visitPost(_ node: FunctionDeclSyntax) { + if let body = node.body, + configuration.shouldIgnoreMultilineFunctionSignatures, + hasMultilinePredecessors(body, keyword: node.funcKeyword) { + return + } + + super.visitPost(node) + } + + override func visitPost(_ node: InitializerDeclSyntax) { + if let body = node.body, + configuration.shouldIgnoreMultilineFunctionSignatures, + hasMultilinePredecessors(body, keyword: node.initKeyword) { + return + } + + super.visitPost(node) + } + + // MARK: - Other Methods + + /// Checks if a `BracedSyntax` has a multiline predecessor. + /// For type declarations, the predecessor is the header. For conditional statements, + /// it is the condition list, and for functions, it is the signature. + private func hasMultilinePredecessors(_ body: some BracedSyntax, keyword: TokenSyntax) -> Bool { guard let endToken = body.previousToken(viewMode: .sourceAccurate) else { return false } - let startLocation = functionIndicator.endLocation(converter: locationConverter) + let startLocation = keyword.endLocation(converter: locationConverter) let endLocation = endToken.endLocation(converter: locationConverter) let braceLocation = body.leftBrace.endLocation(converter: locationConverter) return startLocation.line != endLocation.line && endLocation.line != braceLocation.line diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 969ca71aa8..386bb8a6c0 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -375,6 +375,9 @@ one_declaration_per_file: severity: warning opening_brace: severity: warning + ignore_multiline_type_headers: false + ignore_multiline_statement_conditions: false + ignore_multiline_function_signatures: false allow_multiline_func: false operator_usage_whitespace: severity: warning diff --git a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift index afbf8cf29c..445b2afd44 100644 --- a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift @@ -1,25 +1,120 @@ @testable import SwiftLintBuiltInRules final class OpeningBraceRuleTests: SwiftLintTestCase { - func testDefaultExamplesRunInMultilineMode() { + func testDefaultNonTriggeringExamplesWithMultilineOptionsTrue() { let description = OpeningBraceRule.description - .with(triggeringExamples: OpeningBraceRule.description.triggeringExamples.removing([ - Example("func abc(a: A,\n\tb: B)\n↓{"), - Example(""" - internal static func getPointer() - -> UnsafeMutablePointer<_ThreadLocalStorage> - ↓{ - return _swift_stdlib_threadLocalStorageGet().assumingMemoryBound( - to: _ThreadLocalStorage.self) - } - """), - ])) + .with(triggeringExamples: []) + .with(corrections: [:]) + + verifyRule(description, ruleConfiguration: [ + "ignore_multiline_statement_conditions": true, + "ignore_multiline_type_headers": true, + "ignore_multiline_function_signatures": true, + ]) + } + + func testWithIgnoreMultilineTypeHeadersTrue() { + let nonTriggeringExamples = [ + Example(""" + extension A + where B: Equatable + {} + """), + Example(""" + struct S: Comparable, + Identifiable + { + init() {} + } + """), + ] + + let triggeringExamples = [ + Example(""" + struct S + ↓{} + """), + Example(""" + extension A where B: Equatable + ↓{ + + } + """), + Example(""" + class C + // with comments + ↓{} + """), + ] + + let description = OpeningBraceRule.description + .with(nonTriggeringExamples: nonTriggeringExamples) + .with(triggeringExamples: triggeringExamples) + .with(corrections: [:]) + + verifyRule(description, ruleConfiguration: ["ignore_multiline_type_headers": true]) + } + + func testWithIgnoreMultilineStatementConditionsTrue() { + let nonTriggeringExamples = [ + Example(""" + while + abc + {} + """), + Example(""" + if x { + + } else if + y, + z + { + + } + """), + Example(""" + if + condition1, + let var1 = var1 + {} + """), + ] + + let triggeringExamples = [ + Example(""" + if x + ↓{} + """), + Example(""" + if x { - verifyRule(description, ruleConfiguration: ["allow_multiline_func": true]) + } else if y, z + ↓{} + """), + Example(""" + if x { + + } else + ↓{} + """), + Example(""" + while abc + // comments + ↓{ + } + """), + ] + + let description = OpeningBraceRule.description + .with(nonTriggeringExamples: nonTriggeringExamples) + .with(triggeringExamples: triggeringExamples) + .with(corrections: [:]) + + verifyRule(description, ruleConfiguration: ["ignore_multiline_statement_conditions": true]) } // swiftlint:disable:next function_body_length - func testWithAllowMultilineTrue() { + func testWithIgnoreMultilineFunctionSignaturesTrue() { let nonTriggeringExamples = [ Example(""" func abc( @@ -80,6 +175,13 @@ final class OpeningBraceRuleTests: SwiftLintTestCase { } } """), + Example(""" + class C { + init(a: Int) + // with comments + ↓{} + } + """), ] let description = OpeningBraceRule.description @@ -87,7 +189,7 @@ final class OpeningBraceRuleTests: SwiftLintTestCase { .with(triggeringExamples: triggeringExamples) .with(corrections: [:]) - verifyRule(description, ruleConfiguration: ["allow_multiline_func": true]) + verifyRule(description, ruleConfiguration: ["ignore_multiline_function_signatures": true]) } } From 48aaca61f05669b0eee8152866ddf68c52c40643 Mon Sep 17 00:00:00 2001 From: Sam Rayner Date: Sat, 24 Aug 2024 11:13:04 +0100 Subject: [PATCH 184/265] Reverse Data -> String conversion rule (#5601) --- CHANGELOG.md | 13 ++++++++ .../Models/BuiltInRules.swift | 1 + .../NonOptionalStringDataConversionRule.swift | 19 +++-------- .../OptionalDataStringConversionRule.swift | 32 +++++++++++++++++++ .../Extensions/Configuration+Remote.swift | 2 +- .../RegexConfiguration.swift | 5 +-- .../Configuration+CommandLine.swift | 6 ++-- .../Helpers/LintableFilesVisitor.swift | 4 +-- .../Helpers/SwiftPMCompilationDB.swift | 2 +- Tests/GeneratedTests/GeneratedTests.swift | 6 ++++ Tests/IntegrationTests/IntegrationTests.swift | 4 +-- .../default_rule_configurations.yml | 2 ++ 12 files changed, 71 insertions(+), 25 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 72f6c71a63..32afe3b03d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ [Martin Redington](https://github.com/mildm8nnered) [#5769](https://github.com/realm/SwiftLint/issues/5769) +* Revert the part of the `non_optional_string_data_conversion` + rule that enforces non-failable conversions of `Data` to UTF-8 + `String`. This is due to the fact that the data to be converted + can be arbitrary and especially doesn't need to represent a valid + UTF-8-encoded string. + [Sam Rayner](https://github.com/samrayner) + [#5263](https://github.com/realm/SwiftLint/issues/5263) + #### Experimental * None. @@ -19,6 +27,11 @@ [leonardosrodrigues0](https://github.com/leonardosrodrigues0) [#3720](https://github.com/realm/SwiftLint/issues/3720) +* Add new `optional_data_string_conversion` rule to enforce + failable conversions of `Data` to UTF-8 `String`. + [Sam Rayner](https://github.com/samrayner) + [#5263](https://github.com/realm/SwiftLint/issues/5263) + #### Bug Fixes * None. diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 73f981ab41..121c9e6032 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -141,6 +141,7 @@ public let builtInRules: [any Rule.Type] = [ OpeningBraceRule.self, OperatorFunctionWhitespaceRule.self, OperatorUsageWhitespaceRule.self, + OptionalDataStringConversionRule.self, OptionalEnumCaseMatchingRule.self, OrphanedDocCommentRule.self, OverriddenSuperCallRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift index 2e83b87bde..5141717370 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/NonOptionalStringDataConversionRule.swift @@ -5,16 +5,14 @@ struct NonOptionalStringDataConversionRule: Rule { var configuration = SeverityConfiguration(.warning) static let description = RuleDescription( identifier: "non_optional_string_data_conversion", - name: "Non-Optional String <-> Data Conversion", - description: "Prefer using UTF-8 encoded strings when converting between `String` and `Data`", + name: "Non-optional String -> Data Conversion", + description: "Prefer non-optional `Data(_:)` initializer when converting `String` to `Data`", kind: .lint, nonTriggeringExamples: [ - Example("Data(\"foo\".utf8)"), - Example("String(decoding: data, as: UTF8.self)"), + Example("Data(\"foo\".utf8)") ], triggeringExamples: [ - Example("\"foo\".data(using: .utf8)"), - Example("String(data: data, encoding: .utf8)"), + Example("\"foo\".data(using: .utf8)") ] ) } @@ -31,15 +29,6 @@ private extension NonOptionalStringDataConversionRule { violations.append(node.positionAfterSkippingLeadingTrivia) } } - - override func visitPost(_ node: DeclReferenceExprSyntax) { - if node.baseName.text == "String", - let parent = node.parent?.as(FunctionCallExprSyntax.self), - parent.arguments.map({ $0.label?.text }) == ["data", "encoding"], - parent.arguments.last?.expression.as(MemberAccessExprSyntax.self)?.isUTF8 == true { - violations.append(node.positionAfterSkippingLeadingTrivia) - } - } } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift new file mode 100644 index 0000000000..a98b6dddf9 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift @@ -0,0 +1,32 @@ +import SwiftSyntax + +@SwiftSyntaxRule +struct OptionalDataStringConversionRule: Rule { + var configuration = SeverityConfiguration(.warning) + static let description = RuleDescription( + identifier: "optional_data_string_conversion", + name: "Optional Data -> String Conversion", + description: "Prefer failable `String(data:encoding:)` initializer when converting `Data` to `String`", + kind: .lint, + nonTriggeringExamples: [ + Example("String(data: data, encoding: .utf8)") + ], + triggeringExamples: [ + Example("String(decoding: data, as: UTF8.self)") + ] + ) +} + +private extension OptionalDataStringConversionRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: DeclReferenceExprSyntax) { + if node.baseName.text == "String", + let parent = node.parent?.as(FunctionCallExprSyntax.self), + let expr = parent.arguments.last?.expression.as(MemberAccessExprSyntax.self), + expr.base?.description == "UTF8", + expr.declName.baseName.description == "self" { + violations.append(node.positionAfterSkippingLeadingTrivia) + } + } + } +} diff --git a/Source/SwiftLintCore/Extensions/Configuration+Remote.swift b/Source/SwiftLintCore/Extensions/Configuration+Remote.swift index 3337ad1da0..e8eec05c86 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Remote.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Remote.swift @@ -94,7 +94,7 @@ internal extension Configuration.FileGraph.FilePath { guard taskResult.2 == nil, // No error (taskResult.1 as? HTTPURLResponse)?.statusCode == 200, - let configStr = (taskResult.0.flatMap { String(decoding: $0, as: UTF8.self) }) + let configStr = (taskResult.0.flatMap { String(data: $0, encoding: .utf8) }) else { return try handleWrongData( urlString: urlString, diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index e44c25a307..65b44876f6 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -37,8 +37,9 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, .map(\.rawValue).sorted(by: <).joined(separator: ","), severity.rawValue, ] - if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject) { - return String(decoding: jsonData, as: UTF8.self) + if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject), + let jsonString = String(data: jsonData, encoding: .utf8) { + return jsonString } queuedFatalError("Could not serialize regex configuration for cache") } diff --git a/Source/swiftlint/Extensions/Configuration+CommandLine.swift b/Source/swiftlint/Extensions/Configuration+CommandLine.swift index 84a7119374..6eb4eeb061 100644 --- a/Source/swiftlint/Extensions/Configuration+CommandLine.swift +++ b/Source/swiftlint/Extensions/Configuration+CommandLine.swift @@ -213,8 +213,10 @@ extension Configuration { fileprivate func getFiles(with visitor: LintableFilesVisitor) async throws -> [SwiftLintFile] { if visitor.useSTDIN { let stdinData = FileHandle.standardInput.readDataToEndOfFile() - let stdinString = String(decoding: stdinData, as: UTF8.self) - return [SwiftLintFile(contents: stdinString)] + if let stdinString = String(data: stdinData, encoding: .utf8) { + return [SwiftLintFile(contents: stdinString)] + } + throw SwiftLintError.usageError(description: "stdin isn't a UTF8-encoded string") } if visitor.useScriptInputFiles { let files = try scriptInputFiles() diff --git a/Source/swiftlint/Helpers/LintableFilesVisitor.swift b/Source/swiftlint/Helpers/LintableFilesVisitor.swift index c11d11688d..c200513478 100644 --- a/Source/swiftlint/Helpers/LintableFilesVisitor.swift +++ b/Source/swiftlint/Helpers/LintableFilesVisitor.swift @@ -187,8 +187,8 @@ struct LintableFilesVisitor { } private static func loadLogCompilerInvocations(_ path: String) -> [[String]]? { - if let data = FileManager.default.contents(atPath: path) { - let logContents = String(decoding: data, as: UTF8.self) + if let data = FileManager.default.contents(atPath: path), + let logContents = String(data: data, encoding: .utf8) { if logContents.isEmpty { return nil } diff --git a/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift b/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift index 238985f167..d651290d48 100644 --- a/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift +++ b/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift @@ -37,7 +37,7 @@ struct SwiftPMCompilationDB: Codable { let pathToReplace = Array(nodes.nodes.keys.filter({ node in node.hasSuffix(suffix) }))[0].dropLast(suffix.count - 1) - let stringFileContents = String(decoding: yaml, as: UTF8.self) + let stringFileContents = String(data: yaml, encoding: .utf8)! .replacingOccurrences(of: pathToReplace, with: "") compilationDB = try decoder.decode(Self.self, from: stringFileContents) } else { diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 1b506913c1..332102c95f 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -835,6 +835,12 @@ final class OperatorUsageWhitespaceRuleGeneratedTests: SwiftLintTestCase { } } +final class OptionalDataStringConversionRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(OptionalDataStringConversionRule.description) + } +} + final class OptionalEnumCaseMatchingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(OptionalEnumCaseMatchingRule.description) diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index a4e345af7f..bbb8318ee9 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -190,8 +190,8 @@ private func execute(_ args: [String], queue.async(group: group) { stderrData = stderrPipe.fileHandleForReading.readDataToEndOfFile() } process.waitUntilExit() group.wait() - let stdout = stdoutData.map { String(decoding: $0, as: UTF8.self) } ?? "" - let stderr = stderrData.map { String(decoding: $0, as: UTF8.self) } ?? "" + let stdout = stdoutData.flatMap { String(data: $0, encoding: .utf8) } ?? "" + let stderr = stderrData.flatMap { String(data: $0, encoding: .utf8) } ?? "" return (process.terminationStatus, stdout, stderr) } diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 386bb8a6c0..88e14517c1 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -386,6 +386,8 @@ operator_usage_whitespace: allowed_no_space_operators: ["...", "..<"] operator_whitespace: severity: warning +optional_data_string_conversion: + severity: warning optional_enum_case_matching: severity: warning orphaned_doc_comment: From dfd19bddc20538e4b151927556ea542c8fb021db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 25 Aug 2024 09:11:31 +0200 Subject: [PATCH 185/265] Update Bazel pre-submit steps This is the version of the file that was used to add 0.56.2 to BCR. --- .bcr/presubmit.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml index 80a746c9ad..0ca2eb510b 100644 --- a/.bcr/presubmit.yml +++ b/.bcr/presubmit.yml @@ -1,25 +1,26 @@ -shell_commands: &shell_commands -- "echo --- Downloading and extracting Swift $SWIFT_VERSION to $SWIFT_HOME" -- "mkdir $SWIFT_HOME" -- "curl https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2004/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu20.04.tar.gz | tar xvz --strip-components=1 -C $SWIFT_HOME" - tasks: verify_targets_linux: - name: Verify targets (Linux) + name: Verify Targets (Linux) platform: ubuntu2004 + bazel: 7.x environment: CC: "clang" SWIFT_VERSION: "5.10" SWIFT_HOME: "$HOME/swift-$SWIFT_VERSION" PATH: "$PATH:$SWIFT_HOME/usr/bin" - shell_commands: *shell_commands + shell_commands: + - "echo --- Downloading and extracting Swift $SWIFT_VERSION to $SWIFT_HOME" + - "mkdir $SWIFT_HOME" + - "curl https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2004/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu20.04.tar.gz | tar xvz --strip-components=1 -C $SWIFT_HOME" build_flags: - "--action_env=PATH" build_targets: - # TODO: Build `:swiftlint` target when the Swift compiler crash is fixed - - '@swiftlint//:SwiftLintFramework' + - '@swiftlint//:swiftlint' verify_targets_macos: - name: Verify targets (macOS) + name: Verify Targets (macOS) platform: macos + bazel: 7.x build_targets: - '@swiftlint//:swiftlint' + build_flags: + - "--repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1" From 94d4f7acf9968014679bfe06ce0448823141b4af Mon Sep 17 00:00:00 2001 From: Hui Xu Date: Fri, 30 Aug 2024 23:25:30 -0700 Subject: [PATCH 186/265] Add instructions for installation in Chinese (#5777) --- README_CN.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README_CN.md b/README_CN.md index 4b622bbbb6..a1593f6e51 100644 --- a/README_CN.md +++ b/README_CN.md @@ -13,6 +13,33 @@ SwiftLint Hook 了 [Clang](http://clang.llvm.org) 和 [SourceKit](http://www.jps 不可接受的行为报告给 [info@realm.io](mailto:info@realm.io)。 ## 安装 +### 使用[Swift Package Manager](https://github.com/apple/swift-package-manager) + +SwiftLint 可以用作[命令插件](#swift-package-command-plugin)或[构建工具插件](#build-tool-plugins) + +添加 + +```swift +.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", from: "") +``` + +到你的 `Package.swift` 文件中,以自动获取 SwiftLint 的最新版本,或者将依赖项固定到特定版本: + +```swift +.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", exact: "") +``` + +其中,用所需的最低版本或精确版本替换 ``。 + + +### [Xcode Package Dependency](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) + +使用以下链接将 SwiftLint 作为包依赖添加到 Xcode 项目中: + +```bash +https://github.com/SimplyDanny/SwiftLintPlugins +``` + ### 使用 [Homebrew](http://brew.sh/): From ae3f0c4df9d35b15131bfcabe86f3558101ef8f1 Mon Sep 17 00:00:00 2001 From: Aryaman Sharda Date: Fri, 6 Sep 2024 13:26:47 +0100 Subject: [PATCH 187/265] Add new `attribute_name_spacing` rule (#5669) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 6 + .../Models/BuiltInRules.swift | 1 + .../Style/AttributeNameSpacingRule.swift | 158 ++++++++++++++++++ Tests/GeneratedTests/GeneratedTests.swift | 6 + .../default_rule_configurations.yml | 2 + 5 files changed, 173 insertions(+) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Style/AttributeNameSpacingRule.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 32afe3b03d..65d7db8b24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,12 @@ #### Enhancements +* Add new `attribute_name_spacing` rule to enforce no trailing whitespace between + attribute names and parentheses, ensuring compatibility with Swift 6, where this spacing + causes compilation errors. + [aryamansharda](https://github.com/aryamansharda) + [#5667](https://github.com/realm/SwiftLint/issues/5667) + * Linting got up to 30% faster due to the praisworthy performance improvements done in the [SwiftSyntax](https://github.com/swiftlang/swift-syntax) library. diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index 121c9e6032..eeb3abce7c 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -7,6 +7,7 @@ public let builtInRules: [any Rule.Type] = [ AccessibilityTraitForButtonRule.self, AnonymousArgumentInMultilineClosureRule.self, ArrayInitRule.self, + AttributeNameSpacingRule.self, AttributesRule.self, BalancedXCTestLifecycleRule.self, BlanketDisableCommandRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/AttributeNameSpacingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/AttributeNameSpacingRule.swift new file mode 100644 index 0000000000..50ca9d4b92 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Style/AttributeNameSpacingRule.swift @@ -0,0 +1,158 @@ +import SwiftLintCore +import SwiftSyntax + +@SwiftSyntaxRule +struct AttributeNameSpacingRule: SwiftSyntaxCorrectableRule { + var configuration = SeverityConfiguration(.error) + + static let description = RuleDescription( + identifier: "attribute_name_spacing", + name: "Attribute Name Spacing", + description: """ + This rule prevents trailing spaces after attribute names, ensuring compatibility \ + with Swift 6 where a space between an attribute name and the opening parenthesis \ + results in a compilation error (e.g. `@MyPropertyWrapper ()`, `private (set)`). + """, + kind: .style, + nonTriggeringExamples: [ + Example("private(set) var foo: Bool = false"), + Example("fileprivate(set) var foo: Bool = false"), + Example("@MainActor class Foo {}"), + Example("func funcWithEscapingClosure(_ x: @escaping () -> Int) {}"), + Example("@available(*, deprecated)"), + Example("@MyPropertyWrapper(param: 2) "), + Example("nonisolated(unsafe) var _value: X?"), + Example("@testable import SwiftLintCore"), + Example("func func_type_attribute_with_space(x: @convention(c) () -> Int) {}"), + Example(""" + @propertyWrapper + struct MyPropertyWrapper { + var wrappedValue: Int = 1 + + init(param: Int) {} + } + """), + Example(""" + let closure2 = { @MainActor + (a: Int, b: Int) in + } + """), + ], + triggeringExamples: [ + Example("private ↓(set) var foo: Bool = false"), + Example("fileprivate ↓(set) var foo: Bool = false"), + Example("public ↓(set) var foo: Bool = false"), + Example(" public ↓(set) var foo: Bool = false"), + Example("@ ↓MainActor class Foo {}"), + Example("func funcWithEscapingClosure(_ x: @ ↓escaping () -> Int) {}"), + Example("func funcWithEscapingClosure(_ x: @escaping↓() -> Int) {}"), + Example("@available ↓(*, deprecated)"), + Example("@MyPropertyWrapper ↓(param: 2) "), + Example("nonisolated ↓(unsafe) var _value: X?"), + Example("@MyProperty ↓() class Foo {}"), + Example(""" + let closure1 = { @MainActor ↓(a, b) in + } + """), + ], + corrections: [ + Example("private↓ (set) var foo: Bool = false"): Example("private(set) var foo: Bool = false"), + Example("fileprivate↓ (set) var foo: Bool = false"): Example("fileprivate(set) var foo: Bool = false"), + Example("internal↓ (set) var foo: Bool = false"): Example("internal(set) var foo: Bool = false"), + Example("public↓ (set) var foo: Bool = false"): Example("public(set) var foo: Bool = false"), + Example("public↓ (set) var foo: Bool = false"): Example("public(set) var foo: Bool = false"), + Example("@↓ MainActor"): Example("@MainActor"), + Example("func test(_ x: @↓ escaping () -> Int) {}"): Example("func test(_ x: @escaping () -> Int) {}"), + Example("func test(_ x: @escaping↓() -> Int) {}"): Example("func test(_ x: @escaping () -> Int) {}"), + Example("@available↓ (*, deprecated)"): Example("@available(*, deprecated)"), + Example("@MyPropertyWrapper↓ (param: 2) "): Example("@MyPropertyWrapper(param: 2) "), + Example("nonisolated↓ (unsafe) var _value: X?"): Example("nonisolated(unsafe) var _value: X?"), + Example("@MyProperty↓ ()"): Example("@MyProperty()"), + Example(""" + let closure1 = { @MainActor↓ (a, b) in + } + """): Example(""" + let closure1 = { @MainActor(a, b) in + } + """), + ] + ) +} + +private extension AttributeNameSpacingRule { + final class Visitor: ViolationsSyntaxVisitor { + override func visitPost(_ node: DeclModifierSyntax) { + guard node.detail != nil, node.name.trailingTrivia.isNotEmpty else { + return + } + + addViolation( + startPosition: node.name.endPositionBeforeTrailingTrivia, + endPosition: node.name.endPosition, + replacement: "", + reason: "There must not be any space between access control modifier and scope" + ) + } + + override func visitPost(_ node: AttributeSyntax) { + // Check for trailing trivia after the '@' sign. Handles cases like `@ MainActor` / `@ escaping`. + if node.atSign.trailingTrivia.isNotEmpty { + addViolation( + startPosition: node.atSign.endPositionBeforeTrailingTrivia, + endPosition: node.atSign.endPosition, + replacement: "", + reason: "Attributes must not have trivia between `@` and the identifier" + ) + } + + let hasTrailingTrivia = node.attributeName.trailingTrivia.isNotEmpty + + // Handles cases like `@MyPropertyWrapper (param: 2)`. + if node.arguments != nil, hasTrailingTrivia { + addViolation( + startPosition: node.attributeName.endPositionBeforeTrailingTrivia, + endPosition: node.attributeName.endPosition, + replacement: "", + reason: "Attribute declarations with arguments must not have trailing trivia" + ) + } + + if !hasTrailingTrivia, node.isEscaping { + // Handles cases where escaping has the wrong spacing: `@escaping()` + addViolation( + startPosition: node.attributeName.endPositionBeforeTrailingTrivia, + endPosition: node.attributeName.endPosition, + replacement: " ", + reason: "`@escaping` must have a trailing space before the associated type" + ) + } + } + + private func addViolation( + startPosition: AbsolutePosition, + endPosition: AbsolutePosition, + replacement: String, + reason: String + ) { + let correction = ReasonedRuleViolation.ViolationCorrection( + start: startPosition, + end: endPosition, + replacement: replacement + ) + + let violation = ReasonedRuleViolation( + position: endPosition, + reason: reason, + severity: configuration.severity, + correction: correction + ) + violations.append(violation) + } + } +} + +private extension AttributeSyntax { + var isEscaping: Bool { + attributeNameText == "escaping" + } +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index 332102c95f..d00101a90b 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -31,6 +31,12 @@ final class ArrayInitRuleGeneratedTests: SwiftLintTestCase { } } +final class AttributeNameSpacingRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(AttributeNameSpacingRule.description) + } +} + final class AttributesRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(AttributesRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 88e14517c1..57148068b8 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -6,6 +6,8 @@ anonymous_argument_in_multiline_closure: severity: warning array_init: severity: warning +attribute_name_spacing: + severity: error attributes: severity: warning attributes_with_arguments_always_on_line_above: true From 27cab449acc9a7f4cb83f9ee854077a291a8d1bf Mon Sep 17 00:00:00 2001 From: Enric Enrich Date: Sat, 7 Sep 2024 14:49:42 +0200 Subject: [PATCH 188/265] Use `Diagnostics.error` when command failed (#5782) --- .../SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift index 3ff555170e..4fdcb6bbca 100644 --- a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift +++ b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift @@ -32,6 +32,7 @@ struct SwiftLintCommandPlugin: CommandPlugin { try process.run() process.waitUntilExit() + switch process.terminationReason { case .exit: Diagnostics.remark("Finished running in module '\(target.name)'") @@ -40,9 +41,12 @@ struct SwiftLintCommandPlugin: CommandPlugin { @unknown default: Diagnostics.error("Stopped running in module '\(target.name) due to unexpected termination reason") } + if process.terminationStatus != EXIT_SUCCESS { - Diagnostics.warning( - "Command found violations or unsuccessfully stopped running in module '\(target.name)'" + Diagnostics.error(""" + Command found error violations or unsuccessfully stopped running with \ + exit code \(process.terminationStatus) in module '\(target.name)' + """ ) } } From e8451638a0b2a4ab21adbda875aef7306182bfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 7 Sep 2024 16:59:58 +0200 Subject: [PATCH 189/265] Remove empty lines --- .github/workflows/docker.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1d996c4639..fc37c4292d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -10,36 +10,29 @@ on: jobs: build: runs-on: ubuntu-20.04 - steps: - uses: actions/checkout@v4 - - name: Extract DOCKER_TAG using tag name if: startsWith(github.ref, 'refs/tags/') run: | echo "DOCKER_TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV - - name: Use default DOCKER_TAG if: startsWith(github.ref, 'refs/tags/') != true run: | echo "DOCKER_TAG=latest" >> $GITHUB_ENV - - name: Set lowercase repository name run: | echo "REPOSITORY_LC=${REPOSITORY,,}" >>${GITHUB_ENV} env: REPOSITORY: '${{ github.repository }}' - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Login to GitHub registry - uses: docker/login-action@v3 + uses: docker/login-action@v3 with: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io - - uses: docker/build-push-action@v6 with: push: true From d601c22a173e9f7ab81d9d0d00a2506badb4db27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 7 Sep 2024 18:02:57 +0200 Subject: [PATCH 190/265] Auto-upload Linux build --- .github/workflows/docker-release.yml | 21 +++++++++++++++++++ .github/workflows/docker.yml | 30 +++++++++++++++------------- Releasing.md | 1 - 3 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/docker-release.yml diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml new file mode 100644 index 0000000000..981a5ad407 --- /dev/null +++ b/.github/workflows/docker-release.yml @@ -0,0 +1,21 @@ +name: Docker Release + +on: + release: + types: [released] + +jobs: + trigger-build: + uses: ./.github/workflows/docker.yml + with: + tag: ${{ github.event.release.tag_name }} + secrets: inherit + upload-docker: + needs: trigger-build + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - name: Upload binary to existing release + run: make zip_linux_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index fc37c4292d..062924bbeb 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,28 +1,30 @@ -name: docker +name: Docker Build on: push: branches: - main - tags: - - '*' + workflow_call: + inputs: + tag: + description: 'Docker tag' + required: true + type: string + default: 'latest' jobs: build: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 - - name: Extract DOCKER_TAG using tag name - if: startsWith(github.ref, 'refs/tags/') - run: | - echo "DOCKER_TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV - - name: Use default DOCKER_TAG - if: startsWith(github.ref, 'refs/tags/') != true - run: | - echo "DOCKER_TAG=latest" >> $GITHUB_ENV + - name: Set Docker tag + if: github.event_name == 'workflow_call' + run: echo "DOCKER_TAG=${{ inputs.tag }}" >> $GITHUB_ENV + - name: Use default Docker tag + if: github.event_name == 'push' + run: echo "DOCKER_TAG=latest" >> $GITHUB_ENV - name: Set lowercase repository name - run: | - echo "REPOSITORY_LC=${REPOSITORY,,}" >>${GITHUB_ENV} + run: echo "REPOSITORY_LC=${REPOSITORY,,}" >> $GITHUB_ENV env: REPOSITORY: '${{ github.repository }}' - name: Set up Docker Buildx @@ -31,7 +33,7 @@ jobs: uses: docker/login-action@v3 with: username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + password: ${{ secrets.GITHUB_TOKEN }} registry: ghcr.io - uses: docker/build-push-action@v6 with: diff --git a/Releasing.md b/Releasing.md index fe7520ad4b..93aa81683e 100644 --- a/Releasing.md +++ b/Releasing.md @@ -10,5 +10,4 @@ For SwiftLint contributors, follow these steps to cut a release: 1. Make sure you have the latest stable Xcode version installed and `xcode-select`ed 1. Release new version: `make release "0.2.0: Tumble Dry"` -1. Wait for the Docker CI job to finish then run: `make zip_linux_release` 1. Celebrate. :tada: From d136b02f218146ca43cfdcdec3f6df00ee56f0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 7 Sep 2024 18:03:15 +0200 Subject: [PATCH 191/265] Update release instructions --- Releasing.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Releasing.md b/Releasing.md index 93aa81683e..010f1ed2bf 100644 --- a/Releasing.md +++ b/Releasing.md @@ -7,7 +7,8 @@ For SwiftLint contributors, follow these steps to cut a release: * FabricSoftenerRule * Top Loading * Fresh Out Of The Dryer -1. Make sure you have the latest stable Xcode version installed and - `xcode-select`ed -1. Release new version: `make release "0.2.0: Tumble Dry"` +1. Make sure you have the latest stable Xcode version installed and `xcode-select`ed. +1. Make sure that the selected Xcode has the latest SDKs of all supported platforms installed. This is required to + build the CocoaPods release. +1. Release a new version by running `make release "0.2.0: Tumble Dry"`. 1. Celebrate. :tada: From 1dbe0957c6bdf49358d335819507913a121b2c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 7 Sep 2024 18:08:02 +0200 Subject: [PATCH 192/265] Move release instructions --- CONTRIBUTING.md | 15 +++++++++++++++ Releasing.md | 14 -------------- 2 files changed, 15 insertions(+), 14 deletions(-) delete mode 100644 Releasing.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a9f305a99..51d771aaa8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -158,6 +158,21 @@ We follow the same syntax as CocoaPods' CHANGELOG.md: you may instead link to the change's pull request. 1. All CHANGELOG.md content is hard-wrapped at 80 characters. +## Cutting a Release + +SwiftLint maintainers follow these steps to cut a release: + +1. Come up with a witty washer- or dryer-themed release name. Past names include: + * Tumble Dry + * FabricSoftenerRule + * Top Loading + * Fresh Out Of The Dryer +1. Make sure you have the latest stable Xcode version installed and `xcode-select`ed. +1. Make sure that the selected Xcode has the latest SDKs of all supported platforms installed. This is required to + build the CocoaPods release. +1. Release a new version by running `make release "0.2.0: Tumble Dry"`. +1. Celebrate. :tada: + ## CI SwiftLint uses Azure Pipelines for most of its CI jobs, primarily because diff --git a/Releasing.md b/Releasing.md deleted file mode 100644 index 010f1ed2bf..0000000000 --- a/Releasing.md +++ /dev/null @@ -1,14 +0,0 @@ -# Releasing SwiftLint - -For SwiftLint contributors, follow these steps to cut a release: - -1. Come up with a witty washer- or dryer-themed release name. Past names include: - * Tumble Dry - * FabricSoftenerRule - * Top Loading - * Fresh Out Of The Dryer -1. Make sure you have the latest stable Xcode version installed and `xcode-select`ed. -1. Make sure that the selected Xcode has the latest SDKs of all supported platforms installed. This is required to - build the CocoaPods release. -1. Release a new version by running `make release "0.2.0: Tumble Dry"`. -1. Celebrate. :tada: From 06e4e3cc0779f04154bc790ca5ce5c0e340e6a3e Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 7 Sep 2024 22:15:21 +0100 Subject: [PATCH 193/265] Fix `superfluous_disable_command` for `custom_rules` (#5670) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 7 +- .../Extensions/Configuration+RulesMode.swift | 3 +- .../Configuration+RulesWrapper.swift | 5 +- Source/SwiftLintCore/Models/Linter.swift | 77 +++-- Source/SwiftLintCore/Models/Region.swift | 4 + Source/SwiftLintCore/Protocols/Rule.swift | 34 ++ Source/SwiftLintCore/Rules/CustomRules.swift | 34 +- .../Rules/SuperfluousDisableCommandRule.swift | 4 +- .../CustomRulesTests.swift | 319 +++++++++++++++--- 9 files changed, 402 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d7db8b24..3dd8e064e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,12 @@ #### Bug Fixes -* None. +* `superfluous_disable_command` violations are now triggered for + custom rules. + [Marcelo Fabri](https://github.com/marcelofabri) + [Martin Redington](https://github.com/mildm8nnered) + [SimplyDanny](https://github.com/SimplyDanny) + [#4754](https://github.com/realm/SwiftLint/issues/4754) ## 0.56.2: Heat Pump Dryer diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift index f7d0e6b7ad..e03cadd0a2 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift @@ -112,8 +112,7 @@ public extension Configuration { switch self { case let .only(onlyRules) where onlyRules.contains { $0 == CustomRules.description.identifier }: let customRulesRule = (allRulesWrapped.first { $0.rule is CustomRules })?.rule as? CustomRules - let customRuleIdentifiers = customRulesRule?.configuration.customRuleConfigurations.map(\.identifier) - return .only(onlyRules.union(Set(customRuleIdentifiers ?? []))) + return .only(onlyRules.union(Set(customRulesRule?.customRuleIdentifiers ?? []))) default: return self diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift index 18cdfc42b6..e06a692a6f 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift @@ -13,8 +13,7 @@ internal extension Configuration { private var validRuleIdentifiers: Set { let regularRuleIdentifiers = allRulesWrapped.map { type(of: $0.rule).description.identifier } let configurationCustomRulesIdentifiers = - (allRulesWrapped.first { $0.rule is CustomRules }?.rule as? CustomRules)? - .configuration.customRuleConfigurations.map(\.identifier) ?? [] + (allRulesWrapped.first { $0.rule is CustomRules }?.rule as? CustomRules)?.customRuleIdentifiers ?? [] return Set(regularRuleIdentifiers + configurationCustomRulesIdentifiers) } @@ -247,7 +246,7 @@ internal extension Configuration { as? CustomRules { onlyRules = onlyRules.union( Set( - childCustomRulesRule.configuration.customRuleConfigurations.map(\.identifier) + childCustomRulesRule.customRuleIdentifiers ) ) } diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index c18ce0ad1a..23bfad7d54 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -16,47 +16,56 @@ private struct LintResult { } private extension Rule { - static func superfluousDisableCommandViolations(regions: [Region], - superfluousDisableCommandRule: SuperfluousDisableCommandRule?, - allViolations: [StyleViolation]) -> [StyleViolation] { + func superfluousDisableCommandViolations(regions: [Region], + superfluousDisableCommandRule: SuperfluousDisableCommandRule?, + allViolations: [StyleViolation]) -> [StyleViolation] { guard regions.isNotEmpty, let superfluousDisableCommandRule else { return [] } - let regionsDisablingCurrentRule = regions.filter { region in - region.isRuleDisabled(self.init()) - } let regionsDisablingSuperfluousDisableRule = regions.filter { region in region.isRuleDisabled(superfluousDisableCommandRule) } - return regionsDisablingCurrentRule.compactMap { region -> StyleViolation? in - let isSuperfluousRuleDisabled = regionsDisablingSuperfluousDisableRule.contains { - $0.contains(region.start) - } - - guard !isSuperfluousRuleDisabled else { - return nil + var superfluousDisableCommandViolations = [StyleViolation]() + for region in regions { + if regionsDisablingSuperfluousDisableRule.contains(where: { $0.contains(region.start) }) { + continue } - - let noViolationsInDisabledRegion = !allViolations.contains { violation in - region.contains(violation.location) + let sortedDisabledIdentifiers = region.disabledRuleIdentifiers.sorted { + $0.stringRepresentation < $1.stringRepresentation } - guard noViolationsInDisabledRegion else { - return nil + commandIDsLoop: for disabledIdentifier in sortedDisabledIdentifiers { + guard !isEnabled(in: region, for: disabledIdentifier.stringRepresentation) else { + continue + } + var disableCommandValid = false + for violation in allViolations where region.contains(violation.location) { + if canBeDisabled(violation: violation, by: disabledIdentifier) { + disableCommandValid = true + continue commandIDsLoop + } + } + if !disableCommandValid { + let reason = superfluousDisableCommandRule.reason( + forRuleIdentifier: disabledIdentifier.stringRepresentation + ) + superfluousDisableCommandViolations.append( + StyleViolation( + ruleDescription: type(of: superfluousDisableCommandRule).description, + severity: superfluousDisableCommandRule.configuration.severity, + location: region.start, + reason: reason + ) + ) + } } - - return StyleViolation( - ruleDescription: type(of: superfluousDisableCommandRule).description, - severity: superfluousDisableCommandRule.configuration.severity, - location: region.start, - reason: superfluousDisableCommandRule.reason(for: self) - ) } + return superfluousDisableCommandViolations } // As we need the configuration to get custom identifiers. - // swiftlint:disable:next function_parameter_count + // swiftlint:disable:next function_parameter_count function_body_length func lint(file: SwiftLintFile, regions: [Region], benchmark: Bool, @@ -93,16 +102,26 @@ private extension Rule { let (disabledViolationsAndRegions, enabledViolationsAndRegions) = violations.map { violation in (violation, regions.first { $0.contains(violation.location) }) - }.partitioned { _, region in - region?.isRuleEnabled(self) ?? true + }.partitioned { violation, region in + if let region { + return isEnabled(in: region, for: violation.ruleIdentifier) + } + return true } + let customRulesIDs: [String] = { + guard let customRules = self as? CustomRules else { + return [] + } + return customRules.customRuleIdentifiers + }() let ruleIDs = Self.description.allIdentifiers + + customRulesIDs + (superfluousDisableCommandRule.map({ type(of: $0) })?.description.allIdentifiers ?? []) + [RuleIdentifier.all.stringRepresentation] let ruleIdentifiers = Set(ruleIDs.map { RuleIdentifier($0) }) - let superfluousDisableCommandViolations = Self.superfluousDisableCommandViolations( + let superfluousDisableCommandViolations = superfluousDisableCommandViolations( regions: regions.count > 1 ? file.regions(restrictingRuleIdentifiers: ruleIdentifiers) : regions, superfluousDisableCommandRule: superfluousDisableCommandRule, allViolations: violations diff --git a/Source/SwiftLintCore/Models/Region.swift b/Source/SwiftLintCore/Models/Region.swift index ae2df0fcba..9c6483fbd9 100644 --- a/Source/SwiftLintCore/Models/Region.swift +++ b/Source/SwiftLintCore/Models/Region.swift @@ -44,6 +44,10 @@ public struct Region: Equatable { /// /// - parameter rule: The rule whose status should be determined. /// + /// - note: For CustomRules, this will only return true if the `custom_rules` identifier + /// is used with the `swiftlint` disable command, but this method is never + /// called for CustomRules. + /// /// - returns: True if the specified rule is disabled in this region. public func isRuleDisabled(_ rule: some Rule) -> Bool { areRulesDisabled(ruleIDs: type(of: rule).description.allIdentifiers) diff --git a/Source/SwiftLintCore/Protocols/Rule.swift b/Source/SwiftLintCore/Protocols/Rule.swift index d04f234e53..5e0214b678 100644 --- a/Source/SwiftLintCore/Protocols/Rule.swift +++ b/Source/SwiftLintCore/Protocols/Rule.swift @@ -70,6 +70,26 @@ public protocol Rule { /// /// - returns: All style violations to the rule's expectations. func validate(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [StyleViolation] + + /// Checks if a style violation can be disabled by a command specifying a rule ID. Only the rule can claim that for + /// sure since it knows all the possible identifiers. + /// + /// - Parameters: + /// - violation: A style violation. + /// - ruleID: The name of a rule as used in a disable command. + /// + /// - Returns: A boolean value indicating whether the violation can be disabled by the given ID. + func canBeDisabled(violation: StyleViolation, by ruleID: RuleIdentifier) -> Bool + + /// Checks if a the rule is enabled in a given region. A specific rule ID can be provided in case a rule supports + /// more than one identifier. + /// + /// - Parameters: + /// - region: The region to check. + /// - ruleID: Rule identifier deviating from the default rule's name. + /// + /// - Returns: A boolean value indicating whether the rule is enabled in the given region. + func isEnabled(in region: Region, for ruleID: String) -> Bool } public extension Rule { @@ -110,6 +130,20 @@ public extension Rule { func createConfigurationDescription(exclusiveOptions: Set = []) -> RuleConfigurationDescription { RuleConfigurationDescription.from(configuration: configuration, exclusiveOptions: exclusiveOptions) } + + func canBeDisabled(violation: StyleViolation, by ruleID: RuleIdentifier) -> Bool { + switch ruleID { + case .all: + true + case let .single(identifier: id): + Self.description.allIdentifiers.contains(id) + && Self.description.allIdentifiers.contains(violation.ruleIdentifier) + } + } + + func isEnabled(in region: Region, for ruleID: String) -> Bool { + !Self.description.allIdentifiers.contains(ruleID) || region.isRuleEnabled(self) + } } public extension Rule { diff --git a/Source/SwiftLintCore/Rules/CustomRules.swift b/Source/SwiftLintCore/Rules/CustomRules.swift index c43e191f5e..e523c757a7 100644 --- a/Source/SwiftLintCore/Rules/CustomRules.swift +++ b/Source/SwiftLintCore/Rules/CustomRules.swift @@ -41,6 +41,10 @@ struct CustomRules: Rule, CacheDescriptionProvider { configuration.cacheDescription } + var customRuleIdentifiers: [String] { + configuration.customRuleConfigurations.map(\.identifier) + } + static let description = RuleDescription( identifier: "custom_rules", name: "Custom Rules", @@ -79,19 +83,29 @@ struct CustomRules: Rule, CacheDescriptionProvider { severity: configuration.severity, location: Location(file: file, characterOffset: $0.location), reason: configuration.message) - }).filter { violation in - guard let region = file.regions().first(where: { $0.contains(violation.location) }) else { - return true - } + }) + } + } - return !region.isRuleDisabled(customRuleIdentifier: configuration.identifier) - } + func canBeDisabled(violation: StyleViolation, by ruleID: RuleIdentifier) -> Bool { + switch ruleID { + case let .single(identifier: id): + id == Self.description.identifier + ? customRuleIdentifiers.contains(violation.ruleIdentifier) + : customRuleIdentifiers.contains(id) && violation.ruleIdentifier == id + default: + (self as any Rule).canBeDisabled(violation: violation, by: ruleID) } } -} -private extension Region { - func isRuleDisabled(customRuleIdentifier: String) -> Bool { - disabledRuleIdentifiers.contains(RuleIdentifier(customRuleIdentifier)) + func isEnabled(in region: Region, for ruleID: String) -> Bool { + if !Self.description.allIdentifiers.contains(ruleID), + !customRuleIdentifiers.contains(ruleID), + Self.description.identifier != ruleID { + return true + } + return !region.disabledRuleIdentifiers.contains(RuleIdentifier(Self.description.identifier)) + && !region.disabledRuleIdentifiers.contains(RuleIdentifier(ruleID)) + && !region.disabledRuleIdentifiers.contains(.all) } } diff --git a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift index 0551575d87..fab3ef0b5a 100644 --- a/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift +++ b/Source/SwiftLintCore/Rules/SuperfluousDisableCommandRule.swift @@ -34,9 +34,9 @@ package struct SuperfluousDisableCommandRule: SourceKitFreeRule { [] } - func reason(for rule: (some Rule).Type) -> String { + func reason(forRuleIdentifier ruleIdentifier: String) -> String { """ - SwiftLint rule '\(rule.description.identifier)' did not trigger a violation in the disabled region; \ + SwiftLint rule '\(ruleIdentifier)' did not trigger a violation in the disabled region; \ remove the disable command """ } diff --git a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift index 448886f60f..3337822047 100644 --- a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift @@ -2,8 +2,13 @@ import SourceKittenFramework @testable import SwiftLintCore import XCTest +// swiftlint:disable file_length +// swiftlint:disable:next type_body_length final class CustomRulesTests: SwiftLintTestCase { - typealias Configuration = RegexConfiguration + private typealias Configuration = RegexConfiguration + + private var testFile: SwiftLintFile { SwiftLintFile(path: "\(testResourcesPath)/test.txt")! } + func testCustomRuleConfigurationSetsCorrectlyWithMatchKinds() { let configDict = [ "my_custom_rule": [ @@ -122,10 +127,16 @@ final class CustomRulesTests: SwiftLintTestCase { ) } - func testLocalDisableCustomRule() { - let (_, customRules) = getCustomRules() - let file = SwiftLintFile(contents: "//swiftlint:disable custom \n// file with a pattern") - XCTAssertEqual(customRules.validate(file: file), []) + func testLocalDisableCustomRule() throws { + let customRules: [String: Any] = [ + "custom": [ + "regex": "pattern", + "match_kinds": "comment", + ], + ] + let example = Example("//swiftlint:disable custom \n// file with a pattern") + let violations = try violations(forExample: example, customRules: customRules) + XCTAssertTrue(violations.isEmpty) } func testLocalDisableCustomRuleWithMultipleRules() { @@ -147,7 +158,7 @@ final class CustomRulesTests: SwiftLintTestCase { func testCustomRulesIncludedDefault() { // Violation detected when included is omitted. let (_, customRules) = getCustomRules() - let violations = customRules.validate(file: getTestTextFile()) + let violations = customRules.validate(file: testFile) XCTAssertEqual(violations.count, 1) } @@ -158,8 +169,8 @@ final class CustomRulesTests: SwiftLintTestCase { customRuleConfiguration.customRuleConfigurations = [regexConfig] customRules.configuration = customRuleConfiguration - let violations = customRules.validate(file: getTestTextFile()) - XCTAssertEqual(violations.count, 0) + let violations = customRules.validate(file: testFile) + XCTAssertTrue(violations.isEmpty) } func testCustomRulesExcludedExcludesFile() { @@ -169,8 +180,8 @@ final class CustomRulesTests: SwiftLintTestCase { customRuleConfiguration.customRuleConfigurations = [regexConfig] customRules.configuration = customRuleConfiguration - let violations = customRules.validate(file: getTestTextFile()) - XCTAssertEqual(violations.count, 0) + let violations = customRules.validate(file: testFile) + XCTAssertTrue(violations.isEmpty) } func testCustomRulesExcludedArrayExcludesFile() { @@ -180,8 +191,8 @@ final class CustomRulesTests: SwiftLintTestCase { customRuleConfiguration.customRuleConfigurations = [regexConfig] customRules.configuration = customRuleConfiguration - let violations = customRules.validate(file: getTestTextFile()) - XCTAssertEqual(violations.count, 0) + let violations = customRules.validate(file: testFile) + XCTAssertTrue(violations.isEmpty) } func testCustomRulesCaptureGroup() { @@ -189,12 +200,235 @@ final class CustomRulesTests: SwiftLintTestCase { "regex": #"\ba\s+(\w+)"#, "capture_group": 1, ]) - let violations = customRules.validate(file: getTestTextFile()) + let violations = customRules.validate(file: testFile) XCTAssertEqual(violations.count, 1) XCTAssertEqual(violations[0].location.line, 2) XCTAssertEqual(violations[0].location.character, 6) } + // MARK: - superfluous_disable_command support + + func testCustomRulesTriggersSuperfluousDisableCommand() throws { + let customRuleIdentifier = "forbidden" + let customRules: [String: Any] = [ + customRuleIdentifier: [ + "regex": "FORBIDDEN", + ], + ] + let example = Example(""" + // swiftlint:disable:next custom_rules + let ALLOWED = 2 + """) + + let violations = try violations(forExample: example, customRules: customRules) + XCTAssertEqual(violations.count, 1) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "custom_rules")) + } + + func testSpecificCustomRuleTriggersSuperfluousDisableCommand() throws { + let customRuleIdentifier = "forbidden" + let customRules: [String: Any] = [ + customRuleIdentifier: [ + "regex": "FORBIDDEN", + ], + ] + + let example = Example(""" + // swiftlint:disable:next \(customRuleIdentifier) + let ALLOWED = 2 + """) + + let violations = try violations(forExample: example, customRules: customRules) + XCTAssertEqual(violations.count, 1) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: customRuleIdentifier)) + } + + func testSpecificAndCustomRulesTriggersSuperfluousDisableCommand() throws { + let customRuleIdentifier = "forbidden" + let customRules: [String: Any] = [ + customRuleIdentifier: [ + "regex": "FORBIDDEN", + ], + ] + + let example = Example(""" + // swiftlint:disable:next custom_rules \(customRuleIdentifier) + let ALLOWED = 2 + """) + + let violations = try violations(forExample: example, customRules: customRules) + + XCTAssertEqual(violations.count, 2) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "custom_rules")) + XCTAssertTrue(violations[1].isSuperfluousDisableCommandViolation(for: "\(customRuleIdentifier)")) + } + + func testCustomRulesViolationAndViolationOfSuperfluousDisableCommand() throws { + let customRuleIdentifier = "forbidden" + let customRules: [String: Any] = [ + customRuleIdentifier: [ + "regex": "FORBIDDEN", + ], + ] + + let example = Example(""" + let FORBIDDEN = 1 + // swiftlint:disable:next \(customRuleIdentifier) + let ALLOWED = 2 + """) + + let violations = try violations(forExample: example, customRules: customRules) + + XCTAssertEqual(violations.count, 2) + XCTAssertEqual(violations[0].ruleIdentifier, customRuleIdentifier) + XCTAssertTrue(violations[1].isSuperfluousDisableCommandViolation(for: customRuleIdentifier)) + } + + func testDisablingCustomRulesDoesNotTriggerSuperfluousDisableCommand() throws { + let customRules: [String: Any] = [ + "forbidden": [ + "regex": "FORBIDDEN", + ], + ] + + let example = Example(""" + // swiftlint:disable:next custom_rules + let FORBIDDEN = 1 + """) + + XCTAssertTrue(try violations(forExample: example, customRules: customRules).isEmpty) + } + + func testMultipleSpecificCustomRulesTriggersSuperfluousDisableCommand() throws { + let customRules = [ + "forbidden": [ + "regex": "FORBIDDEN", + ], + "forbidden2": [ + "regex": "FORBIDDEN2", + ], + ] + let example = Example(""" + // swiftlint:disable:next forbidden forbidden2 + let ALLOWED = 2 + """) + + let violations = try self.violations(forExample: example, customRules: customRules) + XCTAssertEqual(violations.count, 2) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "forbidden")) + XCTAssertTrue(violations[1].isSuperfluousDisableCommandViolation(for: "forbidden2")) + } + + func testUnviolatedSpecificCustomRulesTriggersSuperfluousDisableCommand() throws { + let customRules = [ + "forbidden": [ + "regex": "FORBIDDEN", + ], + "forbidden2": [ + "regex": "FORBIDDEN2", + ], + ] + let example = Example(""" + // swiftlint:disable:next forbidden forbidden2 + let FORBIDDEN = 1 + """) + + let violations = try self.violations(forExample: example, customRules: customRules) + XCTAssertEqual(violations.count, 1) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "forbidden2")) + } + + func testViolatedSpecificAndGeneralCustomRulesTriggersSuperfluousDisableCommand() throws { + let customRules = [ + "forbidden": [ + "regex": "FORBIDDEN", + ], + "forbidden2": [ + "regex": "FORBIDDEN2", + ], + ] + let example = Example(""" + // swiftlint:disable:next forbidden forbidden2 custom_rules + let FORBIDDEN = 1 + """) + + let violations = try self.violations(forExample: example, customRules: customRules) + XCTAssertEqual(violations.count, 1) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "forbidden2")) + } + + func testSuperfluousDisableCommandWithMultipleCustomRules() throws { + let customRules: [String: Any] = [ + "custom1": [ + "regex": "pattern", + "match_kinds": "comment", + ], + "custom2": [ + "regex": "10", + "match_kinds": "number", + ], + "custom3": [ + "regex": "100", + "match_kinds": "number", + ], + ] + + let example = Example( + """ + // swiftlint:disable custom1 custom3 + return 10 + """ + ) + + let violations = try violations(forExample: example, customRules: customRules) + + XCTAssertEqual(violations.count, 3) + XCTAssertEqual(violations[0].ruleIdentifier, "custom2") + XCTAssertTrue(violations[1].isSuperfluousDisableCommandViolation(for: "custom1")) + XCTAssertTrue(violations[2].isSuperfluousDisableCommandViolation(for: "custom3")) + } + + func testViolatedCustomRuleDoesNotTriggerSuperfluousDisableCommand() throws { + let customRules: [String: Any] = [ + "dont_print": [ + "regex": "print\\(" + ], + ] + let example = Example(""" + // swiftlint:disable:next dont_print + print("Hello, world") + """) + XCTAssertTrue(try violations(forExample: example, customRules: customRules).isEmpty) + } + + func testDisableAllDoesNotTriggerSuperfluousDisableCommand() throws { + let customRules: [String: Any] = [ + "dont_print": [ + "regex": "print\\(" + ], + ] + let example = Example(""" + // swiftlint:disable:next all + print("Hello, world") + """) + XCTAssertTrue(try violations(forExample: example, customRules: customRules).isEmpty) + } + + func testDisableAllAndDisableSpecificCustomRuleDoesNotTriggerSuperfluousDisableCommand() throws { + let customRules: [String: Any] = [ + "dont_print": [ + "regex": "print\\(" + ], + ] + let example = Example(""" + // swiftlint:disable:next all dont_print + print("Hello, world") + """) + XCTAssertTrue(try violations(forExample: example, customRules: customRules).isEmpty) + } + + // MARK: - Private + private func getCustomRules(_ extraConfig: [String: Any] = [:]) -> (Configuration, CustomRules) { var config: [String: Any] = [ "regex": "pattern", @@ -202,18 +436,8 @@ final class CustomRulesTests: SwiftLintTestCase { ] extraConfig.forEach { config[$0] = $1 } - var regexConfig = RegexConfiguration(identifier: "custom") - do { - try regexConfig.apply(configuration: config) - } catch { - XCTFail("Failed regex config") - } - - var customRuleConfiguration = CustomRulesConfiguration() - customRuleConfiguration.customRuleConfigurations = [regexConfig] - - var customRules = CustomRules() - customRules.configuration = customRuleConfiguration + let regexConfig = configuration(withIdentifier: "custom", configurationDict: config) + let customRules = customRules(withConfigurations: [regexConfig]) return (regexConfig, customRules) } @@ -223,34 +447,53 @@ final class CustomRulesTests: SwiftLintTestCase { "match_kinds": "comment", ] - var regexConfig1 = Configuration(identifier: "custom1") - do { - try regexConfig1.apply(configuration: config1) - } catch { - XCTFail("Failed regex config") - } + let regexConfig1 = configuration(withIdentifier: "custom1", configurationDict: config1) let config2 = [ "regex": "something", "match_kinds": "comment", ] - var regexConfig2 = Configuration(identifier: "custom2") + let regexConfig2 = configuration(withIdentifier: "custom2", configurationDict: config2) + + let customRules = customRules(withConfigurations: [regexConfig1, regexConfig2]) + return ((regexConfig1, regexConfig2), customRules) + } + + private func violations(forExample example: Example, customRules: [String: Any]) throws -> [StyleViolation] { + let configDict: [String: Any] = [ + "only_rules": ["custom_rules", "superfluous_disable_command"], + "custom_rules": customRules, + ] + let configuration = try SwiftLintCore.Configuration(dict: configDict) + return SwiftLintTestHelpers.violations( + example.skipWrappingInCommentTest(), + config: configuration + ) + } + + private func configuration(withIdentifier identifier: String, configurationDict: [String: Any]) -> Configuration { + var regexConfig = Configuration(identifier: identifier) do { - try regexConfig2.apply(configuration: config2) + try regexConfig.apply(configuration: configurationDict) } catch { XCTFail("Failed regex config") } + return regexConfig + } + private func customRules(withConfigurations configurations: [Configuration]) -> CustomRules { var customRuleConfiguration = CustomRulesConfiguration() - customRuleConfiguration.customRuleConfigurations = [regexConfig1, regexConfig2] - + customRuleConfiguration.customRuleConfigurations = configurations var customRules = CustomRules() customRules.configuration = customRuleConfiguration - return ((regexConfig1, regexConfig2), customRules) + return customRules } +} - private func getTestTextFile() -> SwiftLintFile { - SwiftLintFile(path: "\(testResourcesPath)/test.txt")! +private extension StyleViolation { + func isSuperfluousDisableCommandViolation(for ruleIdentifier: String) -> Bool { + self.ruleIdentifier == SuperfluousDisableCommandRule.description.identifier && + reason.contains("SwiftLint rule '\(ruleIdentifier)' did not trigger a violation") } } From 9e7805478104cfc3b99c02280549bdb7e01a85c9 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 8 Sep 2024 12:31:45 +0100 Subject: [PATCH 194/265] Preserve trailing comments for `opening_brace` rule (#5780) --- CHANGELOG.md | 5 +++++ .../Rules/Style/OpeningBraceRule.swift | 5 +++-- .../Style/OpeningBraceRuleExamples.swift | 22 +++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dd8e064e8..a27ac00fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#4754](https://github.com/realm/SwiftLint/issues/4754) +* Trailing comments are now preserved by the `opening_brace` rule when + rewriting. + [Martin Redington](https://github.com/mildm8nnered) + [#5751](https://github.com/realm/SwiftLint/issues/5751) + ## 0.56.2: Heat Pump Dryer #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index 4e3e46b864..fe5b55f517 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -172,10 +172,11 @@ private extension OpeningBraceRule { let previousLocation = previousToken.endLocation(converter: locationConverter) let leftBraceLocation = leftBrace.startLocation(converter: locationConverter) if previousLocation.line != leftBraceLocation.line { + let trailingCommentText = previousToken.trailingTrivia.description.trimmingCharacters(in: .whitespaces) return .init( start: previousToken.endPositionBeforeTrailingTrivia, - end: openingPosition, - replacement: " " + end: openingPosition.advanced(by: trailingCommentText.isNotEmpty ? 1 : 0), + replacement: trailingCommentText.isNotEmpty ? " { \(trailingCommentText)" : " " ) } if previousLocation.column + 1 == leftBraceLocation.column { diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift index e41dc09977..d423c231f2 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRuleExamples.swift @@ -547,6 +547,28 @@ struct OpeningBraceRuleExamples { } """), // https://github.com/realm/SwiftLint/issues/5598 + Example(""" + if c // A comment + { + return + } + """): Example(""" + if c { // A comment + return + } + """), + // https://github.com/realm/SwiftLint/issues/5751 + Example(""" + if c // A comment + { // Another comment + return + } + """): Example(""" + if c { // A comment // Another comment + return + } + """), + // https://github.com/realm/SwiftLint/issues/5751 Example(""" func foo() { if q1, q2 From 8baec9eed80a191b66ac683863f7ff8a593b23f3 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sun, 8 Sep 2024 14:22:58 +0100 Subject: [PATCH 195/265] no_magic_numbers rule now ignores violations in Preview macros (#5778) --- CHANGELOG.md | 5 +++++ .../Rules/Idiomatic/NoMagicNumbersRule.swift | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a27ac00fec..af653bdb3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,11 @@ [Sam Rayner](https://github.com/samrayner) [#5263](https://github.com/realm/SwiftLint/issues/5263) +* The `no_magic_numbers` rule will now ignore violations in + SwiftUI's `Preview` macro. + [Martin Redington](https://github.com/mildm8nnered) + [#5778](https://github.com/realm/SwiftLint/issues/5778) + #### Bug Fixes * `superfluous_disable_command` violations are now triggered for diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift index 3af3d6e77a..85cad443b6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/NoMagicNumbersRule.swift @@ -81,6 +81,11 @@ struct NoMagicNumbersRule: OptInRule { Example("let (lowerBound, upperBound) = (400, 599)"), Example("let a = (5, 10)"), Example("let notFound = (statusCode: 404, description: \"Not Found\", isError: true)"), + Example(""" + #Preview { + ContentView(value: 5) + } + """), ], triggeringExamples: [ Example("foo(↓321)"), @@ -107,6 +112,11 @@ struct NoMagicNumbersRule: OptInRule { """), Example("let imageHeight = (width - ↓24)"), Example("return (↓5, ↓10, ↓15)"), + Example(""" + #ExampleMacro { + ContentView(value: ↓5) + } + """), ] ) } @@ -121,6 +131,10 @@ private extension NoMagicNumbersRule { node.isSimpleTupleAssignment ? .skipChildren : .visitChildren } + override func visit(_ node: MacroExpansionExprSyntax) -> SyntaxVisitorContinueKind { + node.macroName.text == "Preview" ? .skipChildren : .visitChildren + } + override func visitPost(_ node: ClassDeclSyntax) { let className = node.name.text if node.isXCTestCase(configuration.testParentClasses) { From 7afe2dc1e7dd5d1a7a63b2acff65a35a3d7794ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 14:53:13 +0200 Subject: [PATCH 196/265] Combine release jobs into one workflow --- .github/workflows/docker-release.yml | 21 ------------------- .../{plugins-release.yml => release.yml} | 18 ++++++++++++++-- 2 files changed, 16 insertions(+), 23 deletions(-) delete mode 100644 .github/workflows/docker-release.yml rename .github/workflows/{plugins-release.yml => release.yml} (64%) diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml deleted file mode 100644 index 981a5ad407..0000000000 --- a/.github/workflows/docker-release.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Docker Release - -on: - release: - types: [released] - -jobs: - trigger-build: - uses: ./.github/workflows/docker.yml - with: - tag: ${{ github.event.release.tag_name }} - secrets: inherit - upload-docker: - needs: trigger-build - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v4 - - name: Upload binary to existing release - run: make zip_linux_release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/plugins-release.yml b/.github/workflows/release.yml similarity index 64% rename from .github/workflows/plugins-release.yml rename to .github/workflows/release.yml index fd2f6b5704..847357b4a3 100644 --- a/.github/workflows/plugins-release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,11 @@ -name: Plugins Release +name: Release on: release: types: [released] jobs: - dispatch: + dispatch-plugins: runs-on: ubuntu-latest steps: - name: Checkout repository @@ -25,3 +25,17 @@ jobs: "tag": "${{ github.ref_name }}", "checksum": "${{ steps.parse_checksum.outputs.checksum }}" } + trigger-docker: + uses: ./.github/workflows/docker.yml + with: + tag: ${{ github.event.release.tag_name }} + secrets: inherit + upload-docker: + needs: trigger-docker + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + - name: Upload binary to existing release + run: make zip_linux_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 1db3efde3df08aae1c40af534b0a9e68b3864b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 15:03:54 +0200 Subject: [PATCH 197/265] Get tag name from release object --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 847357b4a3..42d85270a1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: client-payload: |- { "title": "${{ github.event.release.name }}", - "tag": "${{ github.ref_name }}", + "tag": "${{ github.event.release.tag_name }}", "checksum": "${{ steps.parse_checksum.outputs.checksum }}" } trigger-docker: From 551adb047f9b9da784e910e974946ce278b28532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 15:58:22 +0200 Subject: [PATCH 198/265] Automate Pod publishing --- .github/workflows/release.yml | 13 +++++++++++++ Makefile | 6 ++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 42d85270a1..ed786cc887 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,3 +39,16 @@ jobs: run: make zip_linux_release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + publish-pod: + runs-on: macOS-latest + steps: + - uses: actions/checkout@v4 + - name: Retrieve author in uppercase + id: retrieve_author + run: | + AUTHOR=${{ github.event.release.author.login }} + echo "name=${AUTHOR@U}" >> $GITHUB_OUTPUT + - name: Deploy to CocoaPods + run: make pod_publish + env: + COCOAPODS_TRUNK_TOKEN: ${{ secrets[format('COCOAPODS_TRUNK_TOKEN_{0}', steps.retrieve_author.outputs.name)] }} diff --git a/Makefile b/Makefile index 2dcae7143c..effd9eb355 100644 --- a/Makefile +++ b/Makefile @@ -153,8 +153,10 @@ docker_htop: display_compilation_time: $(BUILD_TOOL) $(XCODEFLAGS) OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" clean build-for-testing | grep -E ^[1-9]{1}[0-9]*.[0-9]+ms | sort -n -publish: +formula_bump: brew update && brew bump-formula-pr --tag=$(shell git describe --tags) --revision=$(shell git rev-parse HEAD) swiftlint + +pod_publish: bundle install bundle exec pod trunk push SwiftLint.podspec @@ -186,7 +188,7 @@ endif git push origin HEAD git push origin $(NEW_VERSION) ./tools/create-github-release.sh "$(NEW_VERSION)" - make publish + make formula_bump ./tools/add-new-changelog-section.sh git commit -a -m "Add new changelog section" git push origin HEAD From 168fb98ed1f3e343d703ecceaf518b6cf565207b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 18:02:27 +0200 Subject: [PATCH 199/265] Release 0.57.0 --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af653bdb3b..fbff6bbc06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Main +## 0.57.0: Squeaky Clean Cycle #### Breaking diff --git a/MODULE.bazel b/MODULE.bazel index 0ce621122c..f905115cda 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "swiftlint", - version = "0.56.2", + version = "0.57.0", compatibility_level = 1, repo_name = "SwiftLint", ) diff --git a/Package.swift b/Package.swift index 22207c767e..27d7d33a2b 100644 --- a/Package.swift +++ b/Package.swift @@ -172,8 +172,8 @@ let package = Package( package.targets.append( .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.56.2/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "197df93d7f5041d8cd46d6902a34ad57914efe1b5b50635995f3b9065f2c3ffd" + url: "https://github.com/realm/SwiftLint/releases/download/0.57.0/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "a1bbafe57538077f3abe4cfb004b0464dcd87e8c23611a2153c675574b858b3a" ) ) #endif diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index 60cbe4057f..d5a8f6e690 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -9,7 +9,7 @@ public struct Version: VersionComparable { } /// The current SwiftLint version. - public static let current = Self(value: "0.56.2") + public static let current = Self(value: "0.57.0") /// Public initializer. /// From 06547973b849314ea4a079677a9e303567d1f3ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 18:02:57 +0200 Subject: [PATCH 200/265] Add new changelog section --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbff6bbc06..c962702a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Main + +#### Breaking + +* None. + +#### Experimental + +* None. + +#### Enhancements + +* None. + +#### Bug Fixes + +* None. + ## 0.57.0: Squeaky Clean Cycle #### Breaking From 9da392d1583443fc68365e6f54f86cc787b43810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 18:09:19 +0200 Subject: [PATCH 201/265] Fix workflow syntax --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed786cc887..51345f51b3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,9 +27,9 @@ jobs: } trigger-docker: uses: ./.github/workflows/docker.yml + secrets: inherit with: tag: ${{ github.event.release.tag_name }} - secrets: inherit upload-docker: needs: trigger-docker runs-on: ubuntu-20.04 From 614e694928332716a7c659260d2c4a70005e3ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 18:19:39 +0200 Subject: [PATCH 202/265] Allow to trigger Docker build manually --- .github/workflows/docker.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 062924bbeb..fcb133e479 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -11,6 +11,13 @@ on: required: true type: string default: 'latest' + workflow_dispatch: + inputs: + tag: + description: 'Docker tag' + required: true + type: string + default: 'latest' jobs: build: From 274d12b1a06a4d5b2a27143be724eff01142496c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 8 Sep 2024 18:21:28 +0200 Subject: [PATCH 203/265] Read tag from workflow input --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index fcb133e479..ed6825e433 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set Docker tag - if: github.event_name == 'workflow_call' + if: github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' run: echo "DOCKER_TAG=${{ inputs.tag }}" >> $GITHUB_ENV - name: Use default Docker tag if: github.event_name == 'push' From 85c4dbe963ab42875fd4d89307b628aeae073ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 9 Sep 2024 23:18:00 +0200 Subject: [PATCH 204/265] Ensure expected initializer signature (#5786) --- .../Rules/Lint/OptionalDataStringConversionRule.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift index a98b6dddf9..337d68b207 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift @@ -9,7 +9,10 @@ struct OptionalDataStringConversionRule: Rule { description: "Prefer failable `String(data:encoding:)` initializer when converting `Data` to `String`", kind: .lint, nonTriggeringExamples: [ - Example("String(data: data, encoding: .utf8)") + Example("String(data: data, encoding: .utf8)"), + Example("String(UTF8.self)"), + Example("String(a, b, c, UTF8.self)"), + Example("String(decoding: data, encoding: UTF8.self)"), ], triggeringExamples: [ Example("String(decoding: data, as: UTF8.self)") @@ -22,6 +25,7 @@ private extension OptionalDataStringConversionRule { override func visitPost(_ node: DeclReferenceExprSyntax) { if node.baseName.text == "String", let parent = node.parent?.as(FunctionCallExprSyntax.self), + parent.arguments.map(\.label?.text) == ["decoding", "as"], let expr = parent.arguments.last?.expression.as(MemberAccessExprSyntax.self), expr.base?.description == "UTF8", expr.declName.baseName.description == "self" { From 8241909addfd1a10cefde7d0619c4b9c16ba43b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 11 Sep 2024 23:16:39 +0200 Subject: [PATCH 205/265] Run command plugin in whole package if no targets defined (#5789) --- CHANGELOG.md | 5 +- .../SwiftLintCommandPlugin.swift | 64 +++++++++++-------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c962702a1f..43b2f1aeb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,10 @@ #### Bug Fixes -* None. +* Run command plugin in whole package if no targets are defined in the + package manifest. + [SimplyDanny](https://github.com/SimplyDanny) + [#5787](https://github.com/realm/SwiftLint/issues/5787) ## 0.57.0: Squeaky Clean Cycle diff --git a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift index 4fdcb6bbca..d254ff8fdd 100644 --- a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift +++ b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift @@ -13,42 +13,52 @@ struct SwiftLintCommandPlugin: CommandPlugin { let targets = targetNames.isEmpty ? context.package.targets : try context.package.targets(named: targetNames) - let tool = try context.tool(named: "swiftlint") + guard !targets.isEmpty else { + try run(with: context, arguments: arguments) + return + } for target in targets { guard let target = target.sourceModule else { Diagnostics.warning("Target '\(target.name)' is not a source module; skipping it") continue } + try run(in: target.directory.string, for: target.name, with: context, arguments: arguments) + } + } - let process = Process() - process.currentDirectoryURL = URL(fileURLWithPath: context.package.directory.string) - process.executableURL = URL(fileURLWithPath: tool.path.string) - process.arguments = arguments - if !arguments.contains("analyze") { - // The analyze command does not support the `--cache-path` argument. - process.arguments! += ["--cache-path", "\(context.pluginWorkDirectory.string)"] - } - process.arguments! += [target.directory.string] + private func run(in directory: String = ".", + for targetName: String? = nil, + with context: PluginContext, + arguments: [String]) throws { + let process = Process() + process.currentDirectoryURL = URL(fileURLWithPath: context.package.directory.string) + process.executableURL = URL(fileURLWithPath: try context.tool(named: "swiftlint").path.string) + process.arguments = arguments + if !arguments.contains("analyze") { + // The analyze command does not support the `--cache-path` argument. + process.arguments! += ["--cache-path", "\(context.pluginWorkDirectory.string)"] + } + process.arguments! += [directory] - try process.run() - process.waitUntilExit() + try process.run() + process.waitUntilExit() - switch process.terminationReason { - case .exit: - Diagnostics.remark("Finished running in module '\(target.name)'") - case .uncaughtSignal: - Diagnostics.error("Got uncaught signal while running in module '\(target.name)'") - @unknown default: - Diagnostics.error("Stopped running in module '\(target.name) due to unexpected termination reason") - } + let module = targetName.map { "module '\($0)'" } ?? "package" + switch process.terminationReason { + case .exit: + Diagnostics.remark("Finished running in \(module)") + case .uncaughtSignal: + Diagnostics.error("Got uncaught signal while running in \(module)") + @unknown default: + Diagnostics.error("Stopped running in \(module) due to unexpected termination reason") + } - if process.terminationStatus != EXIT_SUCCESS { - Diagnostics.error(""" - Command found error violations or unsuccessfully stopped running with \ - exit code \(process.terminationStatus) in module '\(target.name)' - """ - ) - } + if process.terminationStatus != EXIT_SUCCESS { + Diagnostics.error(""" + Command found error violations or unsuccessfully stopped running with \ + exit code \(process.terminationStatus) in \(module) + """ + ) } } } From 0d04196f92605735821630165bc64c3c3229c913 Mon Sep 17 00:00:00 2001 From: Vladimir Burdukov Date: Sun, 15 Sep 2024 22:13:31 +0300 Subject: [PATCH 206/265] Do not throw deprecation warning if property is not present in configuration (#5792) --- CHANGELOG.md | 5 ++++ .../RuleConfigurationMacros.swift | 4 ++- Tests/MacroTests/AutoConfigParserTests.swift | 26 +++++++++++++------ .../RuleConfigurationDescriptionTests.swift | 11 +++++--- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43b2f1aeb0..8349e5b825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5787](https://github.com/realm/SwiftLint/issues/5787) +* Do not throw deprecation warning if deprecated property is not + presented in configuration. + [chipp](https://github.com/chipp) + [#5791](https://github.com/realm/SwiftLint/issues/5791) + ## 0.57.0: Squeaky Clean Cycle #### Breaking diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index 665a9e4335..e1a44256e8 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -74,7 +74,9 @@ enum AutoConfigParser: MemberMacro { """ for option in nonInlinedOptions { """ - try \(raw: option).apply(configuration[$\(raw: option).key], ruleID: Parent.identifier) + if let value = configuration[$\(raw: option).key] { + try \(raw: option).apply(value, ruleID: Parent.identifier) + } """ } """ diff --git a/Tests/MacroTests/AutoConfigParserTests.swift b/Tests/MacroTests/AutoConfigParserTests.swift index 39d9505032..4164eb411f 100644 --- a/Tests/MacroTests/AutoConfigParserTests.swift +++ b/Tests/MacroTests/AutoConfigParserTests.swift @@ -80,8 +80,12 @@ final class AutoConfigParserTests: XCTestCase { guard let configuration = configuration as? [String: Any] else { throw Issue.invalidConfiguration(ruleID: Parent.identifier) } - try eA.apply(configuration[$eA.key], ruleID: Parent.identifier) - try eB.apply(configuration[$eB.key], ruleID: Parent.identifier) + if let value = configuration[$eA.key] { + try eA.apply(value, ruleID: Parent.identifier) + } + if let value = configuration[$eB.key] { + try eB.apply(value, ruleID: Parent.identifier) + } if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() @@ -131,8 +135,12 @@ final class AutoConfigParserTests: XCTestCase { guard let configuration = configuration as? [String: Any] else { return } - try eA.apply(configuration[$eA.key], ruleID: Parent.identifier) - try eC.apply(configuration[$eC.key], ruleID: Parent.identifier) + if let value = configuration[$eA.key] { + try eA.apply(value, ruleID: Parent.identifier) + } + if let value = configuration[$eC.key] { + try eC.apply(value, ruleID: Parent.identifier) + } if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() @@ -177,7 +185,6 @@ final class AutoConfigParserTests: XCTestCase { } func testSeverityAppliedTwice() { - // swiftlint:disable line_length assertMacroExpansion( """ @AutoConfigParser @@ -211,8 +218,12 @@ final class AutoConfigParserTests: XCTestCase { guard let configuration = configuration as? [String: Any] else { return } - try severityConfiguration.apply(configuration[$severityConfiguration.key], ruleID: Parent.identifier) - try foo.apply(configuration[$foo.key], ruleID: Parent.identifier) + if let value = configuration[$severityConfiguration.key] { + try severityConfiguration.apply(value, ruleID: Parent.identifier) + } + if let value = configuration[$foo.key] { + try foo.apply(value, ruleID: Parent.identifier) + } if !supportedKeys.isSuperset(of: configuration.keys) { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() @@ -222,6 +233,5 @@ final class AutoConfigParserTests: XCTestCase { """, macros: macros ) - // swiftlint:enable line_length } } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift index a4fc6bd707..a656666d60 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationDescriptionTests.swift @@ -499,6 +499,12 @@ final class RuleConfigurationDescriptionTests: XCTestCase { ) } + func testNoDeprecationWarningIfNoDeprecatedPropertySet() throws { + var configuration = TestConfiguration() + + XCTAssert(try Issue.captureConsole { try configuration.apply(configuration: ["flag": false]) }.isEmpty) + } + func testInvalidKeys() throws { var configuration = TestConfiguration() @@ -511,10 +517,7 @@ final class RuleConfigurationDescriptionTests: XCTestCase { "unsupported": true, ]) }, - """ - warning: Configuration option 'set' in 'my_rule' rule is deprecated. Use the option 'other_opt' instead. - warning: Configuration for 'RuleMock' rule contains the invalid key(s) 'unknown', 'unsupported'. - """ + "warning: Configuration for 'RuleMock' rule contains the invalid key(s) 'unknown', 'unsupported'." ) } From a826d177c56aa8538438435e4d8288691653d249 Mon Sep 17 00:00:00 2001 From: minhaaan Date: Mon, 16 Sep 2024 04:14:06 +0900 Subject: [PATCH 207/265] Use SwiftSyntax version 600.0.0 (#5795) --- MODULE.bazel | 2 +- Package.resolved | 4 ++-- Package.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index f905115cda..8ec7b30033 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,7 +11,7 @@ bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "rules_apple", version = "3.8.0", repo_name = "build_bazel_rules_apple") bazel_dep(name = "rules_swift", version = "2.1.1", repo_name = "build_bazel_rules_swift") bazel_dep(name = "sourcekitten", version = "0.36.0", repo_name = "com_github_jpsim_sourcekitten") -bazel_dep(name = "swift-syntax", version = "600.0.0-prerelease-2024-08-14", repo_name = "SwiftSyntax") +bazel_dep(name = "swift-syntax", version = "600.0.0", repo_name = "SwiftSyntax") bazel_dep(name = "swift_argument_parser", version = "1.3.1.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser") bazel_dep(name = "yams", version = "5.1.3", repo_name = "sourcekitten_com_github_jpsim_yams") diff --git a/Package.resolved b/Package.resolved index 204129e258..ee63d9748b 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "515f79b522918f83483068d99c68daeb5116342d", - "version" : "600.0.0-prerelease-2024-08-14" + "revision" : "cb53fa1bd3219b0b23ded7dfdd3b2baff266fd25", + "version" : "600.0.0" } }, { diff --git a/Package.swift b/Package.swift index 27d7d33a2b..3b24604dfd 100644 --- a/Package.swift +++ b/Package.swift @@ -29,7 +29,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.1"), - .package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "600.0.0-prerelease-2024-08-14"), + .package(url: "https://github.com/swiftlang/swift-syntax.git", exact: "600.0.0"), .package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.35.0")), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"), .package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"), From 37f15d4388e0897fbb7507dbb82cd20285826472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 16 Sep 2024 20:16:35 +0200 Subject: [PATCH 208/265] Suggest broader initializer accepting Sequences (#5794) --- CHANGELOG.md | 6 +++++- .../Rules/Lint/OptionalDataStringConversionRule.swift | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8349e5b825..7257d37b63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,11 @@ #### Enhancements -* None. +* Suggest failable `String(bytes:encoding:)` initializer in + `optional_data_string_conversion` rule as it accepts all `Sequence` + types. + [Jordan Rose](https://github.com/jrose-signal) + [SimplyDanny](https://github.com/SimplyDanny) #### Bug Fixes diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift index 337d68b207..1aa44801ec 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/OptionalDataStringConversionRule.swift @@ -3,13 +3,15 @@ import SwiftSyntax @SwiftSyntaxRule struct OptionalDataStringConversionRule: Rule { var configuration = SeverityConfiguration(.warning) + static let description = RuleDescription( identifier: "optional_data_string_conversion", name: "Optional Data -> String Conversion", - description: "Prefer failable `String(data:encoding:)` initializer when converting `Data` to `String`", + description: "Prefer failable `String(bytes:encoding:)` initializer when converting `Data` to `String`", kind: .lint, nonTriggeringExamples: [ Example("String(data: data, encoding: .utf8)"), + Example("String(bytes: data, encoding: .utf8)"), Example("String(UTF8.self)"), Example("String(a, b, c, UTF8.self)"), Example("String(decoding: data, encoding: UTF8.self)"), From e9386aea51e56c398eb0809ad5993f5a78d13e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 16 Sep 2024 21:49:15 +0200 Subject: [PATCH 209/265] Disallow optional configuration values (#5798) Can be avoided now given 0d04196. --- .../Models/RuleConfigurationDescription.swift | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift index b09b4a914e..b0e5750897 100644 --- a/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift +++ b/Source/SwiftLintCore/Models/RuleConfigurationDescription.swift @@ -336,8 +336,10 @@ public protocol AcceptableByConfigurationElement { /// Update the object. /// - /// - Parameter value: New underlying data for the object. - mutating func apply(_ value: Any?, ruleID: String) throws + /// - Parameters: + /// - value: New underlying data for the object. + /// - ruleID: The rule's identifier in which context the configuration parsing runs. + mutating func apply(_ value: Any, ruleID: String) throws } /// Default implementations which are shortcuts applicable for most of the types conforming to the protocol. @@ -346,10 +348,8 @@ public extension AcceptableByConfigurationElement { RuleConfigurationDescription(options: [key => asOption()]) } - mutating func apply(_ value: Any?, ruleID: String) throws { - if let value { - self = try Self(fromAny: value, context: ruleID) - } + mutating func apply(_ value: Any, ruleID: String) throws { + self = try Self(fromAny: value, context: ruleID) } } @@ -657,10 +657,8 @@ public extension AcceptableByConfigurationElement where Self: RuleConfiguration return RuleConfigurationDescription(options: [key => asOption()]) } - mutating func apply(_ value: Any?, ruleID _: String) throws { - if let value { - try apply(configuration: value) - } + mutating func apply(_ value: Any, ruleID _: String) throws { + try apply(configuration: value) } init(fromAny _: Any, context _: String) throws { From 1767dab4858a310719fdf44e6c8dd9dc371503f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 21 Sep 2024 13:53:30 +0200 Subject: [PATCH 210/265] Add Swift 6 presentation of `map(_:)` type (#5804) --- .../Rules/Lint/TypesafeArrayInitRule.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift index 0d7ea85937..faa619e479 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift @@ -51,10 +51,16 @@ struct TypesafeArrayInitRule: AnalyzerRule { ) private static let parentRule = ArrayInitRule() - private static let mapTypePattern = regex(""" - \\Q \ - \\Q(Self) -> ((Self.Element) throws -> T) throws -> [T]\\E - """) + private static let mapTypePatterns = [ + regex(""" + \\Q \ + \\Q(Self) -> ((Self.Element) throws -> T) throws -> [T]\\E + """), + regex(""" + \\Q (Self) -> ((Self.Element) throws(E) -> T) throws(E) -> [T]\\E + """), + ] func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] { guard let filePath = file.path else { @@ -83,7 +89,9 @@ struct TypesafeArrayInitRule: AnalyzerRule { if let isSystem = pointee["key.is_system"], isSystem.isEqualTo(true), let name = pointee["key.name"], name.isEqualTo("map(_:)"), let typeName = pointee["key.typename"] as? String { - return Self.mapTypePattern.numberOfMatches(in: typeName, range: typeName.fullNSRange) == 1 + return Self.mapTypePatterns.contains { + $0.numberOfMatches(in: typeName, range: typeName.fullNSRange) == 1 + } } return false } From 246643fe55f2b024804551016b0ed9394e056684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 17:23:46 +0200 Subject: [PATCH 211/265] Keep only command-line related functions in `swiftlint` module (#5806) Swift 6 doesn't allow importing executable targets. So we need to move testable logic into a framework. --- .bazelrc | 1 - BUILD | 18 +-- Package.swift | 2 +- .../Benchmark.swift | 1 - .../CompilerArgumentsExtractor.swift | 0 .../Configuration+CommandLine.swift | 1 - .../ExitHelper.swift | 4 +- Source/SwiftLintFramework/Exports.swift | 2 +- .../LintOrAnalyzeCommand.swift | 139 ++++++++++++------ .../LintableFilesVisitor.swift | 1 - .../ProcessInfo+XcodeCloud.swift | 0 .../ProgressBar.swift | 1 - .../RulesFilter.swift | 20 +-- .../Signposts.swift | 0 .../SwiftLintError.swift | 4 +- .../SwiftPMCompilationDB.swift | 0 .../UpdateChecker.swift | 5 +- ....ExcludingOptions+RulesFilterOptions.swift | 20 --- Source/swiftlint/Commands/GenerateDocs.swift | 2 +- Source/swiftlint/Commands/Rules.swift | 2 +- .../LintOrAnalyzeArguments.swift | 1 + .../Common/RulesFilterOptions.swift | 20 +++ Tests/BUILD | 2 +- Tests/CLITests/RulesFilterTests.swift | 1 - 24 files changed, 144 insertions(+), 103 deletions(-) rename Source/{swiftlint/Helpers => SwiftLintFramework}/Benchmark.swift (98%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/CompilerArgumentsExtractor.swift (100%) rename Source/{swiftlint/Extensions => SwiftLintFramework}/Configuration+CommandLine.swift (99%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/ExitHelper.swift (68%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/LintOrAnalyzeCommand.swift (86%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/LintableFilesVisitor.swift (99%) rename Source/{swiftlint/Extensions => SwiftLintFramework}/ProcessInfo+XcodeCloud.swift (100%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/ProgressBar.swift (98%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/RulesFilter.swift (63%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/Signposts.swift (100%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/SwiftLintError.swift (66%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/SwiftPMCompilationDB.swift (100%) rename Source/{swiftlint/Helpers => SwiftLintFramework}/UpdateChecker.swift (95%) delete mode 100644 Source/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift rename Source/swiftlint/{Helpers => Common}/LintOrAnalyzeArguments.swift (99%) rename Source/swiftlint/{Commands => }/Common/RulesFilterOptions.swift (51%) diff --git a/.bazelrc b/.bazelrc index aef68378fb..12ae6e95c6 100644 --- a/.bazelrc +++ b/.bazelrc @@ -13,7 +13,6 @@ build --disk_cache=~/.bazel_cache build --experimental_remote_cache_compression build --remote_build_event_upload=minimal build --nolegacy_important_outputs -build --swiftcopt=-warnings-as-errors build:release \ --compilation_mode=opt \ diff --git a/BUILD b/BUILD index b13f510f8e..9dd4eacfee 100644 --- a/BUILD +++ b/BUILD @@ -142,33 +142,23 @@ swift_library( ":SwiftLintBuiltInRules", ":SwiftLintCore", ":SwiftLintExtraRules", + "@com_github_johnsundell_collectionconcurrencykit//:CollectionConcurrencyKit", ], ) -swift_library( - name = "swiftlint.library", +swift_binary( + name = "swiftlint", package_name = "SwiftLint", srcs = glob(["Source/swiftlint/**/*.swift"]), - copts = copts, # TODO: strict_concurrency_copts - module_name = "swiftlint", + copts = copts, visibility = ["//visibility:public"], deps = [ ":SwiftLintFramework", - "@com_github_johnsundell_collectionconcurrencykit//:CollectionConcurrencyKit", "@sourcekitten_com_github_apple_swift_argument_parser//:ArgumentParser", "@swiftlint_com_github_scottrhoyt_swifty_text_table//:SwiftyTextTable", ], ) -swift_binary( - name = "swiftlint", - copts = copts + strict_concurrency_copts, - visibility = ["//visibility:public"], - deps = [ - ":swiftlint.library", - ], -) - apple_universal_binary( name = "universal_swiftlint", binary = ":swiftlint", diff --git a/Package.swift b/Package.swift index 3b24604dfd..0dfcc60a62 100644 --- a/Package.swift +++ b/Package.swift @@ -60,7 +60,7 @@ let package = Package( .testTarget( name: "CLITests", dependencies: [ - "swiftlint" + "SwiftLintFramework", ], swiftSettings: swiftFeatures ), diff --git a/Source/swiftlint/Helpers/Benchmark.swift b/Source/SwiftLintFramework/Benchmark.swift similarity index 98% rename from Source/swiftlint/Helpers/Benchmark.swift rename to Source/SwiftLintFramework/Benchmark.swift index b05755babb..76b113155c 100644 --- a/Source/swiftlint/Helpers/Benchmark.swift +++ b/Source/SwiftLintFramework/Benchmark.swift @@ -1,5 +1,4 @@ import Foundation -import SwiftLintFramework struct BenchmarkEntry { let id: String diff --git a/Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift b/Source/SwiftLintFramework/CompilerArgumentsExtractor.swift similarity index 100% rename from Source/swiftlint/Helpers/CompilerArgumentsExtractor.swift rename to Source/SwiftLintFramework/CompilerArgumentsExtractor.swift diff --git a/Source/swiftlint/Extensions/Configuration+CommandLine.swift b/Source/SwiftLintFramework/Configuration+CommandLine.swift similarity index 99% rename from Source/swiftlint/Extensions/Configuration+CommandLine.swift rename to Source/SwiftLintFramework/Configuration+CommandLine.swift index 6eb4eeb061..49e62b9a69 100644 --- a/Source/swiftlint/Extensions/Configuration+CommandLine.swift +++ b/Source/SwiftLintFramework/Configuration+CommandLine.swift @@ -1,7 +1,6 @@ import CollectionConcurrencyKit import Foundation import SourceKittenFramework -import SwiftLintFramework private actor CounterActor { private var count = 0 diff --git a/Source/swiftlint/Helpers/ExitHelper.swift b/Source/SwiftLintFramework/ExitHelper.swift similarity index 68% rename from Source/swiftlint/Helpers/ExitHelper.swift rename to Source/SwiftLintFramework/ExitHelper.swift index cd20c6a7de..f2bf1281ea 100644 --- a/Source/swiftlint/Helpers/ExitHelper.swift +++ b/Source/SwiftLintFramework/ExitHelper.swift @@ -2,8 +2,8 @@ import Glibc #endif -enum ExitHelper { - static func successfullyExit() { +package enum ExitHelper { + package static func successfullyExit() { #if os(Linux) // Workaround for https://github.com/apple/swift/issues/59961 Glibc.exit(0) diff --git a/Source/SwiftLintFramework/Exports.swift b/Source/SwiftLintFramework/Exports.swift index b61dabc36c..a352d954cd 100644 --- a/Source/SwiftLintFramework/Exports.swift +++ b/Source/SwiftLintFramework/Exports.swift @@ -6,7 +6,7 @@ private let _registerAllRulesOnceImpl: Void = { RuleRegistry.shared.register(rules: builtInRules + coreRules + extraRules()) }() -public extension RuleRegistry { +package extension RuleRegistry { /// Register all rules. Should only be called once before any SwiftLint code is executed. static func registerAllRulesOnce() { _ = _registerAllRulesOnceImpl diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift similarity index 86% rename from Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift rename to Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index 1994c12ff4..b2d313233b 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -1,11 +1,12 @@ import Dispatch import Foundation -import SwiftLintFramework -enum LintOrAnalyzeMode { +// swiftlint:disable file_length + +package enum LintOrAnalyzeMode { case lint, analyze - var imperative: String { + package var imperative: String { switch self { case .lint: return "lint" @@ -14,7 +15,7 @@ enum LintOrAnalyzeMode { } } - var verb: String { + package var verb: String { switch self { case .lint: return "linting" @@ -24,8 +25,98 @@ enum LintOrAnalyzeMode { } } -struct LintOrAnalyzeCommand { - static func run(_ options: LintOrAnalyzeOptions) async throws { +package struct LintOrAnalyzeOptions { + let mode: LintOrAnalyzeMode + let paths: [String] + let useSTDIN: Bool + let configurationFiles: [String] + let strict: Bool + let lenient: Bool + let forceExclude: Bool + let useExcludingByPrefix: Bool + let useScriptInputFiles: Bool + let benchmark: Bool + let reporter: String? + let baseline: String? + let writeBaseline: String? + let workingDirectory: String? + let quiet: Bool + let output: String? + let progress: Bool + let cachePath: String? + let ignoreCache: Bool + let enableAllRules: Bool + let onlyRule: String? + let autocorrect: Bool + let format: Bool + let compilerLogPath: String? + let compileCommands: String? + let checkForUpdates: Bool + + package init(mode: LintOrAnalyzeMode, + paths: [String], + useSTDIN: Bool, + configurationFiles: [String], + strict: Bool, + lenient: Bool, + forceExclude: Bool, + useExcludingByPrefix: Bool, + useScriptInputFiles: Bool, + benchmark: Bool, + reporter: String?, + baseline: String?, + writeBaseline: String?, + workingDirectory: String?, + quiet: Bool, + output: String?, + progress: Bool, + cachePath: String?, + ignoreCache: Bool, + enableAllRules: Bool, + onlyRule: String?, + autocorrect: Bool, + format: Bool, + compilerLogPath: String?, + compileCommands: String?, + checkForUpdates: Bool) { + self.mode = mode + self.paths = paths + self.useSTDIN = useSTDIN + self.configurationFiles = configurationFiles + self.strict = strict + self.lenient = lenient + self.forceExclude = forceExclude + self.useExcludingByPrefix = useExcludingByPrefix + self.useScriptInputFiles = useScriptInputFiles + self.benchmark = benchmark + self.reporter = reporter + self.baseline = baseline + self.writeBaseline = writeBaseline + self.workingDirectory = workingDirectory + self.quiet = quiet + self.output = output + self.progress = progress + self.cachePath = cachePath + self.ignoreCache = ignoreCache + self.enableAllRules = enableAllRules + self.onlyRule = onlyRule + self.autocorrect = autocorrect + self.format = format + self.compilerLogPath = compilerLogPath + self.compileCommands = compileCommands + self.checkForUpdates = checkForUpdates + } + + var verb: String { + if autocorrect { + return "correcting" + } + return mode.verb + } +} + +package struct LintOrAnalyzeCommand { + package static func run(_ options: LintOrAnalyzeOptions) async throws { if let workingDirectory = options.workingDirectory { if !FileManager.default.changeCurrentDirectoryPath(workingDirectory) { throw SwiftLintError.usageError( @@ -251,42 +342,6 @@ struct LintOrAnalyzeCommand { } } -struct LintOrAnalyzeOptions { - let mode: LintOrAnalyzeMode - let paths: [String] - let useSTDIN: Bool - let configurationFiles: [String] - let strict: Bool - let lenient: Bool - let forceExclude: Bool - let useExcludingByPrefix: Bool - let useScriptInputFiles: Bool - let benchmark: Bool - let reporter: String? - let baseline: String? - let writeBaseline: String? - let workingDirectory: String? - let quiet: Bool - let output: String? - let progress: Bool - let cachePath: String? - let ignoreCache: Bool - let enableAllRules: Bool - let onlyRule: String? - let autocorrect: Bool - let format: Bool - let compilerLogPath: String? - let compileCommands: String? - let checkForUpdates: Bool - - var verb: String { - if autocorrect { - return "correcting" - } - return mode.verb - } -} - private class LintOrAnalyzeResultBuilder { var fileBenchmark = Benchmark(name: "files") var ruleBenchmark = Benchmark(name: "rules") diff --git a/Source/swiftlint/Helpers/LintableFilesVisitor.swift b/Source/SwiftLintFramework/LintableFilesVisitor.swift similarity index 99% rename from Source/swiftlint/Helpers/LintableFilesVisitor.swift rename to Source/SwiftLintFramework/LintableFilesVisitor.swift index c200513478..97c5a2e535 100644 --- a/Source/swiftlint/Helpers/LintableFilesVisitor.swift +++ b/Source/SwiftLintFramework/LintableFilesVisitor.swift @@ -1,6 +1,5 @@ import Foundation import SourceKittenFramework -import SwiftLintFramework typealias File = String typealias Arguments = [String] diff --git a/Source/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift b/Source/SwiftLintFramework/ProcessInfo+XcodeCloud.swift similarity index 100% rename from Source/swiftlint/Extensions/ProcessInfo+XcodeCloud.swift rename to Source/SwiftLintFramework/ProcessInfo+XcodeCloud.swift diff --git a/Source/swiftlint/Helpers/ProgressBar.swift b/Source/SwiftLintFramework/ProgressBar.swift similarity index 98% rename from Source/swiftlint/Helpers/ProgressBar.swift rename to Source/SwiftLintFramework/ProgressBar.swift index 0d50555df6..b5a08ab62f 100644 --- a/Source/swiftlint/Helpers/ProgressBar.swift +++ b/Source/SwiftLintFramework/ProgressBar.swift @@ -1,6 +1,5 @@ import Dispatch import Foundation -import SwiftLintFramework // Inspired by https://github.com/jkandzi/Progress.swift actor ProgressBar { diff --git a/Source/swiftlint/Helpers/RulesFilter.swift b/Source/SwiftLintFramework/RulesFilter.swift similarity index 63% rename from Source/swiftlint/Helpers/RulesFilter.swift rename to Source/SwiftLintFramework/RulesFilter.swift index ad56eb29b4..9f585f7be4 100644 --- a/Source/swiftlint/Helpers/RulesFilter.swift +++ b/Source/SwiftLintFramework/RulesFilter.swift @@ -1,23 +1,25 @@ -import SwiftLintFramework +package final class RulesFilter { + package struct ExcludingOptions: OptionSet { + package let rawValue: Int -final class RulesFilter { - struct ExcludingOptions: OptionSet { - let rawValue: Int + package init(rawValue: Int) { + self.rawValue = rawValue + } - static let enabled = Self(rawValue: 1 << 0) - static let disabled = Self(rawValue: 1 << 1) - static let uncorrectable = Self(rawValue: 1 << 2) + package static let enabled = Self(rawValue: 1 << 0) + package static let disabled = Self(rawValue: 1 << 1) + package static let uncorrectable = Self(rawValue: 1 << 2) } private let allRules: RuleList private let enabledRules: [any Rule] - init(allRules: RuleList = RuleRegistry.shared.list, enabledRules: [any Rule]) { + package init(allRules: RuleList = RuleRegistry.shared.list, enabledRules: [any Rule]) { self.allRules = allRules self.enabledRules = enabledRules } - func getRules(excluding excludingOptions: ExcludingOptions) -> RuleList { + package func getRules(excluding excludingOptions: ExcludingOptions) -> RuleList { if excludingOptions.isEmpty { return allRules } diff --git a/Source/swiftlint/Helpers/Signposts.swift b/Source/SwiftLintFramework/Signposts.swift similarity index 100% rename from Source/swiftlint/Helpers/Signposts.swift rename to Source/SwiftLintFramework/Signposts.swift diff --git a/Source/swiftlint/Helpers/SwiftLintError.swift b/Source/SwiftLintFramework/SwiftLintError.swift similarity index 66% rename from Source/swiftlint/Helpers/SwiftLintError.swift rename to Source/SwiftLintFramework/SwiftLintError.swift index cf17a123a4..da6ee8fd49 100644 --- a/Source/swiftlint/Helpers/SwiftLintError.swift +++ b/Source/SwiftLintFramework/SwiftLintError.swift @@ -1,9 +1,9 @@ import Foundation -enum SwiftLintError: LocalizedError { +package enum SwiftLintError: LocalizedError { case usageError(description: String) - var errorDescription: String? { + package var errorDescription: String? { switch self { case .usageError(let description): return description diff --git a/Source/swiftlint/Helpers/SwiftPMCompilationDB.swift b/Source/SwiftLintFramework/SwiftPMCompilationDB.swift similarity index 100% rename from Source/swiftlint/Helpers/SwiftPMCompilationDB.swift rename to Source/SwiftLintFramework/SwiftPMCompilationDB.swift diff --git a/Source/swiftlint/Helpers/UpdateChecker.swift b/Source/SwiftLintFramework/UpdateChecker.swift similarity index 95% rename from Source/swiftlint/Helpers/UpdateChecker.swift rename to Source/SwiftLintFramework/UpdateChecker.swift index 15f4294b85..81043ce36b 100644 --- a/Source/swiftlint/Helpers/UpdateChecker.swift +++ b/Source/SwiftLintFramework/UpdateChecker.swift @@ -14,10 +14,9 @@ import Foundation #if canImport(FoundationNetworking) import FoundationNetworking #endif -import SwiftLintFramework -enum UpdateChecker { - static func checkForUpdates() { +package enum UpdateChecker { + package static func checkForUpdates() { guard let url = URL(string: "https://api.github.com/repos/realm/SwiftLint/releases/latest"), let data = sendRequest(to: url), let latestVersionNumber = parseVersionNumber(data) else { diff --git a/Source/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift b/Source/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift deleted file mode 100644 index 192bf6895a..0000000000 --- a/Source/swiftlint/Commands/Common/RulesFilter.ExcludingOptions+RulesFilterOptions.swift +++ /dev/null @@ -1,20 +0,0 @@ -extension RulesFilter.ExcludingOptions { - static func excludingOptions(byCommandLineOptions rulesFilterOptions: RulesFilterOptions) -> Self { - var excludingOptions: Self = [] - - switch rulesFilterOptions.ruleEnablement { - case .enabled: - excludingOptions.insert(.disabled) - case .disabled: - excludingOptions.insert(.enabled) - case .none: - break - } - - if rulesFilterOptions.correctable { - excludingOptions.insert(.uncorrectable) - } - - return excludingOptions - } -} diff --git a/Source/swiftlint/Commands/GenerateDocs.swift b/Source/swiftlint/Commands/GenerateDocs.swift index fc448fc594..b62e6ae8f9 100644 --- a/Source/swiftlint/Commands/GenerateDocs.swift +++ b/Source/swiftlint/Commands/GenerateDocs.swift @@ -18,7 +18,7 @@ extension SwiftLint { func run() throws { let configuration = Configuration(configurationFiles: [config].compactMap({ $0 })) let rulesFilter = RulesFilter(enabledRules: configuration.rules) - let rules = rulesFilter.getRules(excluding: .excludingOptions(byCommandLineOptions: rulesFilterOptions)) + let rules = rulesFilter.getRules(excluding: rulesFilterOptions.excludingOptions) try RuleListDocumentation(rules) .write(to: URL(fileURLWithPath: path, isDirectory: true)) diff --git a/Source/swiftlint/Commands/Rules.swift b/Source/swiftlint/Commands/Rules.swift index 33cb9bd94a..0ed3a966a7 100644 --- a/Source/swiftlint/Commands/Rules.swift +++ b/Source/swiftlint/Commands/Rules.swift @@ -40,7 +40,7 @@ extension SwiftLint { return } let rules = RulesFilter(enabledRules: configuration.rules) - .getRules(excluding: .excludingOptions(byCommandLineOptions: rulesFilterOptions)) + .getRules(excluding: rulesFilterOptions.excludingOptions) .list .sorted { $0.0 < $1.0 } if configOnly { diff --git a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift b/Source/swiftlint/Common/LintOrAnalyzeArguments.swift similarity index 99% rename from Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift rename to Source/swiftlint/Common/LintOrAnalyzeArguments.swift index 779293fdf7..8b9b00eba5 100644 --- a/Source/swiftlint/Helpers/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Common/LintOrAnalyzeArguments.swift @@ -1,4 +1,5 @@ import ArgumentParser +import SwiftLintFramework enum LeniencyOptions: String, EnumerableFlag { case strict, lenient diff --git a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift b/Source/swiftlint/Common/RulesFilterOptions.swift similarity index 51% rename from Source/swiftlint/Commands/Common/RulesFilterOptions.swift rename to Source/swiftlint/Common/RulesFilterOptions.swift index e4bfe4fb47..456bfe44d5 100644 --- a/Source/swiftlint/Commands/Common/RulesFilterOptions.swift +++ b/Source/swiftlint/Common/RulesFilterOptions.swift @@ -1,4 +1,5 @@ import ArgumentParser +import SwiftLintFramework enum RuleEnablementOptions: String, EnumerableFlag { case enabled, disabled @@ -17,4 +18,23 @@ struct RulesFilterOptions: ParsableArguments { var ruleEnablement: RuleEnablementOptions? @Flag(name: .shortAndLong, help: "Only display correctable rules") var correctable = false + + var excludingOptions: RulesFilter.ExcludingOptions { + var excludingOptions: RulesFilter.ExcludingOptions = [] + + switch ruleEnablement { + case .enabled: + excludingOptions.insert(.disabled) + case .disabled: + excludingOptions.insert(.enabled) + case .none: + break + } + + if correctable { + excludingOptions.insert(.uncorrectable) + } + + return excludingOptions + } } diff --git a/Tests/BUILD b/Tests/BUILD index 509bce099d..01aa65395c 100644 --- a/Tests/BUILD +++ b/Tests/BUILD @@ -13,7 +13,7 @@ swift_library( module_name = "CLITests", package_name = "SwiftLint", deps = [ - "//:swiftlint.library", + "//:SwiftLintFramework", ], copts = copts, ) diff --git a/Tests/CLITests/RulesFilterTests.swift b/Tests/CLITests/RulesFilterTests.swift index e3546c0810..7c2f3fcfa4 100644 --- a/Tests/CLITests/RulesFilterTests.swift +++ b/Tests/CLITests/RulesFilterTests.swift @@ -1,4 +1,3 @@ -@testable import swiftlint import SwiftLintFramework import XCTest From 8db0fbf6e8ed33dc0b37bffff2e8a8122dbc65a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 19:18:02 +0200 Subject: [PATCH 212/265] Extend clean command --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index effd9eb355..b20fa4e15c 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,8 @@ analyze_autocorrect: write_xcodebuild_log clean: rm -f "$(OUTPUT_PACKAGE)" rm -rf "$(TEMPORARY_FOLDER)" - rm -f "./*.zip" "bazel.tar.gz" "bazel.tar.gz.sha256" + rm -rf rule_docs/ docs/ + rm -f ./*.{zip,pkg} bazel.tar.gz bazel.tar.gz.sha256 swift package clean clean_xcode: From 0c9ea0e74054df7a28148fdc30a696e0fef4d056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 19:36:26 +0200 Subject: [PATCH 213/265] Add Swift 6 builds (#5810) --- .../SwiftVersionTests.swift | 4 +- azure-pipelines.yml | 43 ++++++++----------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift index 179849adaa..fb103a7b7e 100644 --- a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift +++ b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift @@ -3,7 +3,9 @@ import XCTest final class SwiftVersionTests: SwiftLintTestCase { func testDetectSwiftVersion() { -#if compiler(>=6.0.0) +#if compiler(>=6.0.1) + let version = "6.0.1" +#elseif compiler(>=6.0.0) let version = "6.0.0" #elseif compiler(>=5.10.1) let version = "5.10.1" diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 992185d397..f4e8aaa3d9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,47 +4,42 @@ trigger: jobs: - job: Linux pool: - vmImage: 'ubuntu-22.04' + vmImage: 'ubuntu-24.04' strategy: maxParallel: 10 matrix: - swift-5.10.1: - containerImage: swift:5.10.1 - container: $[ variables['containerImage'] ] + 'Swift 5.10.1': + image: swift:5.10.1-noble + 'Swift 6': + image: swift:6.0-noble + container: $[ variables['image'] ] steps: - script: swift test --parallel -Xswiftc -DDISABLE_FOCUSED_EXAMPLES displayName: swift test -- job: macOS13 - pool: - vmImage: 'macOS-13' +- job: macOS strategy: maxParallel: 10 + matrix: + '13': + image: 'macOS-13' + xcode: '15.2' + '14': + image: 'macOS-14' + xcode: '15.4' + pool: + vmImage: $(image) + variables: + DEVELOPER_DIR: /Applications/Xcode_$(xcode).app steps: - script: swift test --parallel -Xswiftc -DDISABLE_FOCUSED_EXAMPLES displayName: swift test -# TODO: Re-enable when FB11648454 is fixed -# - job: Xcode -# pool: -# vmImage: 'macOS-12' -# strategy: -# maxParallel: 10 -# matrix: -# xcode14: -# DEVELOPER_DIR: /Applications/Xcode_14.0.1.app -# steps: -# - script: | -# sw_vers -# xcodebuild -version -# displayName: Version Informations -# - script: xcodebuild -scheme swiftlint test -destination "platform=macOS" OTHER_SWIFT_FLAGS="\$(inherited) -D DISABLE_FOCUSED_EXAMPLES" -# displayName: xcodebuild test - job: CocoaPods pool: vmImage: 'macOS-14' variables: - DEVELOPER_DIR: /Applications/Xcode_15.4.app + DEVELOPER_DIR: /Applications/Xcode_16.app steps: - script: bundle install --path vendor/bundle displayName: bundle install From 36b88c5e88a513d644c66afc66cc409c9726601c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 20:15:31 +0200 Subject: [PATCH 214/265] Remove unused `testSimulateHomebrewTest` (#5812) This test has been inactive for the last 5 years and it doesn't run anymore. --- Tests/IntegrationTests/IntegrationTests.swift | 173 ------------------ 1 file changed, 173 deletions(-) diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index bbb8318ee9..fb6945ed47 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -69,64 +69,6 @@ final class IntegrationTests: SwiftLintTestCase { .appendingPathComponent("default_rule_configurations.yml") XCTAssertEqual(defaultConfig + "\n", try String(contentsOf: referenceFile)) } - - func testSimulateHomebrewTest() { - // Since this test uses the `swiftlint` binary built while building `SwiftLintPackageTests`, - // we run it only on macOS using SwiftPM. -#if os(macOS) && SWIFT_PACKAGE - let keyName = "SWIFTLINT_FRAMEWORK_TEST_ENABLE_SIMULATE_HOMEBREW_TEST" - guard ProcessInfo.processInfo.environment[keyName] != nil else { - print(""" - Skipping the opt-in test `\(#function)`. - Set the `\(keyName)` environment variable to test `\(#function)`. - """) - return - } - guard let swiftlintURL = swiftlintBuiltBySwiftPM(), - let (testSwiftURL, seatbeltURL) = prepareSandbox() else { - return - } - - defer { - try? FileManager.default.removeItem(at: testSwiftURL.deletingLastPathComponent()) - try? FileManager.default.removeItem(at: seatbeltURL) - } - - let swiftlintInSandboxArgs = [ - "sandbox-exec", "-f", seatbeltURL.path, "sh", "-c", - "SWIFTLINT_SWIFT_VERSION=5 \(swiftlintURL.path) --no-cache", - ] - let swiftlintResult = execute(swiftlintInSandboxArgs, in: testSwiftURL.deletingLastPathComponent()) - let statusWithoutCrash: Int32 = 0 - let stdoutWithoutCrash = """ - \(testSwiftURL.path):1:1: \ - warning: Trailing Newline Violation: Files should have a single trailing newline. (trailing_newline) - - """ - let stderrWithoutCrash = """ - Linting Swift files at paths \n\ - Linting 'Test.swift' (1/1) - Connection invalid - Most rules will be skipped because sourcekitd has failed. - Done linting! Found 1 violation, 0 serious in 1 file. - - """ - if #available(macOS 10.14.1, *) { - // Within a sandbox on macOS 10.14.1+, `swiftlint` crashes with "Test::Unit::AssertionFailedError" - // error in `libxpc.dylib` when calling `sourcekitd_send_request_sync`. - // - // Since Homebrew CI succeeded in bottling swiftlint 0.27.0 on release of macOS 10.14, - // `swiftlint` may not crash on macOS 10.14. But that is not confirmed. - XCTAssertNotEqual(swiftlintResult.status, statusWithoutCrash, "It is expected to crash.") - XCTAssertNotEqual(swiftlintResult.stdout, stdoutWithoutCrash) - XCTAssertNotEqual(swiftlintResult.stderr, stderrWithoutCrash) - } else { - XCTAssertEqual(swiftlintResult.status, statusWithoutCrash) - XCTAssertEqual(swiftlintResult.stdout, stdoutWithoutCrash) - XCTAssertEqual(swiftlintResult.stderr, stderrWithoutCrash) - } -#endif - } } private struct StaticStringImitator { @@ -162,118 +104,3 @@ private extension String { StaticStringImitator(string: self).withStaticString(closure) } } - -#if os(macOS) && SWIFT_PACKAGE - -private func execute(_ args: [String], - in directory: URL? = nil, - input: Data? = nil) -> (status: Int32, stdout: String, stderr: String) { - let process = Process() - process.launchPath = "/usr/bin/env" - process.arguments = args - if let directory { - process.currentDirectoryPath = directory.path - } - let stdoutPipe = Pipe(), stderrPipe = Pipe() - process.standardOutput = stdoutPipe - process.standardError = stderrPipe - if let input { - let stdinPipe = Pipe() - process.standardInput = stdinPipe.fileHandleForReading - stdinPipe.fileHandleForWriting.write(input) - stdinPipe.fileHandleForWriting.closeFile() - } - let group = DispatchGroup(), queue = DispatchQueue.global() - var stdoutData: Data?, stderrData: Data? - process.launch() - queue.async(group: group) { stdoutData = stdoutPipe.fileHandleForReading.readDataToEndOfFile() } - queue.async(group: group) { stderrData = stderrPipe.fileHandleForReading.readDataToEndOfFile() } - process.waitUntilExit() - group.wait() - let stdout = stdoutData.flatMap { String(data: $0, encoding: .utf8) } ?? "" - let stderr = stderrData.flatMap { String(data: $0, encoding: .utf8) } ?? "" - return (process.terminationStatus, stdout, stderr) -} - -private func prepareSandbox() -> (testSwiftURL: URL, seatbeltURL: URL)? { - // Since `/private/tmp` is hard coded in `/usr/local/Homebrew/Library/Homebrew/sandbox.rb`, we use them. - // /private/tmp - // ├── AADA6B05-2E06-4E7F-BA48-8B3AF44415E3 - // │   └── Test.swift - // ├── AADA6B05-2E06-4E7F-BA48-8B3AF44415E3.sb - do { - // `/private/tmp` is standardized to `/tmp` that is symbolic link to `/private/tmp`. - let temporaryDirectoryURL = URL(fileURLWithPath: "/tmp", isDirectory: true) - .appendingPathComponent(UUID().uuidString) - try FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: true) - - let seatbeltURL = temporaryDirectoryURL.appendingPathExtension("sb") - try sandboxProfile().write(to: seatbeltURL, atomically: true, encoding: .utf8) - - let testSwiftURL = temporaryDirectoryURL.appendingPathComponent("Test.swift") - try "import Foundation".write(to: testSwiftURL, atomically: true, encoding: .utf8) - return (testSwiftURL, seatbeltURL) - } catch { - XCTFail("\(error)") - return nil - } -} - -private func sandboxProfile() -> String { - let homeDirectory = NSHomeDirectory() - return """ - (version 1) - (debug deny) ; log all denied operations to /var/log/system.log - (allow file-write* (subpath "/private/tmp")) - (allow file-write* (subpath "/private/var/tmp")) - (allow file-write* (regex #"^/private/var/folders/[^/]+/[^/]+/[C,T]/")) - (allow file-write* (subpath "/private/tmp")) - (allow file-write* (subpath "\(homeDirectory)/Library/Caches/Homebrew")) - (allow file-write* (subpath "\(homeDirectory)/Library/Logs/Homebrew/swiftlint")) - (allow file-write* (subpath "\(homeDirectory)/Library/Developer")) - (allow file-write* (subpath "/usr/local/var/cache")) - (allow file-write* (subpath "/usr/local/var/homebrew/locks")) - (allow file-write* (subpath "/usr/local/var/log")) - (allow file-write* (subpath "/usr/local/var/run")) - (allow file-write* - (literal "/dev/ptmx") - (literal "/dev/dtracehelper") - (literal "/dev/null") - (literal "/dev/random") - (literal "/dev/zero") - (regex #"^/dev/fd/[0-9]+$") - (regex #"^/dev/ttys?[0-9]*$") - ) - (deny file-write*) ; deny all other file write operations - (allow process-exec - (literal "/bin/ps") - (with no-sandbox) - ) ; allow certain processes running without sandbox - (allow default) ; allow everything else - - """ -} - -private func swiftlintBuiltBySwiftPM() -> URL? { -#if DEBUG - let configuration = "debug" -#else - let configuration = "release" -#endif - let swiftBuildShowBinPathArgs = ["swift", "build", "--show-bin-path", "--configuration", configuration] - let binPathResult = execute(swiftBuildShowBinPathArgs) - guard binPathResult.status == 0 else { - let commandline = swiftBuildShowBinPathArgs.joined(separator: " ") - XCTFail("`\(commandline)` failed with status: \(binPathResult.status), error: \(binPathResult.stderr)") - return nil - } - let binPathString = binPathResult.stdout.components(separatedBy: CharacterSet.newlines).first! - let swiftlint = URL(fileURLWithPath: binPathString).appendingPathComponent("swiftlint") - guard FileManager.default.fileExists(atPath: swiftlint.path) else { - XCTFail("`swiftlint` does not exists.") - return nil - } - return swiftlint -} - -#endif From 1ec3fdc58d7f5a64145f24c317e04dc17b4432e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 20:23:17 +0200 Subject: [PATCH 215/265] Pass options to visitor (#5811) --- .../Configuration+CommandLine.swift | 41 ++++++----- .../LintOrAnalyzeCommand.swift | 9 +-- .../LintableFilesVisitor.swift | 69 +++++-------------- 3 files changed, 44 insertions(+), 75 deletions(-) diff --git a/Source/SwiftLintFramework/Configuration+CommandLine.swift b/Source/SwiftLintFramework/Configuration+CommandLine.swift index 49e62b9a69..6e2d1d526c 100644 --- a/Source/SwiftLintFramework/Configuration+CommandLine.swift +++ b/Source/SwiftLintFramework/Configuration+CommandLine.swift @@ -77,7 +77,7 @@ extension Configuration { -> [Configuration: [SwiftLintFile]] { if files.isEmpty && !visitor.allowZeroLintableFiles { throw SwiftLintError.usageError( - description: "No lintable files found at paths: '\(visitor.paths.joined(separator: ", "))'" + description: "No lintable files found at paths: '\(visitor.options.paths.joined(separator: ", "))'" ) } @@ -141,13 +141,13 @@ extension Configuration { let counter = CounterActor() let total = linters.filter(\.isCollecting).count let progress = ProgressBar(count: total) - if visitor.showProgressBar && total > 0 { + if visitor.options.progress && total > 0 { await progress.initialize() } let collect = { (linter: Linter) -> CollectedLinter? in let skipFile = visitor.shouldSkipFile(atPath: linter.file.path) - if !visitor.quiet && linter.isCollecting { - if visitor.showProgressBar { + if !visitor.options.quiet && linter.isCollecting { + if visitor.options.progress { await progress.printNext() } else if let filePath = linter.file.path { let outputFilename = self.outputFilename(for: filePath, duplicateFileNames: duplicateFileNames) @@ -185,17 +185,19 @@ extension Configuration { duplicateFileNames: Set) async -> [SwiftLintFile] { let counter = CounterActor() let progress = ProgressBar(count: linters.count) - if visitor.showProgressBar { + if visitor.options.progress { await progress.initialize() } let visit = { (linter: CollectedLinter) -> SwiftLintFile in - if !visitor.quiet { - if visitor.showProgressBar { + if !visitor.options.quiet { + if visitor.options.progress { await progress.printNext() } else if let filePath = linter.file.path { let outputFilename = self.outputFilename(for: filePath, duplicateFileNames: duplicateFileNames) let visited = await counter.next() - queuedPrintError("\(visitor.action) '\(outputFilename)' (\(visited)/\(linters.count))") + queuedPrintError( + "\(visitor.options.capitalizedVerb) '\(outputFilename)' (\(visited)/\(linters.count))" + ) } } @@ -210,45 +212,46 @@ extension Configuration { } fileprivate func getFiles(with visitor: LintableFilesVisitor) async throws -> [SwiftLintFile] { - if visitor.useSTDIN { + let options = visitor.options + if options.useSTDIN { let stdinData = FileHandle.standardInput.readDataToEndOfFile() if let stdinString = String(data: stdinData, encoding: .utf8) { return [SwiftLintFile(contents: stdinString)] } throw SwiftLintError.usageError(description: "stdin isn't a UTF8-encoded string") } - if visitor.useScriptInputFiles { + if options.useScriptInputFiles { let files = try scriptInputFiles() - guard visitor.forceExclude else { + guard options.forceExclude else { return files } let scriptInputPaths = files.compactMap(\.path) - if visitor.useExcludingByPrefix { + if options.useExcludingByPrefix { return filterExcludedPathsByPrefix(in: scriptInputPaths) .map(SwiftLintFile.init(pathDeferringReading:)) } return filterExcludedPaths(excludedPaths(), in: scriptInputPaths) .map(SwiftLintFile.init(pathDeferringReading:)) } - if !visitor.quiet { + if !options.quiet { let filesInfo: String - if visitor.paths.isEmpty || visitor.paths == [""] { + if options.paths.isEmpty || options.paths == [""] { filesInfo = "in current working directory" } else { - filesInfo = "at paths \(visitor.paths.joined(separator: ", "))" + filesInfo = "at paths \(options.paths.joined(separator: ", "))" } - queuedPrintError("\(visitor.action) Swift files \(filesInfo)") + queuedPrintError("\(options.capitalizedVerb) Swift files \(filesInfo)") } - let excludeLintableFilesBy = visitor.useExcludingByPrefix + let excludeLintableFilesBy = options.useExcludingByPrefix ? Configuration.ExcludeBy.prefix : .paths(excludedPaths: excludedPaths()) - return visitor.paths.flatMap { + return options.paths.flatMap { self.lintableFiles( inPath: $0, - forceExclude: visitor.forceExclude, + forceExclude: options.forceExclude, excludeBy: excludeLintableFilesBy) } } diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index b2d313233b..26ac2688ce 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -108,10 +108,11 @@ package struct LintOrAnalyzeOptions { } var verb: String { - if autocorrect { - return "correcting" - } - return mode.verb + autocorrect ? "correcting" : mode.verb + } + + var capitalizedVerb: String { + verb.capitalized } } diff --git a/Source/SwiftLintFramework/LintableFilesVisitor.swift b/Source/SwiftLintFramework/LintableFilesVisitor.swift index 97c5a2e535..c6c630e335 100644 --- a/Source/SwiftLintFramework/LintableFilesVisitor.swift +++ b/Source/SwiftLintFramework/LintableFilesVisitor.swift @@ -68,78 +68,43 @@ private func resolveParamsFiles(args: [String]) -> [String] { } struct LintableFilesVisitor { - let paths: [String] - let action: String - let useSTDIN: Bool - let quiet: Bool - let showProgressBar: Bool - let useScriptInputFiles: Bool - let forceExclude: Bool - let useExcludingByPrefix: Bool + let options: LintOrAnalyzeOptions let cache: LinterCache? - let parallel: Bool - let allowZeroLintableFiles: Bool let mode: LintOrAnalyzeModeWithCompilerArguments + let parallel: Bool let block: (CollectedLinter) async -> Void + let allowZeroLintableFiles: Bool - private init(paths: [String], - action: String, - useSTDIN: Bool, - quiet: Bool, - showProgressBar: Bool, - useScriptInputFiles: Bool, - forceExclude: Bool, - useExcludingByPrefix: Bool, + private init(options: LintOrAnalyzeOptions, cache: LinterCache?, - compilerInvocations: CompilerInvocations?, allowZeroLintableFiles: Bool, - block: @escaping (CollectedLinter) async -> Void) { - self.paths = resolveParamsFiles(args: paths) - self.action = action - self.useSTDIN = useSTDIN - self.quiet = quiet - self.showProgressBar = showProgressBar - self.useScriptInputFiles = useScriptInputFiles - self.forceExclude = forceExclude - self.useExcludingByPrefix = useExcludingByPrefix + block: @escaping (CollectedLinter) async -> Void) throws { + self.options = options self.cache = cache - if let compilerInvocations { - self.mode = .analyze(allCompilerInvocations: compilerInvocations) + if options.mode == .lint { + self.mode = .lint + self.parallel = true + } else { + self.mode = .analyze(allCompilerInvocations: try Self.loadCompilerInvocations(options)) // SourceKit had some changes in 5.6 that makes it ~100x more expensive // to process files concurrently. By processing files serially, it's // only 2x slower than before. self.parallel = SwiftVersion.current < .fiveDotSix - } else { - self.mode = .lint - self.parallel = true } - self.block = block self.allowZeroLintableFiles = allowZeroLintableFiles + self.block = block } static func create(_ options: LintOrAnalyzeOptions, cache: LinterCache?, allowZeroLintableFiles: Bool, - block: @escaping (CollectedLinter) async -> Void) - throws -> Self { + block: @escaping (CollectedLinter) async -> Void) throws -> Self { try Signposts.record(name: "LintableFilesVisitor.Create") { - let compilerInvocations: CompilerInvocations? - if options.mode == .lint { - compilerInvocations = nil - } else { - compilerInvocations = try loadCompilerInvocations(options) - } - - return Self( - paths: options.paths, action: options.verb.bridge().capitalized, - useSTDIN: options.useSTDIN, quiet: options.quiet, - showProgressBar: options.progress, - useScriptInputFiles: options.useScriptInputFiles, - forceExclude: options.forceExclude, - useExcludingByPrefix: options.useExcludingByPrefix, + try Self( + options: options, cache: cache, - compilerInvocations: compilerInvocations, - allowZeroLintableFiles: allowZeroLintableFiles, block: block + allowZeroLintableFiles: allowZeroLintableFiles, + block: block ) } } From ab699f98ae8fdb7eb3ae96463ecbf440d482efbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 21:19:23 +0200 Subject: [PATCH 216/265] Use async/await for URL session (#5814) --- .../LintOrAnalyzeCommand.swift | 2 +- Source/SwiftLintFramework/UpdateChecker.swift | 18 ++++-------------- Source/swiftlint/Commands/Version.swift | 2 +- azure-pipelines.yml | 2 -- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index 26ac2688ce..eeb59ee19c 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -144,7 +144,7 @@ package struct LintOrAnalyzeCommand { try postProcessViolations(files: files, builder: builder) } if options.checkForUpdates || builder.configuration.checkForUpdates { - UpdateChecker.checkForUpdates() + await UpdateChecker.checkForUpdates() } } diff --git a/Source/SwiftLintFramework/UpdateChecker.swift b/Source/SwiftLintFramework/UpdateChecker.swift index 81043ce36b..ad8db0538c 100644 --- a/Source/SwiftLintFramework/UpdateChecker.swift +++ b/Source/SwiftLintFramework/UpdateChecker.swift @@ -16,9 +16,9 @@ import FoundationNetworking #endif package enum UpdateChecker { - package static func checkForUpdates() { + package static func checkForUpdates() async { guard let url = URL(string: "https://api.github.com/repos/realm/SwiftLint/releases/latest"), - let data = sendRequest(to: url), + let data = try? await sendRequest(to: url), let latestVersionNumber = parseVersionNumber(data) else { print("Could not check latest SwiftLint version") return @@ -39,20 +39,10 @@ package enum UpdateChecker { return jsonObject["tag_name"] as? String } - private static func sendRequest(to url: URL) -> Data? { + private static func sendRequest(to url: URL) async throws -> Data { var request = URLRequest(url: url) request.setValue("SwiftLint", forHTTPHeaderField: "User-Agent") request.setValue("application/vnd.github.v3+json", forHTTPHeaderField: "Accept") - let semaphore = DispatchSemaphore(value: 0) - var result: Data? - - let task = URLSession.shared.dataTask(with: request) { data, _, _ in - result = data - semaphore.signal() - } - task.resume() - - semaphore.wait() - return result + return try await URLSession.shared.data(for: request).0 } } diff --git a/Source/swiftlint/Commands/Version.swift b/Source/swiftlint/Commands/Version.swift index aaa35dd897..0aa32567d1 100644 --- a/Source/swiftlint/Commands/Version.swift +++ b/Source/swiftlint/Commands/Version.swift @@ -20,7 +20,7 @@ extension SwiftLint { print(Self.value) } if checkForUpdates { - UpdateChecker.checkForUpdates() + await UpdateChecker.checkForUpdates() } ExitHelper.successfullyExit() } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f4e8aaa3d9..6fc1eb3f11 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,8 +8,6 @@ jobs: strategy: maxParallel: 10 matrix: - 'Swift 5.10.1': - image: swift:5.10.1-noble 'Swift 6': image: swift:6.0-noble container: $[ variables['image'] ] From b903e0bd8728d489f5cfeea650e272bb4d09bbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 21:22:07 +0200 Subject: [PATCH 217/265] Sync strict concurrency build settings (#5813) --- BUILD | 2 +- Package.swift | 10 ++++++---- Source/SwiftLintCore/Models/Issue.swift | 2 +- azure-pipelines.yml | 3 --- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/BUILD b/BUILD index 9dd4eacfee..fdcb795575 100644 --- a/BUILD +++ b/BUILD @@ -150,7 +150,7 @@ swift_binary( name = "swiftlint", package_name = "SwiftLint", srcs = glob(["Source/swiftlint/**/*.swift"]), - copts = copts, + copts = copts + strict_concurrency_copts, visibility = ["//visibility:public"], deps = [ ":SwiftLintFramework", diff --git a/Package.swift b/Package.swift index 0dfcc60a62..37a7f3fbe7 100644 --- a/Package.swift +++ b/Package.swift @@ -9,6 +9,7 @@ let swiftFeatures: [SwiftSetting] = [ .enableUpcomingFeature("ForwardTrailingClosures"), .enableUpcomingFeature("ImplicitOpenExistentials"), ] +let strictConcurrency = [SwiftSetting.enableExperimentalFeature("StrictConcurrency")] let swiftLintPluginDependencies: [Target.Dependency] @@ -55,7 +56,7 @@ let package = Package( "SwiftLintFramework", "SwiftyTextTable", ], - swiftSettings: swiftFeatures + swiftSettings: swiftFeatures + strictConcurrency ), .testTarget( name: "CLITests", @@ -88,7 +89,8 @@ let package = Package( ), .target( name: "SwiftLintExtraRules", - dependencies: ["SwiftLintCore"] + dependencies: ["SwiftLintCore"], + swiftSettings: strictConcurrency ), .target( name: "SwiftLintFramework", @@ -100,7 +102,7 @@ let package = Package( .product(name: "ArgumentParser", package: "swift-argument-parser"), "CollectionConcurrencyKit", ], - swiftSettings: swiftFeatures + swiftSettings: swiftFeatures + strictConcurrency ), .target(name: "DyldWarningWorkaround"), .target( @@ -155,7 +157,7 @@ let package = Package( .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), ], path: "Source/SwiftLintCoreMacros", - swiftSettings: swiftFeatures + swiftSettings: swiftFeatures + strictConcurrency ), .testTarget( name: "MacroTests", diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index bdb9fbfe94..0954bac837 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -75,7 +75,7 @@ public enum Issue: LocalizedError, Equatable { case baselineNotReadable(path: String) /// Flag to enable warnings for deprecations being printed to the console. Printing is enabled by default. - public static var printDeprecationWarnings = true + package nonisolated(unsafe) static var printDeprecationWarnings = true /// Hook used to capture all messages normally printed to stdout and return them back to the caller. /// diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6fc1eb3f11..3ec9125914 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,9 +19,6 @@ jobs: strategy: maxParallel: 10 matrix: - '13': - image: 'macOS-13' - xcode: '15.2' '14': image: 'macOS-14' xcode: '15.4' From b59e2daad0bc000c14ee38e94fa0a1d9df049729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 21:34:49 +0200 Subject: [PATCH 218/265] Build Docker image with Swift 6 on Ubuntu 24.04 --- .github/workflows/docker.yml | 2 +- Dockerfile | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ed6825e433..47f6f9f583 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -21,7 +21,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Set Docker tag diff --git a/Dockerfile b/Dockerfile index cef955886e..acc6c1e258 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ -# Explicitly specify `jammy` to keep the Swift & Ubuntu images in sync. -ARG BUILDER_IMAGE=swift:5.9-jammy -ARG RUNTIME_IMAGE=ubuntu:jammy +# Explicitly specify `noble` to keep the Swift & Ubuntu images in sync. +ARG BUILDER_IMAGE=swift:6.0-noble +ARG RUNTIME_IMAGE=ubuntu:noble # Builder image FROM ${BUILDER_IMAGE} AS builder From 4f2b03b43376098a1038665466e2657a89661166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 29 Sep 2024 23:35:31 +0200 Subject: [PATCH 219/265] Link to internal libraries --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index acc6c1e258..e802cd46a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,13 +15,13 @@ COPY Tests Tests/ COPY Package.* ./ RUN swift package update -ARG SWIFT_FLAGS="-c release -Xswiftc -static-stdlib -Xlinker -lCFURLSessionInterface -Xlinker -lCFXMLInterface -Xlinker -lcurl -Xlinker -lxml2 -Xswiftc -I. -Xlinker -fuse-ld=lld -Xlinker -L/usr/lib/swift/linux" +ARG SWIFT_FLAGS="-c release -Xswiftc -static-stdlib -Xlinker -l_CFURLSessionInterface -Xlinker -l_CFXMLInterface -Xlinker -lcurl -Xlinker -lxml2 -Xswiftc -I. -Xlinker -fuse-ld=lld -Xlinker -L/usr/lib/swift/linux" RUN swift build $SWIFT_FLAGS --product swiftlint RUN mv `swift build $SWIFT_FLAGS --show-bin-path`/swiftlint /usr/bin # Runtime image FROM ${RUNTIME_IMAGE} -LABEL org.opencontainers.image.source https://github.com/realm/SwiftLint +LABEL org.opencontainers.image.source=https://github.com/realm/SwiftLint RUN apt-get update && apt-get install -y \ libcurl4 \ libxml2 \ From 6d1cb6062143335280fd85ec80eb37168d1c4a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 30 Sep 2024 13:32:42 +0200 Subject: [PATCH 220/265] Copy more required dependencies --- Dockerfile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Dockerfile b/Dockerfile index e802cd46a0..146675d8e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,20 +30,31 @@ COPY --from=builder /usr/lib/libsourcekitdInProc.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftBasicFormat.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftCompilerPluginMessageHandling.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftDiagnostics.so /usr/lib +COPY --from=builder /usr/lib/swift/host/libSwiftIDEUtils.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftOperators.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftParser.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftParserDiagnostics.so /usr/lib +COPY --from=builder /usr/lib/swift/host/libSwiftRefactor.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftSyntax.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftSyntaxBuilder.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftSyntaxMacroExpansion.so /usr/lib COPY --from=builder /usr/lib/swift/host/libSwiftSyntaxMacros.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/lib_FoundationICU.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libBlocksRuntime.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libdispatch.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libFoundation.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libFoundationInternationalization.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libFoundationEssentials.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libFoundationNetworking.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libFoundationXML.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswift_Concurrency.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswift_RegexParser.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswift_StringProcessing.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswiftCore.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libswiftDispatch.so /usr/lib COPY --from=builder /usr/lib/swift/linux/libswiftGlibc.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libswiftSynchronization.so /usr/lib +COPY --from=builder /usr/lib/swift/linux/libswiftSwiftOnoneSupport.so /usr/lib COPY --from=builder /usr/bin/swiftlint /usr/bin RUN swiftlint version From c4a732583a01e4f389a1e6b8402dff4bc471431f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 30 Sep 2024 14:35:34 +0200 Subject: [PATCH 221/265] Wrap buffer to make it @Sendable (#5815) --- .../Extensions/Array+SwiftLint.swift | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift b/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift index e06fb18ea2..9981e91bdd 100644 --- a/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift +++ b/Source/SwiftLintCore/Extensions/Array+SwiftLint.swift @@ -103,10 +103,36 @@ public extension Array { func parallelMap(transform: (Element) -> T) -> [T] { var result = ContiguousArray(repeating: nil, count: count) return result.withUnsafeMutableBufferPointer { buffer in + let buffer = Wrapper(buffer: buffer) DispatchQueue.concurrentPerform(iterations: buffer.count) { idx in buffer[idx] = transform(self[idx]) } - return buffer.map { $0! } + return buffer.data + } + } + + private class Wrapper: @unchecked Sendable { + let buffer: UnsafeMutableBufferPointer + + init(buffer: UnsafeMutableBufferPointer) { + self.buffer = buffer + } + + var data: [T] { + buffer.map { $0! } + } + + var count: Int { + buffer.count + } + + subscript(index: Int) -> T { + get { + queuedFatalError("Do not call this getter.") + } + set(newValue) { + buffer[index] = newValue + } } } } From 63ee1944bd40ed50aaae3d8b1a8e2c60090f119f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 1 Oct 2024 17:25:03 +0200 Subject: [PATCH 222/265] Keep Swift 5 macOS build for the time being (#5816) --- Source/SwiftLintCore/Models/Issue.swift | 4 ++++ azure-pipelines.yml | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index 0954bac837..cb5e8615c4 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -75,7 +75,11 @@ public enum Issue: LocalizedError, Equatable { case baselineNotReadable(path: String) /// Flag to enable warnings for deprecations being printed to the console. Printing is enabled by default. + #if compiler(>=6.0) package nonisolated(unsafe) static var printDeprecationWarnings = true + #else + package static var printDeprecationWarnings = true + #endif /// Hook used to capture all messages normally printed to stdout and return them back to the caller. /// diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3ec9125914..6fc1eb3f11 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -19,6 +19,9 @@ jobs: strategy: maxParallel: 10 matrix: + '13': + image: 'macOS-13' + xcode: '15.2' '14': image: 'macOS-14' xcode: '15.4' From 88c2e4c1ce6033f6c242098ccf1a05ee219283f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 4 Oct 2024 15:29:29 +0200 Subject: [PATCH 223/265] Enable strict concurrency in built-in rules module (#5817) --- BUILD | 5 +---- Package.swift | 2 +- Source/SwiftLintFramework/LintOrAnalyzeCommand.swift | 3 +++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/BUILD b/BUILD index fdcb795575..02e28f9cb1 100644 --- a/BUILD +++ b/BUILD @@ -103,10 +103,7 @@ swift_library( name = "SwiftLintBuiltInRules", package_name = "SwiftLint", srcs = glob(["Source/SwiftLintBuiltInRules/**/*.swift"]), - copts = copts + select({ - ":strict_concurrency_builtin_rules": strict_concurrency_copts, - "//conditions:default": [], - }), + copts = copts + strict_concurrency_copts, module_name = "SwiftLintBuiltInRules", visibility = ["//visibility:public"], deps = [ diff --git a/Package.swift b/Package.swift index 37a7f3fbe7..2bad9f4e92 100644 --- a/Package.swift +++ b/Package.swift @@ -85,7 +85,7 @@ let package = Package( .target( name: "SwiftLintBuiltInRules", dependencies: ["SwiftLintCore"], - swiftSettings: swiftFeatures + swiftSettings: swiftFeatures + strictConcurrency ), .target( name: "SwiftLintExtraRules", diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index eeb59ee19c..8889fa3251 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -1,3 +1,6 @@ +#if os(macOS) +@preconcurrency import Darwin +#endif import Dispatch import Foundation From d22a719d76f2e13288d48d679673cf526b8d5198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 6 Oct 2024 22:51:40 +0200 Subject: [PATCH 224/265] Build with warnings as errors excluding SourceKitten (#5818) --- BUILD | 13 ++++++++++++- Source/SourceKittenFrameworkWrapper/Empty.swift | 0 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Source/SourceKittenFrameworkWrapper/Empty.swift diff --git a/BUILD b/BUILD index 02e28f9cb1..f6e1b93ccf 100644 --- a/BUILD +++ b/BUILD @@ -26,6 +26,7 @@ config_setting( ) copts = [ + "-warnings-as-errors", "-enable-upcoming-feature", "ExistentialAny", "-enable-upcoming-feature", @@ -90,7 +91,7 @@ swift_library( "@SwiftSyntax//:SwiftParserDiagnostics_opt", "@SwiftSyntax//:SwiftSyntaxBuilder_opt", "@SwiftSyntax//:SwiftSyntax_opt", - "@com_github_jpsim_sourcekitten//:SourceKittenFramework", + ":SourceKittenFramework.wrapper", "@sourcekitten_com_github_jpsim_yams//:Yams", "@swiftlint_com_github_scottrhoyt_swifty_text_table//:SwiftyTextTable", ] + select({ @@ -99,6 +100,16 @@ swift_library( }), ) +swift_library( + name = "SourceKittenFramework.wrapper", + srcs = ["Source/SourceKittenFrameworkWrapper/Empty.swift"], + module_name = "SourceKittenFrameworkWrapper", + visibility = ["//visibility:public"], + deps = [ + "@com_github_jpsim_sourcekitten//:SourceKittenFramework", + ], +) + swift_library( name = "SwiftLintBuiltInRules", package_name = "SwiftLint", diff --git a/Source/SourceKittenFrameworkWrapper/Empty.swift b/Source/SourceKittenFrameworkWrapper/Empty.swift new file mode 100644 index 0000000000..e69de29bb2 From 3b6ba6d1f042bc7baeb470da7417c7204aa9c9b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 7 Oct 2024 21:55:57 +0200 Subject: [PATCH 225/265] Fix warning for unused return value in Linux build (#5819) --- Source/swiftlint/Commands/SwiftLint.swift | 6 ++++- .../ConfigurationTests+MultipleConfigs.swift | 18 +++++++------- .../ConfigurationTests.swift | 24 +++++++++---------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Source/swiftlint/Commands/SwiftLint.swift b/Source/swiftlint/Commands/SwiftLint.swift index 7368b9a9d8..c0b0772533 100644 --- a/Source/swiftlint/Commands/SwiftLint.swift +++ b/Source/swiftlint/Commands/SwiftLint.swift @@ -10,7 +10,11 @@ import SwiftLintFramework struct SwiftLint: AsyncParsableCommand { static let configuration: CommandConfiguration = { if let directory = ProcessInfo.processInfo.environment["BUILD_WORKSPACE_DIRECTORY"] { - FileManager.default.changeCurrentDirectoryPath(directory) + if !FileManager.default.changeCurrentDirectoryPath(directory) { + queuedFatalError(""" + Could not change current directory to \(directory) specified by BUILD_WORKSPACE_DIRECTORY. + """) + } } RuleRegistry.registerAllRulesOnce() diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index 4351b19786..a5c1328741 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -237,7 +237,7 @@ extension ConfigurationTests { } for path in [Mock.Dir.childConfigTest1, Mock.Dir.childConfigTest2] { - FileManager.default.changeCurrentDirectoryPath(path) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(path)) assertEqualExceptForFileGraph( Configuration(configurationFiles: ["main.yml"]), @@ -248,7 +248,7 @@ extension ConfigurationTests { func testValidParentConfig() { for path in [Mock.Dir.parentConfigTest1, Mock.Dir.parentConfigTest2] { - FileManager.default.changeCurrentDirectoryPath(path) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(path)) assertEqualExceptForFileGraph( Configuration(configurationFiles: ["main.yml"]), @@ -263,7 +263,7 @@ extension ConfigurationTests { } for path in [Mock.Dir.childConfigTest1, Mock.Dir.childConfigTest2] { - FileManager.default.changeCurrentDirectoryPath(path) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(path)) assertEqualExceptForFileGraph( Configuration( @@ -283,7 +283,7 @@ extension ConfigurationTests { Mock.Dir.parentConfigCycle2, Mock.Dir.parentConfigCycle3, ] { - FileManager.default.changeCurrentDirectoryPath(path) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(path)) // If the cycle is properly detected, the config should equal the default config. XCTAssertEqual( @@ -294,7 +294,7 @@ extension ConfigurationTests { } func testCommandLineConfigsCycleDetection() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.childConfigCycle4) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.childConfigCycle4)) // If the cycle is properly detected, the config should equal the default config. assertEqualExceptForFileGraph( @@ -525,7 +525,7 @@ extension ConfigurationTests { // MARK: - Remote Configs func testValidRemoteChildConfig() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigChild) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigChild)) assertEqualExceptForFileGraph( Configuration( @@ -544,7 +544,7 @@ extension ConfigurationTests { } func testValidRemoteParentConfig() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigParent) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigParent)) assertEqualExceptForFileGraph( Configuration( @@ -569,7 +569,7 @@ extension ConfigurationTests { } func testsRemoteConfigNotAllowedToReferenceLocalConfig() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigLocalRef) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigLocalRef)) // If the remote file is not allowed to reference a local file, the config should equal the default config. XCTAssertEqual( @@ -589,7 +589,7 @@ extension ConfigurationTests { } func testRemoteConfigCycleDetection() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigCycle) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.remoteConfigCycle)) // If the cycle is properly detected, the config should equal the default config. XCTAssertEqual( diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index 16fe56e7cf..f0ea288ba0 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -15,12 +15,12 @@ final class ConfigurationTests: SwiftLintTestCase { super.setUp() Configuration.resetCache() previousWorkingDir = FileManager.default.currentDirectoryPath - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) } override func tearDown() { super.tearDown() - FileManager.default.changeCurrentDirectoryPath(previousWorkingDir) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(previousWorkingDir)) } // MARK: Tests @@ -37,7 +37,7 @@ final class ConfigurationTests: SwiftLintTestCase { func testNoConfiguration() { // Change to a folder where there is no `.swiftlint.yml` - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.emptyFolder) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.emptyFolder)) // Test whether the default configuration is used if there is no `.swiftlint.yml` or other config file XCTAssertEqual(Configuration(configurationFiles: []), Configuration.default) @@ -210,7 +210,7 @@ final class ConfigurationTests: SwiftLintTestCase { return } - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level1) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level1)) // The included path "File.swift" should be put relative to the configuration file // (~> Resources/ProjectMock/File.swift) and not relative to the path where @@ -230,7 +230,7 @@ final class ConfigurationTests: SwiftLintTestCase { func testIncludedExcludedRelativeLocationLevel0() { // Same as testIncludedPathRelatedToConfigurationFileLocationLevel1(), // but run from the directory the config file resides in - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration(configurationFiles: ["custom_included_excluded.yml"]) let actualIncludedPath = configuration.includedPaths.first!.bridge() .absolutePathRepresentation(rootDirectory: configuration.rootDirectory) @@ -345,7 +345,7 @@ final class ConfigurationTests: SwiftLintTestCase { } func testGlobIncludePaths() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration(includedPaths: ["**/Level2"]) let paths = configuration.lintablePaths(inPath: Mock.Dir.level0, forceExclude: true, @@ -468,7 +468,7 @@ final class ConfigurationTests: SwiftLintTestCase { // MARK: - ExcludeByPrefix option tests extension ConfigurationTests { func testExcludeByPrefixExcludedPaths() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration( includedPaths: ["Level1"], excludedPaths: ["Level1/Level1.swift", "Level1/Level2/Level3"] @@ -481,7 +481,7 @@ extension ConfigurationTests { } func testExcludeByPrefixForceExcludesFile() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration(excludedPaths: ["Level1/Level2/Level3/Level3.swift"]) let paths = configuration.lintablePaths(inPath: "Level1/Level2/Level3/Level3.swift", forceExclude: true, @@ -490,7 +490,7 @@ extension ConfigurationTests { } func testExcludeByPrefixForceExcludesFileNotPresentInExcluded() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration(includedPaths: ["Level1"], excludedPaths: ["Level1/Level1.swift"]) let paths = configuration.lintablePaths(inPath: "Level1", @@ -501,7 +501,7 @@ extension ConfigurationTests { } func testExcludeByPrefixForceExcludesDirectory() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration( excludedPaths: [ "Level1/Level2", "Directory.swift", "ChildConfig", "ParentConfig", "NestedConfig" @@ -515,7 +515,7 @@ extension ConfigurationTests { } func testExcludeByPrefixForceExcludesDirectoryThatIsNotInExcludedButHasChildrenThatAre() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration( excludedPaths: [ "Level1", "Directory.swift/DirectoryLevel1.swift", "ChildConfig", "ParentConfig", "NestedConfig" @@ -529,7 +529,7 @@ extension ConfigurationTests { } func testExcludeByPrefixGlobExcludePaths() { - FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0) + XCTAssert(FileManager.default.changeCurrentDirectoryPath(Mock.Dir.level0)) let configuration = Configuration( includedPaths: ["Level1"], excludedPaths: ["Level1/*/*.swift", "Level1/*/*/*.swift"]) From 0a1ee180da3787418fbcd3e85013b4ac04e48c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Mon, 7 Oct 2024 22:14:46 +0200 Subject: [PATCH 226/265] Separate build and copy steps from each other (#5820) --- tools/oss-check | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/tools/oss-check b/tools/oss-check index 1bf0c65e7c..77a70c8365 100755 --- a/tools/oss-check +++ b/tools/oss-check @@ -97,15 +97,12 @@ def fail(str) exit end -def perform(*args) - commands = args - if @options[:verbose] - commands.each do |x| - puts(x) - system(x) - end +def perform(command, dir: nil) + puts command if @options[:verbose] + if dir + Dir.chdir(dir) { perform(command) } else - commands.each { |x| `#{x}` } + system(command) end end @@ -208,24 +205,24 @@ def build(branch) dir = "#{@working_dir}/builds" target = branch == 'main' ? @effective_main_commitish : @options[:branch] if File.directory?(dir) - perform("cd #{dir}; git checkout #{target}") + perform("git checkout #{target}", dir: dir) else perform("git worktree add --detach #{dir} #{target}") end - build_command = "cd #{dir}; bazel build --config=release @SwiftLint//:swiftlint && mv bazel-bin/swiftlint swiftlint-#{branch}" - - perform(build_command) - return if $?.success? + build_command = "bazel build --config=release @SwiftLint//:swiftlint" return_value = nil puts build_command if @options[:verbose] - Open3.popen3(build_command) do |_, stdout, _, wait_thr| + Open3.popen3(build_command, :chdir=>"#{dir}") do |_, stdout, stderr, wait_thr| puts stdout.read.chomp + puts stderr.read.chomp return_value = wait_thr.value end fail "Could not build #{branch}" unless return_value.success? + + perform("mv bazel-bin/swiftlint swiftlint-#{branch}", dir: dir) end def diff_and_report_changes_to_danger From 9ebd6ae9d20798b111bd7088e3c247be4473b006 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Fri, 11 Oct 2024 19:15:48 +0100 Subject: [PATCH 227/265] Dont trigger for non-optional type casting, or for optional types (#5805) --- CHANGELOG.md | 5 ++++ .../Idiomatic/PreferTypeCheckingRule.swift | 26 ++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7257d37b63..3596e31d18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,11 @@ [chipp](https://github.com/chipp) [#5791](https://github.com/realm/SwiftLint/issues/5791) +* The `prefer_type_checking` rule will no longer trigger for non-optional + type casting (`as`), or for comparisons to optional types. + [Martin Redington](https://github.com/mildm8nnered) + [#5802](https://github.com/realm/SwiftLint/issues/5802) + ## 0.57.0: Squeaky Clean Cycle #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift index c0ae6731d7..c595dd0db8 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferTypeCheckingRule.swift @@ -24,6 +24,10 @@ struct PreferTypeCheckingRule: Rule { foo.run() } """), + Example("bar as Foo != nil"), + Example("nil != bar as Foo"), + Example("bar as Foo? != nil"), + Example("bar as? Foo? != nil"), ], triggeringExamples: [ Example("bar ↓as? Foo != nil"), @@ -33,9 +37,12 @@ struct PreferTypeCheckingRule: Rule { doSomeThing() } """), + Example("nil != bar ↓as? Foo"), + Example("nil != 2*x ↓as? X"), ], corrections: [ Example("bar ↓as? Foo != nil"): Example("bar is Foo"), + Example("nil != bar ↓as? Foo"): Example("bar is Foo"), Example("2*x ↓as? X != nil"): Example("2*x is X"), Example(""" if foo ↓as? Bar != nil { @@ -53,7 +60,7 @@ struct PreferTypeCheckingRule: Rule { private extension PreferTypeCheckingRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: InfixOperatorExprSyntax) { - if node.typeChecksWithAsCasting, let asExpr = node.leftOperand.as(AsExprSyntax.self) { + if let asExpr = node.asExprWithOptionalTypeChecking { violations.append(asExpr.asKeyword.positionAfterSkippingLeadingTrivia) } } @@ -61,8 +68,7 @@ private extension PreferTypeCheckingRule { final class Rewriter: ViolationsSyntaxRewriter { override func visit(_ node: InfixOperatorExprSyntax) -> ExprSyntax { - guard node.typeChecksWithAsCasting, - let asExpr = node.leftOperand.as(AsExprSyntax.self) else { + guard let asExpr = node.asExprWithOptionalTypeChecking else { return super.visit(node) } @@ -79,9 +85,15 @@ private extension PreferTypeCheckingRule { } private extension InfixOperatorExprSyntax { - var typeChecksWithAsCasting: Bool { - self.leftOperand.is(AsExprSyntax.self) - && self.operator.as(BinaryOperatorExprSyntax.self)?.operator.tokenKind == .binaryOperator("!=") - && self.rightOperand.is(NilLiteralExprSyntax.self) + var asExprWithOptionalTypeChecking: AsExprSyntax? { + if let asExpr = leftOperand.as(AsExprSyntax.self) ?? rightOperand.as(AsExprSyntax.self), + asExpr.questionOrExclamationMark?.tokenKind == .postfixQuestionMark, + !asExpr.type.is(OptionalTypeSyntax.self), + self.operator.as(BinaryOperatorExprSyntax.self)?.operator.tokenKind == .binaryOperator("!="), + rightOperand.is(NilLiteralExprSyntax.self) || leftOperand.is(NilLiteralExprSyntax.self) { + asExpr + } else { + nil + } } } From 9c2d0d5f86f29170ec5cc69235e3f1b5da6dac85 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Tue, 15 Oct 2024 18:56:39 +0100 Subject: [PATCH 228/265] Fix nested disable commands improved (#5797) --- CHANGELOG.md | 5 + Source/SwiftLintCore/Models/Linter.swift | 101 +++++++++++++----- .../SwiftLintCore/Models/RuleIdentifier.swift | 8 +- .../CustomRulesTests.swift | 77 +++++++++++++ 4 files changed, 166 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3596e31d18..e32680d436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,11 @@ [Martin Redington](https://github.com/mildm8nnered) [#5802](https://github.com/realm/SwiftLint/issues/5802) +* Fixes an issue where the `superfluous_disable_command` rule could generate + false positives for nested disable commands for custom rules. + [Martin Redington](https://github.com/mildm8nnered) + [#5788](https://github.com/realm/SwiftLint/issues/5788) + ## 0.57.0: Squeaky Clean Cycle #### Breaking diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index 23bfad7d54..c87065a557 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -1,6 +1,8 @@ import Foundation import SourceKittenFramework +// swiftlint:disable file_length + private let warnSourceKitFailedOnceImpl: Void = { Issue.genericWarning("SourceKit-based rules will be skipped because sourcekitd has failed.").print() }() @@ -23,6 +25,8 @@ private extension Rule { return [] } + let regions = regions.perIdentifierRegions + let regionsDisablingSuperfluousDisableRule = regions.filter { region in region.isRuleDisabled(superfluousDisableCommandRule) } @@ -32,33 +36,31 @@ private extension Rule { if regionsDisablingSuperfluousDisableRule.contains(where: { $0.contains(region.start) }) { continue } - let sortedDisabledIdentifiers = region.disabledRuleIdentifiers.sorted { - $0.stringRepresentation < $1.stringRepresentation + guard let disabledRuleIdentifier = region.disabledRuleIdentifiers.first else { + continue } - commandIDsLoop: for disabledIdentifier in sortedDisabledIdentifiers { - guard !isEnabled(in: region, for: disabledIdentifier.stringRepresentation) else { - continue - } - var disableCommandValid = false - for violation in allViolations where region.contains(violation.location) { - if canBeDisabled(violation: violation, by: disabledIdentifier) { - disableCommandValid = true - continue commandIDsLoop - } + guard !isEnabled(in: region, for: disabledRuleIdentifier.stringRepresentation) else { + continue + } + var disableCommandValid = false + for violation in allViolations where region.contains(violation.location) { + if canBeDisabled(violation: violation, by: disabledRuleIdentifier) { + disableCommandValid = true + break } - if !disableCommandValid { - let reason = superfluousDisableCommandRule.reason( - forRuleIdentifier: disabledIdentifier.stringRepresentation - ) - superfluousDisableCommandViolations.append( - StyleViolation( - ruleDescription: type(of: superfluousDisableCommandRule).description, - severity: superfluousDisableCommandRule.configuration.severity, - location: region.start, - reason: reason - ) + } + if !disableCommandValid { + let reason = superfluousDisableCommandRule.reason( + forRuleIdentifier: disabledRuleIdentifier.stringRepresentation + ) + superfluousDisableCommandViolations.append( + StyleViolation( + ruleDescription: type(of: superfluousDisableCommandRule).description, + severity: superfluousDisableCommandRule.configuration.severity, + location: region.start, + reason: reason ) - } + ) } } return superfluousDisableCommandViolations @@ -147,6 +149,57 @@ private extension Rule { } } +private extension [Region] { + // Normally regions correspond to changes in the set of enabled rules. To detect superfluous disable command + // rule violations effectively, we need individual regions for each disabled rule identifier. + var perIdentifierRegions: [Region] { + guard isNotEmpty else { + return [] + } + + var convertedRegions = [Region]() + var startMap: [RuleIdentifier: Location] = [:] + var lastRegionEnd: Location? + + for region in self { + let ruleIdentifiers = startMap.keys.sorted() + for ruleIdentifier in ruleIdentifiers where !region.disabledRuleIdentifiers.contains(ruleIdentifier) { + if let lastRegionEnd, let start = startMap[ruleIdentifier] { + let newRegion = Region(start: start, end: lastRegionEnd, disabledRuleIdentifiers: [ruleIdentifier]) + convertedRegions.append(newRegion) + startMap[ruleIdentifier] = nil + } + } + for ruleIdentifier in region.disabledRuleIdentifiers where startMap[ruleIdentifier] == nil { + startMap[ruleIdentifier] = region.start + } + if region.disabledRuleIdentifiers.isEmpty { + convertedRegions.append(region) + } + lastRegionEnd = region.end + } + + let end = Location(file: first?.start.file, line: .max, character: .max) + for ruleIdentifier in startMap.keys.sorted() { + if let start = startMap[ruleIdentifier] { + let newRegion = Region(start: start, end: end, disabledRuleIdentifiers: [ruleIdentifier]) + convertedRegions.append(newRegion) + startMap[ruleIdentifier] = nil + } + } + + return convertedRegions.sorted { + if $0.start == $1.start { + if let lhsDisabledRuleIdentifier = $0.disabledRuleIdentifiers.first, + let rhsDisabledRuleIdentifier = $1.disabledRuleIdentifiers.first { + return lhsDisabledRuleIdentifier < rhsDisabledRuleIdentifier + } + } + return $0.start < $1.start + } + } +} + /// Represents a file that can be linted for style violations and corrections after being collected. public struct Linter { /// The file to lint with this linter. diff --git a/Source/SwiftLintCore/Models/RuleIdentifier.swift b/Source/SwiftLintCore/Models/RuleIdentifier.swift index c4ee97f5ba..8955c8badf 100644 --- a/Source/SwiftLintCore/Models/RuleIdentifier.swift +++ b/Source/SwiftLintCore/Models/RuleIdentifier.swift @@ -1,5 +1,5 @@ /// An identifier representing a SwiftLint rule, or all rules. -public enum RuleIdentifier: Hashable, ExpressibleByStringLiteral { +public enum RuleIdentifier: Hashable, ExpressibleByStringLiteral, Comparable { // MARK: - Values /// Special identifier that should be treated as referring to 'all' SwiftLint rules. One helpful usecase is in @@ -39,4 +39,10 @@ public enum RuleIdentifier: Hashable, ExpressibleByStringLiteral { public init(stringLiteral value: String) { self = Self(value) } + + // MARK: - Comparable Conformance + + public static func < (lhs: Self, rhs: Self) -> Bool { + lhs.stringRepresentation < rhs.stringRepresentation + } } diff --git a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift index 3337822047..548fb98db2 100644 --- a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift @@ -427,6 +427,83 @@ final class CustomRulesTests: SwiftLintTestCase { XCTAssertTrue(try violations(forExample: example, customRules: customRules).isEmpty) } + func testNestedCustomRuleDisablesDoNotTriggerSuperfluousDisableCommand() throws { + let customRules: [String: Any] = [ + "rule1": [ + "regex": "pattern1" + ], + "rule2": [ + "regex": "pattern2" + ], + ] + let example = Example(""" + // swiftlint:disable rule1 + // swiftlint:disable rule2 + let pattern2 = "" + // swiftlint:enable rule2 + let pattern1 = "" + // swiftlint:enable rule1 + """) + XCTAssertTrue(try violations(forExample: example, customRules: customRules).isEmpty) + } + + func testNestedAndOverlappingCustomRuleDisables() throws { + let customRules: [String: Any] = [ + "rule1": [ + "regex": "pattern1" + ], + "rule2": [ + "regex": "pattern2" + ], + "rule3": [ + "regex": "pattern3" + ], + ] + let example = Example(""" + // swiftlint:disable rule1 + // swiftlint:disable rule2 + // swiftlint:disable rule3 + let pattern2 = "" + // swiftlint:enable rule2 + // swiftlint:enable rule3 + let pattern1 = "" + // swiftlint:enable rule1 + """) + let violations = try violations(forExample: example, customRules: customRules) + + XCTAssertEqual(violations.count, 1) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "rule3")) + } + + func testSuperfluousDisableRuleOrder() throws { + let customRules: [String: Any] = [ + "rule1": [ + "regex": "pattern1" + ], + "rule2": [ + "regex": "pattern2" + ], + "rule3": [ + "regex": "pattern3" + ], + ] + let example = Example(""" + // swiftlint:disable rule1 + // swiftlint:disable rule2 rule3 + // swiftlint:enable rule3 rule2 + // swiftlint:disable rule2 + // swiftlint:enable rule1 + // swiftlint:enable rule2 + """) + let violations = try violations(forExample: example, customRules: customRules) + + XCTAssertEqual(violations.count, 4) + XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "rule1")) + XCTAssertTrue(violations[1].isSuperfluousDisableCommandViolation(for: "rule2")) + XCTAssertTrue(violations[2].isSuperfluousDisableCommandViolation(for: "rule3")) + XCTAssertTrue(violations[3].isSuperfluousDisableCommandViolation(for: "rule2")) + } + // MARK: - Private private func getCustomRules(_ extraConfig: [String: Any] = [:]) -> (Configuration, CustomRules) { From 5070b8257c0adb9e06ee43122aa9f5b91ecb2623 Mon Sep 17 00:00:00 2001 From: timesince Date: Fri, 18 Oct 2024 04:34:19 +0800 Subject: [PATCH 229/265] Remove unnecessary symbol (#5827) --- .../Extensions/RandomAccessCollection+Swiftlint.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/SwiftLintCore/Extensions/RandomAccessCollection+Swiftlint.swift b/Source/SwiftLintCore/Extensions/RandomAccessCollection+Swiftlint.swift index 1678cb8f3f..e347d3f38b 100644 --- a/Source/SwiftLintCore/Extensions/RandomAccessCollection+Swiftlint.swift +++ b/Source/SwiftLintCore/Extensions/RandomAccessCollection+Swiftlint.swift @@ -24,7 +24,7 @@ public extension RandomAccessCollection where Index == Int { @inlinable func firstIndexAssumingSorted(where predicate: (Self.Element) throws -> Bool) rethrows -> Int? { // Predicate should divide a collection to two pairs of values - // "bad" values for which predicate returns `false`` + // "bad" values for which predicate returns `false` // "good" values for which predicate return `true` // false false false false false true true true From 7385beaaf6579c67f74d4437cece2f9214de2c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 17 Oct 2024 23:13:17 +0200 Subject: [PATCH 230/265] Add validation hook to configuration parsing (#5824) --- Source/SwiftLintCore/Models/Issue.swift | 13 ++++++++++--- .../SwiftLintCore/Protocols/RuleConfiguration.swift | 8 ++++++++ .../RuleConfigurationMacros.swift | 3 +++ Tests/MacroTests/AutoConfigParserTests.swift | 5 +++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Source/SwiftLintCore/Models/Issue.swift b/Source/SwiftLintCore/Models/Issue.swift index cb5e8615c4..2a35b36863 100644 --- a/Source/SwiftLintCore/Models/Issue.swift +++ b/Source/SwiftLintCore/Models/Issue.swift @@ -3,7 +3,7 @@ import Foundation /// All possible SwiftLint issues which are printed as warnings by default. public enum Issue: LocalizedError, Equatable { /// The configuration didn't match internal expectations. - case invalidConfiguration(ruleID: String) + case invalidConfiguration(ruleID: String, message: String? = nil) /// Issued when an option is deprecated. Suggests an alternative optionally. case deprecatedConfigurationOption(ruleID: String, key: String, alternative: String? = nil) @@ -20,6 +20,10 @@ public enum Issue: LocalizedError, Equatable { /// Some configuration keys are invalid. case invalidConfigurationKeys(ruleID: String, keys: Set) + /// The configuration is inconsistent, that is options are mutually exclusive or one drives other values + /// irrelevant. + case inconsistentConfiguration(ruleID: String, message: String) + /// Used rule IDs are invalid. case invalidRuleIDs(Set) @@ -138,8 +142,9 @@ public enum Issue: LocalizedError, Equatable { private var message: String { switch self { - case let .invalidConfiguration(id): - return "Invalid configuration for '\(id)' rule. Falling back to default." + case let .invalidConfiguration(id, message): + let message = if let message { ": \(message)" } else { "." } + return "Invalid configuration for '\(id)' rule\(message) Falling back to default." case let .deprecatedConfigurationOption(id, key, alternative): let baseMessage = "Configuration option '\(key)' in '\(id)' rule is deprecated." if let alternative { @@ -154,6 +159,8 @@ public enum Issue: LocalizedError, Equatable { return "'\(old)' has been renamed to '\(new)' and will be completely removed in a future release." case let .invalidConfigurationKeys(id, keys): return "Configuration for '\(id)' rule contains the invalid key(s) \(keys.formatted)." + case let .inconsistentConfiguration(id, message): + return "Inconsistent configuration for '\(id)' rule: \(message)" case let .invalidRuleIDs(ruleIDs): return "The key(s) \(ruleIDs.formatted) used as rule identifier(s) is/are invalid." case let .ruleNotPresentInOnlyRules(id): diff --git a/Source/SwiftLintCore/Protocols/RuleConfiguration.swift b/Source/SwiftLintCore/Protocols/RuleConfiguration.swift index acdd2b6359..c750417df4 100644 --- a/Source/SwiftLintCore/Protocols/RuleConfiguration.swift +++ b/Source/SwiftLintCore/Protocols/RuleConfiguration.swift @@ -13,6 +13,10 @@ public protocol RuleConfiguration: Equatable { /// /// - throws: Throws if the configuration is not in the expected format. mutating func apply(configuration: Any) throws + + /// Run a sanity check on the configuration, perform optional postprocessing steps and/or warn about potential + /// issues. + mutating func validate() throws } /// A configuration for a rule that allows to configure at least the severity. @@ -30,6 +34,10 @@ public extension SeverityBasedRuleConfiguration { public extension RuleConfiguration { var parameterDescription: RuleConfigurationDescription? { nil } + + func validate() throws { + // Do nothing by default. + } } public extension RuleConfiguration { diff --git a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift index e1a44256e8..51ba4427d7 100644 --- a/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift +++ b/Source/SwiftLintCoreMacros/RuleConfigurationMacros.swift @@ -85,6 +85,9 @@ enum AutoConfigParser: MemberMacro { Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } """ + """ + try validate() + """ }), ] } diff --git a/Tests/MacroTests/AutoConfigParserTests.swift b/Tests/MacroTests/AutoConfigParserTests.swift index 4164eb411f..86ce276120 100644 --- a/Tests/MacroTests/AutoConfigParserTests.swift +++ b/Tests/MacroTests/AutoConfigParserTests.swift @@ -44,6 +44,7 @@ final class AutoConfigParserTests: XCTestCase { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } + try validate() } } """, @@ -90,6 +91,7 @@ final class AutoConfigParserTests: XCTestCase { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } + try validate() } } """, @@ -145,6 +147,7 @@ final class AutoConfigParserTests: XCTestCase { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } + try validate() } } """, @@ -171,6 +174,7 @@ final class AutoConfigParserTests: XCTestCase { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } + try validate() } } """, @@ -228,6 +232,7 @@ final class AutoConfigParserTests: XCTestCase { let unknownKeys = Set(configuration.keys).subtracting(supportedKeys) Issue.invalidConfigurationKeys(ruleID: Parent.identifier, keys: unknownKeys).print() } + try validate() } } """, From b4866488faa79d8b1369cae925f7daa133705809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 19 Oct 2024 19:56:59 +0200 Subject: [PATCH 231/265] Remove workaround (#5830) --- Package.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Package.swift b/Package.swift index 2bad9f4e92..2789c2fef6 100644 --- a/Package.swift +++ b/Package.swift @@ -98,8 +98,6 @@ let package = Package( "SwiftLintBuiltInRules", "SwiftLintCore", "SwiftLintExtraRules", - // Workaround for https://github.com/apple/swift-package-manager/issues/6940: - .product(name: "ArgumentParser", package: "swift-argument-parser"), "CollectionConcurrencyKit", ], swiftSettings: swiftFeatures + strictConcurrency From d4b41bc53b5ff2d2490f51196f5658eb4c0d9473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Thu, 24 Oct 2024 18:50:18 +0200 Subject: [PATCH 232/265] Stop triggering on `self` in key path expressions (#5836) --- CHANGELOG.md | 5 +++++ .../SelfInPropertyInitializationRule.swift | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e32680d436..3ca68bc5cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5787](https://github.com/realm/SwiftLint/issues/5787) +* Do not trigger `self_in_property_initialization` rule on `self` in + key paths expressions. + [SimplyDanny](https://github.com/SimplyDanny) + [#5835](https://github.com/realm/SwiftLint/issues/5835) + * Do not throw deprecation warning if deprecated property is not presented in configuration. [chipp](https://github.com/chipp) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift index cc39c1962b..74082ee95c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/SelfInPropertyInitializationRule.swift @@ -68,6 +68,12 @@ struct SelfInPropertyInitializationRule: Rule { func calculateB() -> String { "B" } } """, excludeFromDocumentation: true), + Example(""" + final class NotActuallyReferencingSelf { + let keyPath: Any = \\String.self + let someType: Any = String.self + } + """, excludeFromDocumentation: true), ], triggeringExamples: [ Example(""" @@ -102,7 +108,7 @@ private extension SelfInPropertyInitializationRule { return } - let visitor = IdentifierUsageVisitor(identifier: .keyword(.self)) + let visitor = IdentifierUsageVisitor(viewMode: .sourceAccurate) for binding in node.bindings { guard let initializer = binding.initializer, visitor.walk(tree: initializer.value, handler: \.isTokenUsed) else { @@ -116,16 +122,12 @@ private extension SelfInPropertyInitializationRule { } private final class IdentifierUsageVisitor: SyntaxVisitor { - let identifier: TokenKind private(set) var isTokenUsed = false - init(identifier: TokenKind) { - self.identifier = identifier - super.init(viewMode: .sourceAccurate) - } - override func visitPost(_ node: DeclReferenceExprSyntax) { - if node.baseName.tokenKind == identifier, node.keyPathInParent != \MemberAccessExprSyntax.declName { + if node.baseName.tokenKind == .keyword(.self), + node.keyPathInParent != \MemberAccessExprSyntax.declName, + node.keyPathInParent != \KeyPathPropertyComponentSyntax.declName { isTokenUsed = true } } From e87efff39b62b1a37984d775c2f74a6eedb3f71b Mon Sep 17 00:00:00 2001 From: BlueVirusX Date: Fri, 25 Oct 2024 12:57:41 +0200 Subject: [PATCH 233/265] Support Xcode input file lists (#5790) Adds the option `--use-script-input-file-lists` and parsing for `.xcfilelist` files. --- CHANGELOG.md | 5 ++ README.md | 5 ++ .../Configuration+CommandLine.swift | 56 +++++++++++++++---- .../LintOrAnalyzeCommand.swift | 3 + Source/swiftlint/Commands/Analyze.swift | 1 + Source/swiftlint/Commands/Lint.swift | 1 + .../Common/LintOrAnalyzeArguments.swift | 2 + 7 files changed, 61 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ca68bc5cc..b87e71e2c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ [Jordan Rose](https://github.com/jrose-signal) [SimplyDanny](https://github.com/SimplyDanny) +* Support reading files to lint from Input File Lists provided + by Run Script Build Phases in Xcode using the command-line + argument `--use-script-input-file-lists`. + [BlueVirusX](https://github.com/BlueVirusX) + #### Bug Fixes * Run command plugin in whole package if no targets are defined in the diff --git a/README.md b/README.md index e5868b1cec..2d37e03326 100644 --- a/README.md +++ b/README.md @@ -514,6 +514,11 @@ can do so by passing the option `--use-script-input-files` and setting the following instance variables: `SCRIPT_INPUT_FILE_COUNT` and `SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`, ..., `SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT - 1}`. +Similarly, files can be read from file lists by passing +the option `--use-script-input-file-lists` and setting the +following instance variables: `SCRIPT_INPUT_FILE_LIST_COUNT` +and `SCRIPT_INPUT_FILE_LIST_0`, `SCRIPT_INPUT_FILE_LIST_1`, ..., +`SCRIPT_INPUT_FILE_LIST_{SCRIPT_INPUT_FILE_LIST_COUNT - 1}`. These are same environment variables set for input files to [custom Xcode script phases](http://indiestack.com/2014/12/speeding-up-custom-script-phases/). diff --git a/Source/SwiftLintFramework/Configuration+CommandLine.swift b/Source/SwiftLintFramework/Configuration+CommandLine.swift index 6e2d1d526c..c24f5c9c55 100644 --- a/Source/SwiftLintFramework/Configuration+CommandLine.swift +++ b/Source/SwiftLintFramework/Configuration+CommandLine.swift @@ -11,16 +11,8 @@ private actor CounterActor { } } -private func scriptInputFiles() throws -> [SwiftLintFile] { - let inputFileKey = "SCRIPT_INPUT_FILE_COUNT" - guard let countString = ProcessInfo.processInfo.environment[inputFileKey] else { - throw SwiftLintError.usageError(description: "\(inputFileKey) variable not set") - } - - guard let count = Int(countString) else { - throw SwiftLintError.usageError(description: "\(inputFileKey) did not specify a number") - } - +private func readFilesFromScriptInputFiles() throws -> [SwiftLintFile] { + let count = try fileCount(from: "SCRIPT_INPUT_FILE_COUNT") return (0.. [SwiftLintFile] { } } +private func readFilesFromScriptInputFileLists() throws -> [SwiftLintFile] { + let count = try fileCount(from: "SCRIPT_INPUT_FILE_LIST_COUNT") + return (0.. Int { + guard let countString = ProcessInfo.processInfo.environment[envVar] else { + throw SwiftLintError.usageError(description: "\(envVar) variable not set") + } + guard let count = Int(countString) else { + throw SwiftLintError.usageError(description: "\(envVar) did not specify a number") + } + return count +} + #if os(Linux) private func autoreleasepool(block: () -> T) -> T { block() } #endif @@ -220,8 +250,10 @@ extension Configuration { } throw SwiftLintError.usageError(description: "stdin isn't a UTF8-encoded string") } - if options.useScriptInputFiles { - let files = try scriptInputFiles() + if options.useScriptInputFiles || options.useScriptInputFileLists { + let files = try options.useScriptInputFiles + ? readFilesFromScriptInputFiles() + : readFilesFromScriptInputFileLists() guard options.forceExclude else { return files } diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index 8889fa3251..7afeef8abf 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -38,6 +38,7 @@ package struct LintOrAnalyzeOptions { let forceExclude: Bool let useExcludingByPrefix: Bool let useScriptInputFiles: Bool + let useScriptInputFileLists: Bool let benchmark: Bool let reporter: String? let baseline: String? @@ -65,6 +66,7 @@ package struct LintOrAnalyzeOptions { forceExclude: Bool, useExcludingByPrefix: Bool, useScriptInputFiles: Bool, + useScriptInputFileLists: Bool, benchmark: Bool, reporter: String?, baseline: String?, @@ -91,6 +93,7 @@ package struct LintOrAnalyzeOptions { self.forceExclude = forceExclude self.useExcludingByPrefix = useExcludingByPrefix self.useScriptInputFiles = useScriptInputFiles + self.useScriptInputFileLists = useScriptInputFileLists self.benchmark = benchmark self.reporter = reporter self.baseline = baseline diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index d000077baa..7ff786edec 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -31,6 +31,7 @@ extension SwiftLint { forceExclude: common.forceExclude, useExcludingByPrefix: common.useAlternativeExcluding, useScriptInputFiles: common.useScriptInputFiles, + useScriptInputFileLists: common.useScriptInputFileLists, benchmark: common.benchmark, reporter: common.reporter, baseline: common.baseline, diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index 27911e6fb5..eadc1ab416 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -43,6 +43,7 @@ extension SwiftLint { forceExclude: common.forceExclude, useExcludingByPrefix: common.useAlternativeExcluding, useScriptInputFiles: common.useScriptInputFiles, + useScriptInputFileLists: common.useScriptInputFileLists, benchmark: common.benchmark, reporter: common.reporter, baseline: common.baseline, diff --git a/Source/swiftlint/Common/LintOrAnalyzeArguments.swift b/Source/swiftlint/Common/LintOrAnalyzeArguments.swift index 8b9b00eba5..2e545aa7ae 100644 --- a/Source/swiftlint/Common/LintOrAnalyzeArguments.swift +++ b/Source/swiftlint/Common/LintOrAnalyzeArguments.swift @@ -31,6 +31,8 @@ struct LintOrAnalyzeArguments: ParsableArguments { var useAlternativeExcluding = false @Flag(help: "Read SCRIPT_INPUT_FILE* environment variables as files.") var useScriptInputFiles = false + @Flag(help: "Read SCRIPT_INPUT_FILE_LIST* environment variables as file lists.") + var useScriptInputFileLists = false @Flag(exclusivity: .exclusive) var leniency: LeniencyOptions? @Flag(help: "Exclude files in config `excluded` even if their paths are explicitly specified.") From 9ea4374145dbd48a97eacf054987e899f59f8ab4 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Fri, 25 Oct 2024 17:19:17 +0100 Subject: [PATCH 234/265] Fix `--only-rule` config issues (#5773) --- CHANGELOG.md | 9 +++ .../Extensions/Configuration+FileGraph.swift | 4 +- .../Extensions/Configuration+Parsing.swift | 20 +++--- .../Extensions/Configuration+RulesMode.swift | 47 ++++++++------ .../Configuration+RulesWrapper.swift | 50 +++++++++------ .../SwiftLintCore/Models/Configuration.swift | 12 +++- .../LintOrAnalyzeCommand.swift | 4 +- Source/swiftlint/Commands/Analyze.swift | 10 ++- Source/swiftlint/Commands/Lint.swift | 10 ++- Tests/IntegrationTests/IntegrationTests.swift | 2 +- .../CollectingRuleTests.swift | 2 +- .../CommandTests.swift | 6 +- .../ConfigurationTests+MultipleConfigs.swift | 62 +++++++++++++------ .../ConfigurationTests.swift | 29 +++++++-- .../SourceKitCrashTests.swift | 2 +- Tests/SwiftLintTestHelpers/TestHelpers.swift | 8 +-- 16 files changed, 186 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b87e71e2c9..9148f4f3dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,15 @@ [Martin Redington](https://github.com/mildm8nnered) [#5788](https://github.com/realm/SwiftLint/issues/5788) +* Fixes the `--only-rule` command line option, when a default `.swiftlint.yml` + is absent. Additionally rules specified with `--only-rule` on the command + line can now be disabled in a child configuration, to allow specific + directories to be excluded from the rule (or from being auto-corrected by + the rule), and `--only-rule` can now be specified multiple times + to run multiple rules. + [Martin Redington](https://github.com/mildm8nnered) + [#5711](https://github.com/realm/SwiftLint/issues/5711) + ## 0.57.0: Squeaky Clean Cycle #### Breaking diff --git a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift index 4c151e8ab3..464553659e 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+FileGraph.swift @@ -41,7 +41,7 @@ package extension Configuration { // MARK: - Methods internal mutating func resultingConfiguration( enableAllRules: Bool, - onlyRule: String?, + onlyRule: [String], cachePath: String? ) throws -> Configuration { // Build if needed @@ -250,7 +250,7 @@ package extension Configuration { private func merged( configurationData: [(configurationDict: [String: Any], rootDirectory: String)], enableAllRules: Bool, - onlyRule: String?, + onlyRule: [String], cachePath: String? ) throws -> Configuration { // Split into first & remainder; use empty dict for first if the array is empty diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 232cf0ae72..1528591840 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -42,7 +42,7 @@ extension Configuration { dict: [String: Any], ruleList: RuleList = RuleRegistry.shared.list, enableAllRules: Bool = false, - onlyRule: String? = nil, + onlyRule: [String] = [], cachePath: String? = nil ) throws { func defaultStringArray(_ object: Any?) -> [String] { [String].array(of: object) ?? [] } @@ -81,7 +81,7 @@ extension Configuration { analyzerRules: analyzerRules ) - if onlyRule == nil { + if onlyRule.isEmpty { Self.validateConfiguredRulesAreEnabled( parentConfiguration: parentConfiguration, configurationDictionary: dict, @@ -174,12 +174,12 @@ extension Configuration { } switch rulesMode { - case .allEnabled: + case .allCommandLine, .onlyCommandLine: return - case .only(let onlyRules): + case .onlyConfiguration(let onlyRules): let issue = validateConfiguredRuleIsEnabled(onlyRules: onlyRules, ruleType: ruleType) issue?.print() - case let .default(disabled: disabledRules, optIn: optInRules): + case let .defaultConfiguration(disabled: disabledRules, optIn: optInRules): let issue = validateConfiguredRuleIsEnabled( parentConfiguration: parentConfiguration, disabledRules: disabledRules, @@ -201,9 +201,11 @@ extension Configuration { var disabledInParentRules: Set = [] var allEnabledRules: Set = [] - if case .only(let onlyRules) = parentConfiguration?.rulesMode { + if case .onlyConfiguration(let onlyRules) = parentConfiguration?.rulesMode { enabledInParentRules = onlyRules - } else if case .default(let parentDisabledRules, let parentOptInRules) = parentConfiguration?.rulesMode { + } else if case .defaultConfiguration( + let parentDisabledRules, let parentOptInRules + ) = parentConfiguration?.rulesMode { enabledInParentRules = parentOptInRules disabledInParentRules = parentDisabledRules } @@ -243,7 +245,7 @@ extension Configuration { allEnabledRules: Set, ruleType: any Rule.Type ) -> Issue? { - if case .allEnabled = parentConfiguration?.rulesMode { + if case .allCommandLine = parentConfiguration?.rulesMode { if disabledRules.contains(ruleType.identifier) { return Issue.ruleDisabledInDisabledRules(ruleID: ruleType.identifier) } @@ -264,7 +266,7 @@ extension Configuration { if enabledInParentRules.union(optInRules).isDisjoint(with: allIdentifiers) { return Issue.ruleNotEnabledInOptInRules(ruleID: ruleType.identifier) } - } else if case .only(let enabledInParentRules) = parentConfiguration?.rulesMode, + } else if case .onlyConfiguration(let enabledInParentRules) = parentConfiguration?.rulesMode, enabledInParentRules.isDisjoint(with: allIdentifiers) { return Issue.ruleNotEnabledInParentOnlyRules(ruleID: ruleType.identifier) } diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift index e03cadd0a2..897fbfe39e 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift @@ -21,17 +21,21 @@ public extension Configuration { /// The default rules mode, which will enable all rules that aren't defined as being opt-in /// (conforming to the `OptInRule` protocol), minus the rules listed in `disabled`, plus the rules listed in /// `optIn`. - case `default`(disabled: Set, optIn: Set) + case defaultConfiguration(disabled: Set, optIn: Set) - /// Only enable the rules explicitly listed. - case only(Set) + /// Only enable the rules explicitly listed in the configuration files. + case onlyConfiguration(Set) + + /// Only enable the rule(s) explicitly listed on the command line (and their aliases). `--only-rule` can be + /// specified multiple times to enable multiple rules. + case onlyCommandLine(Set) /// Enable all available rules. - case allEnabled + case allCommandLine internal init( enableAllRules: Bool, - onlyRule: String?, + onlyRule: [String], onlyRules: [String], optInRules: [String], disabledRules: [String], @@ -48,9 +52,9 @@ public extension Configuration { } if enableAllRules { - self = .allEnabled - } else if let onlyRule { - self = .only(Set([onlyRule])) + self = .allCommandLine + } else if onlyRule.isNotEmpty { + self = .onlyCommandLine(Set(onlyRule)) } else if onlyRules.isNotEmpty { if disabledRules.isNotEmpty || optInRules.isNotEmpty { throw Issue.genericWarning( @@ -61,7 +65,7 @@ public extension Configuration { } warnAboutDuplicates(in: onlyRules + analyzerRules) - self = .only(Set(onlyRules + analyzerRules)) + self = .onlyConfiguration(Set(onlyRules + analyzerRules)) } else { warnAboutDuplicates(in: disabledRules) @@ -86,23 +90,28 @@ public extension Configuration { } warnAboutDuplicates(in: effectiveOptInRules + effectiveAnalyzerRules) - self = .default(disabled: Set(disabledRules), optIn: Set(effectiveOptInRules + effectiveAnalyzerRules)) + self = .defaultConfiguration( + disabled: Set(disabledRules), optIn: Set(effectiveOptInRules + effectiveAnalyzerRules) + ) } } internal func applied(aliasResolver: (String) -> String) -> Self { switch self { - case let .default(disabled, optIn): - return .default( + case let .defaultConfiguration(disabled, optIn): + return .defaultConfiguration( disabled: Set(disabled.map(aliasResolver)), optIn: Set(optIn.map(aliasResolver)) ) - case let .only(onlyRules): - return .only(Set(onlyRules.map(aliasResolver))) + case let .onlyConfiguration(onlyRules): + return .onlyConfiguration(Set(onlyRules.map(aliasResolver))) + + case let .onlyCommandLine(onlyRules): + return .onlyCommandLine(Set(onlyRules.map(aliasResolver))) - case .allEnabled: - return .allEnabled + case .allCommandLine: + return .allCommandLine } } @@ -110,9 +119,11 @@ public extension Configuration { // In the only mode, if the custom rules rule is enabled, all custom rules are also enabled implicitly // This method makes the implicitly explicit switch self { - case let .only(onlyRules) where onlyRules.contains { $0 == CustomRules.description.identifier }: + case let .onlyConfiguration(onlyRules) where onlyRules.contains { + $0 == CustomRules.identifier + }: let customRulesRule = (allRulesWrapped.first { $0.rule is CustomRules })?.rule as? CustomRules - return .only(onlyRules.union(Set(customRulesRule?.customRuleIdentifiers ?? []))) + return .onlyConfiguration(onlyRules.union(Set(customRulesRule?.customRuleIdentifiers ?? []))) default: return self diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift index e06a692a6f..2a947148a1 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift @@ -34,18 +34,18 @@ internal extension Configuration { let customRulesFilter: (RegexConfiguration) -> (Bool) var resultingRules = [any Rule]() switch mode { - case .allEnabled: + case .allCommandLine: customRulesFilter = { _ in true } resultingRules = allRulesWrapped.map(\.rule) - case var .only(onlyRulesRuleIdentifiers): + case let .onlyConfiguration(onlyRulesRuleIdentifiers), let .onlyCommandLine(onlyRulesRuleIdentifiers): customRulesFilter = { onlyRulesRuleIdentifiers.contains($0.identifier) } - onlyRulesRuleIdentifiers = validate(ruleIds: onlyRulesRuleIdentifiers, valid: validRuleIdentifiers) + let onlyRulesRuleIdentifiers = validate(ruleIds: onlyRulesRuleIdentifiers, valid: validRuleIdentifiers) resultingRules = allRulesWrapped.filter { tuple in onlyRulesRuleIdentifiers.contains(type(of: tuple.rule).description.identifier) }.map(\.rule) - case var .default(disabledRuleIdentifiers, optInRuleIdentifiers): + case var .defaultConfiguration(disabledRuleIdentifiers, optInRuleIdentifiers): customRulesFilter = { !disabledRuleIdentifiers.contains($0.identifier) } disabledRuleIdentifiers = validate(ruleIds: disabledRuleIdentifiers, valid: validRuleIdentifiers) optInRuleIdentifiers = validate(optInRuleIds: optInRuleIdentifiers, valid: validRuleIdentifiers) @@ -75,11 +75,11 @@ internal extension Configuration { lazy var disabledRuleIdentifiers: [String] = { switch mode { - case let .default(disabled, _): + case let .defaultConfiguration(disabled, _): return validate(ruleIds: disabled, valid: validRuleIdentifiers, silent: true) .sorted(by: <) - case let .only(onlyRules): + case let .onlyConfiguration(onlyRules), let .onlyCommandLine(onlyRules): return validate( ruleIds: Set(allRulesWrapped .map { type(of: $0.rule).description.identifier } @@ -88,7 +88,7 @@ internal extension Configuration { silent: true ).sorted(by: <) - case .allEnabled: + case .allCommandLine: return [] } }() @@ -147,7 +147,7 @@ internal extension Configuration { let validRuleIdentifiers = self.validRuleIdentifiers.union(child.validRuleIdentifiers) let newMode: RulesMode switch child.mode { - case let .default(childDisabled, childOptIn): + case let .defaultConfiguration(childDisabled, childOptIn): newMode = mergeDefaultMode( newAllRulesWrapped: newAllRulesWrapped, child: child, @@ -156,13 +156,21 @@ internal extension Configuration { validRuleIdentifiers: validRuleIdentifiers ) - case let .only(childOnlyRules): - // Always use the child only rules - newMode = .only(childOnlyRules) + case let .onlyConfiguration(childOnlyRules): + // Use the child only rules, unless the parent is onlyRule + switch mode { + case let .onlyCommandLine(onlyRules): + newMode = .onlyCommandLine(onlyRules) + default: + newMode = .onlyConfiguration(childOnlyRules) + } + case let .onlyCommandLine(onlyRules): + // Always use the only rule + newMode = .onlyCommandLine(onlyRules) - case .allEnabled: + case .allCommandLine: // Always use .allEnabled mode - newMode = .allEnabled + newMode = .allCommandLine } // Assemble & return merged rules @@ -225,12 +233,12 @@ internal extension Configuration { let childOptIn = child.validate(optInRuleIds: childOptIn, valid: validRuleIdentifiers) switch mode { // Switch parent's mode. Child is in default mode. - case var .default(disabled, optIn): + case var .defaultConfiguration(disabled, optIn): disabled = validate(ruleIds: disabled, valid: validRuleIdentifiers) optIn = child.validate(optInRuleIds: optIn, valid: validRuleIdentifiers) // Only use parent disabled / optIn if child config doesn't tell the opposite - return .default( + return .defaultConfiguration( disabled: Set(childDisabled).union(Set(disabled.filter { !childOptIn.contains($0) })), optIn: Set(childOptIn).union(Set(optIn.filter { !childDisabled.contains($0) })) .filter { @@ -238,7 +246,7 @@ internal extension Configuration { } ) - case var .only(onlyRules): + case var .onlyConfiguration(onlyRules): // Also add identifiers of child custom rules iff the custom_rules rule is enabled // (parent custom rules are already added) if (onlyRules.contains { $0 == CustomRules.description.identifier }) { @@ -256,13 +264,17 @@ internal extension Configuration { // Allow parent only rules that weren't disabled via the child config // & opt-ins from the child config - return .only(Set( + return .onlyConfiguration(Set( childOptIn.union(onlyRules).filter { !childDisabled.contains($0) } )) - case .allEnabled: + case let .onlyCommandLine(onlyRules): + // Like .allEnabled, rules can be disabled in a child config + return .onlyCommandLine(onlyRules.filter { !childDisabled.contains($0) }) + + case .allCommandLine: // Opt-in to every rule that isn't disabled via child config - return .default( + return .defaultConfiguration( disabled: childDisabled .filter { !isOptInRule($0, allRulesWrapped: newAllRulesWrapped) diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 47401ed79e..944bbb6792 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -147,7 +147,7 @@ public struct Configuration { /// - parameter writeBaseline: The path to write a baseline to. /// - parameter checkForUpdates: Check for updates to SwiftLint. package init( - rulesMode: RulesMode = .default(disabled: [], optIn: []), + rulesMode: RulesMode = .defaultConfiguration(disabled: [], optIn: []), allRulesWrapped: [ConfigurationRuleWrapper]? = nil, ruleList: RuleList = RuleRegistry.shared.list, fileGraph: FileGraph? = nil, @@ -210,7 +210,7 @@ public struct Configuration { public init( configurationFiles: [String], // No default value here to avoid ambiguous Configuration() initializer enableAllRules: Bool = false, - onlyRule: String? = nil, + onlyRule: [String] = [], cachePath: String? = nil, ignoreParentAndChildConfigs: Bool = false, mockedNetworkResults: [String: String] = [:], @@ -230,7 +230,13 @@ public struct Configuration { defer { basedOnCustomConfigurationFiles = hasCustomConfigurationFiles } let currentWorkingDirectory = FileManager.default.currentDirectoryPath.bridge().absolutePathStandardized() - let rulesMode: RulesMode = enableAllRules ? .allEnabled : .default(disabled: [], optIn: []) + let rulesMode: RulesMode = if enableAllRules { + .allCommandLine + } else if onlyRule.isNotEmpty { + .onlyCommandLine(Set(onlyRule)) + } else { + .defaultConfiguration(disabled: [], optIn: []) + } // Try obtaining cached config let cacheIdentifier = "\(currentWorkingDirectory) - \(configurationFiles)" diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index 7afeef8abf..f9e24151b4 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -50,7 +50,7 @@ package struct LintOrAnalyzeOptions { let cachePath: String? let ignoreCache: Bool let enableAllRules: Bool - let onlyRule: String? + let onlyRule: [String] let autocorrect: Bool let format: Bool let compilerLogPath: String? @@ -78,7 +78,7 @@ package struct LintOrAnalyzeOptions { cachePath: String?, ignoreCache: Bool, enableAllRules: Bool, - onlyRule: String?, + onlyRule: [String], autocorrect: Bool, format: Bool, compilerLogPath: String?, diff --git a/Source/swiftlint/Commands/Analyze.swift b/Source/swiftlint/Commands/Analyze.swift index 7ff786edec..10471b1dda 100644 --- a/Source/swiftlint/Commands/Analyze.swift +++ b/Source/swiftlint/Commands/Analyze.swift @@ -13,8 +13,14 @@ extension SwiftLint { var compilerLogPath: String? @Option(help: "The path of a compilation database to use when running AnalyzerRules.") var compileCommands: String? - @Option(help: "Run only the specified rule, ignoring `only_rules`, `opt_in_rules` and `disabled_rules`.") - var onlyRule: String? + @Option( + parsing: .singleValue, + help: """ + Run only the specified rule, ignoring `only_rules`, `opt_in_rules` and `disabled_rules`. + Can be specified repeatedly to run multiple rules. + """ + ) + var onlyRule: [String] = [] @Argument(help: pathsArgumentDescription(for: .analyze)) var paths = [String]() diff --git a/Source/swiftlint/Commands/Lint.swift b/Source/swiftlint/Commands/Lint.swift index eadc1ab416..c1edb053b7 100644 --- a/Source/swiftlint/Commands/Lint.swift +++ b/Source/swiftlint/Commands/Lint.swift @@ -19,8 +19,14 @@ extension SwiftLint { var noCache = false @Flag(help: "Run all rules, even opt-in and disabled ones, ignoring `only_rules`.") var enableAllRules = false - @Option(help: "Run only the specified rule, ignoring `only_rules`, `opt_in_rules` and `disabled_rules`.") - var onlyRule: String? + @Option( + parsing: .singleValue, + help: """ + Run only the specified rule, ignoring `only_rules`, `opt_in_rules` and `disabled_rules`. + Can be specified repeatedly to run multiple rules. + """ + ) + var onlyRule: [String] = [] @Argument(help: pathsArgumentDescription(for: .lint)) var paths = [String]() diff --git a/Tests/IntegrationTests/IntegrationTests.swift b/Tests/IntegrationTests/IntegrationTests.swift index fb6945ed47..c4830a3ed1 100644 --- a/Tests/IntegrationTests/IntegrationTests.swift +++ b/Tests/IntegrationTests/IntegrationTests.swift @@ -54,7 +54,7 @@ final class IntegrationTests: SwiftLintTestCase { } func testDefaultConfigurations() { - let defaultConfig = Configuration(rulesMode: .allEnabled).rules + let defaultConfig = Configuration(rulesMode: .allCommandLine).rules .map { type(of: $0) } .filter { $0.identifier != "custom_rules" } .map { diff --git a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift index 8d4aa43cb5..dc5cea9e4f 100644 --- a/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CollectingRuleTests.swift @@ -147,7 +147,7 @@ extension MockCollectingRule { RuleDescription(identifier: "test_rule", name: "", description: "", kind: .lint) } static var configuration: Configuration? { - Configuration(rulesMode: .only([description.identifier]), ruleList: RuleList(rules: self)) + Configuration(rulesMode: .onlyConfiguration([identifier]), ruleList: RuleList(rules: self)) } init(configuration _: Any) throws { self.init() } diff --git a/Tests/SwiftLintFrameworkTests/CommandTests.swift b/Tests/SwiftLintFrameworkTests/CommandTests.swift index 5532fc0fa2..6ede31b63f 100644 --- a/Tests/SwiftLintFrameworkTests/CommandTests.swift +++ b/Tests/SwiftLintFrameworkTests/CommandTests.swift @@ -393,7 +393,9 @@ final class CommandTests: SwiftLintTestCase { } func testSuperfluousDisableCommandsDisabledOnConfiguration() { - let rulesMode = Configuration.RulesMode.default(disabled: ["superfluous_disable_command"], optIn: []) + let rulesMode = Configuration.RulesMode.defaultConfiguration( + disabled: ["superfluous_disable_command"], optIn: [] + ) let configuration = Configuration(rulesMode: rulesMode) XCTAssertEqual( @@ -456,7 +458,7 @@ final class CommandTests: SwiftLintTestCase { func testSuperfluousDisableCommandsEnabledForAnalyzer() { let configuration = Configuration( - rulesMode: .default(disabled: [], optIn: [UnusedDeclarationRule.description.identifier]) + rulesMode: .defaultConfiguration(disabled: [], optIn: [UnusedDeclarationRule.identifier]) ) let violations = violations( Example(""" diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index a5c1328741..2c3c742e66 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -52,7 +52,7 @@ extension ConfigurationTests { func testOnlyRulesMerging() { let baseConfiguration = Configuration( - rulesMode: .default( + rulesMode: .defaultConfiguration( disabled: [], optIn: [ ForceTryRule.description.identifier, @@ -60,7 +60,7 @@ extension ConfigurationTests { ] ) ) - let onlyConfiguration = Configuration(rulesMode: .only([TodoRule.description.identifier])) + let onlyConfiguration = Configuration(rulesMode: .onlyConfiguration([TodoRule.identifier])) XCTAssertTrue(baseConfiguration.contains(rule: TodoRule.self)) XCTAssertEqual(onlyConfiguration.rules.count, 1) XCTAssertTrue(onlyConfiguration.rules[0] is TodoRule) @@ -77,6 +77,25 @@ extension ConfigurationTests { XCTAssertTrue(mergedConfiguration2.contains(rule: ForceTryRule.self)) } + func testOnlyRuleMerging() { + let ruleIdentifier = TodoRule.description.identifier + let onlyRuleConfiguration = Configuration.onlyRuleConfiguration(ruleIdentifier) + + let emptyDefaultConfiguration = Configuration.emptyDefaultConfiguration() + let mergedConfiguration1 = onlyRuleConfiguration.merged(withChild: emptyDefaultConfiguration) + XCTAssertEqual(mergedConfiguration1.rules.count, 1) + XCTAssertTrue(mergedConfiguration1.rules[0] is TodoRule) + + let disabledDefaultConfiguration = Configuration.disabledDefaultConfiguration(ruleIdentifier) + let mergedConfiguration2 = onlyRuleConfiguration.merged(withChild: disabledDefaultConfiguration) + XCTAssertTrue(mergedConfiguration2.rules.isEmpty) + + let enabledOnlyConfiguration = Configuration.enabledOnlyConfiguration(ForceTryRule.description.identifier) + let mergedConfiguration3 = onlyRuleConfiguration.merged(withChild: enabledOnlyConfiguration) + XCTAssertEqual(mergedConfiguration3.rules.count, 1) + XCTAssertTrue(mergedConfiguration3.rules[0] is TodoRule) + } + func testCustomRulesMerging() { let mergedConfiguration = Mock.Config._0CustomRules.merged( withChild: Mock.Config._2CustomRules, @@ -345,11 +364,11 @@ extension ConfigurationTests { XCTAssertTrue((ruleType as Any) is any OptInRule.Type) let ruleIdentifier = ruleType.description.identifier for testCase in testCases { - let parentConfiguration = Configuration(rulesMode: .default( + let parentConfiguration = Configuration(rulesMode: .defaultConfiguration( disabled: testCase.disabledInParent ? [ruleIdentifier] : [], optIn: testCase.optedInInParent ? [ruleIdentifier] : [] )) - let childConfiguration = Configuration(rulesMode: .default( + let childConfiguration = Configuration(rulesMode: .defaultConfiguration( disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: testCase.optedInInChild ? [ruleIdentifier] : [] )) @@ -380,10 +399,10 @@ extension ConfigurationTests { let ruleIdentifier = ruleType.description.identifier for testCase in testCases { let parentConfiguration = Configuration( - rulesMode: .default(disabled: testCase.disabledInParent ? [ruleIdentifier] : [], optIn: []) + rulesMode: .defaultConfiguration(disabled: testCase.disabledInParent ? [ruleIdentifier] : [], optIn: []) ) let childConfiguration = Configuration( - rulesMode: .default(disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: []) + rulesMode: .defaultConfiguration(disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: []) ) let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration) let isEnabled = mergedConfiguration.contains(rule: ruleType) @@ -410,9 +429,9 @@ extension ConfigurationTests { let ruleType = ImplicitReturnRule.self XCTAssertTrue((ruleType as Any) is any OptInRule.Type) let ruleIdentifier = ruleType.description.identifier - let parentConfiguration = Configuration(rulesMode: .only([ruleIdentifier])) + let parentConfiguration = Configuration(rulesMode: .onlyConfiguration([ruleIdentifier])) for testCase in testCases { - let childConfiguration = Configuration(rulesMode: .default( + let childConfiguration = Configuration(rulesMode: .defaultConfiguration( disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: testCase.optedInInChild ? [ruleIdentifier] : [] )) @@ -448,10 +467,10 @@ extension ConfigurationTests { ] let configurations = [ - Configuration(rulesMode: .default(disabled: [], optIn: [])), - Configuration(rulesMode: .default(disabled: [], optIn: [ruleIdentifier])), - Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [ruleIdentifier])), - Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [])), + Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [])), + Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [ruleIdentifier])), + Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [ruleIdentifier])), + Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [])), ] for parentConfiguration in parentConfigurations { @@ -466,7 +485,7 @@ extension ConfigurationTests { configuration: Configuration, ruleType: any Rule.Type ) { - guard case .default(let disabledRules, let optInRules) = configuration.rulesMode else { + guard case .defaultConfiguration(let disabledRules, let optInRules) = configuration.rulesMode else { XCTFail("Configuration rulesMode was not the default") return } @@ -637,20 +656,23 @@ extension ConfigurationTests { private extension Configuration { static func emptyDefaultConfiguration() -> Self { - Configuration(rulesMode: .default(disabled: [], optIn: [])) + Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [])) } static func optInDefaultConfiguration(_ ruleIdentifier: String) -> Self { - Configuration(rulesMode: .default(disabled: [], optIn: [ruleIdentifier])) + Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [ruleIdentifier])) } static func optInDisabledDefaultConfiguration(_ ruleIdentifier: String) -> Self { - Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [ruleIdentifier])) + Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [ruleIdentifier])) } static func disabledDefaultConfiguration(_ ruleIdentifier: String) -> Self { - Configuration(rulesMode: .default(disabled: [ruleIdentifier], optIn: [])) + Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [])) } - static func emptyOnlyConfiguration() -> Self { Configuration(rulesMode: .only([])) } + static func emptyOnlyConfiguration() -> Self { Configuration(rulesMode: .onlyConfiguration([])) } static func enabledOnlyConfiguration(_ ruleIdentifier: String) -> Self { - Configuration(rulesMode: .only([ruleIdentifier])) + Configuration(rulesMode: .onlyConfiguration([ruleIdentifier])) + } + static func allEnabledConfiguration() -> Self { Configuration(rulesMode: .allCommandLine)} + static func onlyRuleConfiguration(_ ruleIdentifier: String) -> Self { + Configuration(rulesMode: .onlyCommandLine([ruleIdentifier])) } - static func allEnabledConfiguration() -> Self { Configuration(rulesMode: .allEnabled)} } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index f0ea288ba0..f718aed784 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -90,13 +90,27 @@ final class ConfigurationTests: SwiftLintTestCase { func testOnlyRule() throws { let configuration = try Configuration( dict: [:], - onlyRule: "nesting", + onlyRule: ["nesting"], cachePath: nil ) XCTAssertEqual(configuration.rules.count, 1) } + func testOnlyRuleMultiple() throws { + let onlyRuleIdentifiers = ["nesting", "todo"].sorted() + let configuration = try Configuration( + dict: ["only_rules": "line_length"], + onlyRule: onlyRuleIdentifiers, + cachePath: nil + ) + XCTAssertEqual(onlyRuleIdentifiers, configuration.enabledRuleIdentifiers) + + let childConfiguration = try Configuration(dict: ["disabled_rules": onlyRuleIdentifiers.last ?? ""]) + let mergedConfiguration = configuration.merged(withChild: childConfiguration) + XCTAssertEqual(onlyRuleIdentifiers.dropLast(), mergedConfiguration.enabledRuleIdentifiers) + } + func testOnlyRules() throws { let only = ["nesting", "todo"] @@ -180,10 +194,7 @@ final class ConfigurationTests: SwiftLintTestCase { "initializing Configuration with valid rules in YAML string should succeed") let expectedIdentifiers = Set(RuleRegistry.shared.list.list.keys .filter({ !([validRule] + optInRules).contains($0) })) - let configuredIdentifiers = Set(configuration.rules.map { - type(of: $0).description.identifier - }) - XCTAssertEqual(expectedIdentifiers, configuredIdentifiers) + XCTAssertEqual(expectedIdentifiers, Set(configuration.enabledRuleIdentifiers)) } func testDuplicatedRules() { @@ -592,3 +603,11 @@ private extension Sequence where Element == String { map { $0.absolutePathStandardized() } } } + +private extension Configuration { + var enabledRuleIdentifiers: [String] { + rules.map { + type(of: $0).identifier + }.sorted() + } +} diff --git a/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift b/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift index dab162bfaf..4b5b8d3e22 100644 --- a/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift +++ b/Tests/SwiftLintFrameworkTests/SourceKitCrashTests.swift @@ -52,7 +52,7 @@ final class SourceKitCrashTests: SwiftLintTestCase { file.assertHandler = { XCTFail("If this called, rule's SourceKitFreeRule is not properly configured") } - let configuration = Configuration(rulesMode: .only(allRuleIdentifiers)) + let configuration = Configuration(rulesMode: .onlyConfiguration(allRuleIdentifiers)) let storage = RuleStorage() _ = Linter(file: file, configuration: configuration).collect(into: storage).styleViolations(using: storage) file.sourcekitdFailed = false diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index 6a3293133f..c28f43e055 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -52,7 +52,7 @@ public let allRuleIdentifiers = Set(RuleRegistry.shared.list.list.keys) public extension Configuration { func applyingConfiguration(from example: Example) -> Configuration { guard let exampleConfiguration = example.configuration, - case let .only(onlyRules) = self.rulesMode, + case let .onlyConfiguration(onlyRules) = self.rulesMode, let firstRule = (onlyRules.first { $0 != "superfluous_disable_command" }), case let configDict: [_: any Sendable] = ["only_rules": onlyRules, firstRule: exampleConfiguration], let typedConfiguration = try? Configuration(dict: configDict) else { return self } @@ -281,12 +281,12 @@ public func makeConfig(_ ruleConfiguration: Any?, return (try? ruleType.init(configuration: ruleConfiguration)).flatMap { configuredRule in let rules = skipDisableCommandTests ? [configuredRule] : [configuredRule, SuperfluousDisableCommandRule()] return Configuration( - rulesMode: .only(identifiers), + rulesMode: .onlyConfiguration(identifiers), allRulesWrapped: rules.map { ($0, false) } ) } } - return Configuration(rulesMode: .only(identifiers)) + return Configuration(rulesMode: .onlyConfiguration(identifiers)) } private func testCorrection(_ correction: (Example, Example), @@ -299,7 +299,7 @@ private func testCorrection(_ correction: (Example, Example), #endif var config = configuration if let correctionConfiguration = correction.0.configuration, - case let .only(onlyRules) = configuration.rulesMode, + case let .onlyConfiguration(onlyRules) = configuration.rulesMode, let ruleToConfigure = (onlyRules.first { $0 != SuperfluousDisableCommandRule.description.identifier }), case let configDict: [_: any Sendable] = ["only_rules": onlyRules, ruleToConfigure: correctionConfiguration], let typedConfiguration = try? Configuration(dict: configDict) { From 832821259a499553f8e2056a13697d89b6c10b38 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Fri, 25 Oct 2024 20:43:49 +0300 Subject: [PATCH 235/265] Make use of transitive imports configuration (#5622) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 6 +++ .../Rules/Lint/UnusedImportRule.swift | 34 +++++++++++----- .../Rules/Lint/UnusedImportRuleExamples.swift | 40 +++++++++++++++++-- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9148f4f3dd..b7f2100741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,12 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5835](https://github.com/realm/SwiftLint/issues/5835) +* Allow to specify transitive modules to be taken into account by + `unused_import` rule. This avoids that required imports are removed. + [Paul Taykalo](https://github.com/PaulTaykalo) + [SimplyDanny](https://github.com/SimplyDanny) + [#5167](https://github.com/realm/SwiftLint/issues/5167) + * Do not throw deprecation warning if deprecated property is not presented in configuration. [chipp](https://github.com/chipp) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift index e61203ef3a..175a6cb40c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift @@ -118,17 +118,11 @@ private extension SwiftLintFile { ) } - let unusedImportUsages = rangedAndSortedUnusedImports(of: Array(unusedImports)) - .map { ImportUsage.unused(module: $0, range: $1) } - - guard configuration.requireExplicitImports else { - return unusedImportUsages - } - + // Find the missing imports, which should be imported, but are not. let currentModule = (compilerArguments.firstIndex(of: "-module-name")?.advanced(by: 1)) .map { compilerArguments[$0] } - let missingImports = usrFragments + var missingImports = usrFragments .subtracting(imports + [currentModule].compactMap({ $0 })) .filter { module in let modulesAllowedToImportCurrentModule = configuration.allowedTransitiveImports @@ -140,7 +134,29 @@ private extension SwiftLintFile { imports.isDisjoint(with: modulesAllowedToImportCurrentModule) } - return unusedImportUsages + missingImports.sorted().map { .missing(module: $0) } + // Check if unused imports were used for transitive imports + var foundUmbrellaModules = Set() + var foundMissingImports = Set() + for missingImport in missingImports { + let umbrellaModules = configuration.allowedTransitiveImports + .filter { $0.transitivelyImportedModules.contains(missingImport) } + .map(\.importedModule) + if umbrellaModules.isEmpty { + continue + } + foundMissingImports.insert(missingImport) + foundUmbrellaModules.formUnion(umbrellaModules.filter(unusedImports.contains)) + } + + unusedImports.subtract(foundUmbrellaModules) + missingImports.subtract(foundMissingImports) + + let unusedImportUsages = rangedAndSortedUnusedImports(of: Array(unusedImports)) + .map { ImportUsage.unused(module: $0, range: $1) } + + return configuration.requireExplicitImports + ? unusedImportUsages + missingImports.sorted().map { .missing(module: $0) } + : unusedImportUsages } func getImportsAndUSRFragments(compilerArguments: [String]) -> (imports: Set, usrFragments: Set) { diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift index 5a74494073..fdd33285e1 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRuleExamples.swift @@ -25,6 +25,33 @@ struct UnusedImportRuleExamples { let 👨‍👩‍👧‍👦 = #selector(NSArray.contains(_:)) 👨‍👩‍👧‍👦 == 👨‍👩‍👧‍👦 """), + Example(""" + import Foundation + enum E { + static let min: CGFloat = 44 + } + """, configuration: [ + "allowed_transitive_imports": [ + [ + "module": "Foundation", + "allowed_transitive_imports": ["CoreFoundation"], + ] as [String: any Sendable], + ], + ]), + Example(""" + import SwiftUI + + final class EditMode: ObservableObject { + @Published var isEditing = false + } + """, configuration: [ + "allowed_transitive_imports": [ + [ + "module": "SwiftUI", + "allowed_transitive_imports": ["Foundation"], + ] as [String: any Sendable], + ], + ], excludeFromDocumentation: true), ] static let triggeringExamples = [ @@ -152,30 +179,35 @@ struct UnusedImportRuleExamples { class A {} """), Example(""" - ↓↓import Foundation + import Foundation typealias Foo = CFArray + dispatchMain() """, configuration: [ "require_explicit_imports": true, "allowed_transitive_imports": [ [ "module": "Foundation", - "allowed_transitive_imports": ["CoreFoundation"], + "allowed_transitive_imports": ["CoreFoundation", "Dispatch"], ] as [String: any Sendable], ], ] as [String: any Sendable], testMultiByteOffsets: false, testOnLinux: false): Example(""" - import CoreFoundation + import Foundation typealias Foo = CFArray + dispatchMain() """), Example(""" - ↓↓import Foundation + ↓↓↓import Foundation typealias Foo = CFData + dispatchMain() """, configuration: [ "require_explicit_imports": true ], testMultiByteOffsets: false, testOnLinux: false): Example(""" import CoreFoundation + import Dispatch typealias Foo = CFData + dispatchMain() """), Example(""" import Foundation From 01f5ecd64a696468f90a1489f8ab1ac9adf0d6ff Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Sat, 26 Oct 2024 14:46:03 +0100 Subject: [PATCH 236/265] Replace `description.identifier` with `identifier` (#5837) --- .../Rules/Lint/CaptureVariableRule.swift | 2 +- .../Rules/Lint/InertDeferRule.swift | 2 +- .../Rules/Lint/TypesafeArrayInitRule.swift | 2 +- .../Rules/Lint/UnusedCaptureListRule.swift | 2 +- .../Rules/Lint/UnusedDeclarationRule.swift | 6 +++--- .../Rules/Lint/UnusedImportRule.swift | 8 ++++---- .../Rules/Style/ExplicitSelfRule.swift | 4 ++-- .../Documentation/RuleDocumentation.swift | 6 +++--- .../Extensions/Configuration+Cache.swift | 2 +- .../Extensions/Configuration+Parsing.swift | 2 +- .../Extensions/Configuration+RulesMode.swift | 2 +- .../Configuration+RulesWrapper.swift | 16 ++++++++-------- .../ChildOptionSeverityConfiguration.swift | 2 +- .../SwiftLintCore/Models/Configuration.swift | 4 ++-- ...shableConfigurationRuleWrapperWrapper.swift | 6 +++--- Source/SwiftLintCore/Models/Linter.swift | 6 +++--- Source/SwiftLintCore/Models/RuleList.swift | 2 +- .../RegexConfiguration.swift | 6 +++--- Source/SwiftLintCore/Rules/CustomRules.swift | 6 +++--- Source/SwiftLintFramework/RulesFilter.swift | 2 +- Tests/CLITests/RulesFilterTests.swift | 10 +++++----- .../CompilerProtocolInitRuleTests.swift | 2 +- .../ComputedAccessorsOrderRuleTests.swift | 2 +- .../ConfigurationAliasesTests.swift | 2 +- .../ConfigurationTests+MultipleConfigs.swift | 18 +++++++++--------- .../ConfigurationTests.swift | 10 +++++----- .../ContainsOverFirstNotNilRuleTests.swift | 2 +- .../CustomRulesTests.swift | 6 +++--- ...yclomaticComplexityConfigurationTests.swift | 2 +- .../DeploymentTargetConfigurationTests.swift | 2 +- .../DeploymentTargetRuleTests.swift | 2 +- .../ExpiringTodoRuleTests.swift | 2 +- ...plicitTypeInterfaceConfigurationTests.swift | 4 ++-- .../FunctionBodyLengthRuleTests.swift | 2 +- .../ImplicitGetterRuleTests.swift | 4 ++-- .../ImplicitReturnConfigurationTests.swift | 2 +- ...lyUnwrappedOptionalConfigurationTests.swift | 2 +- .../IndentationWidthRuleTests.swift | 2 +- .../LineLengthConfigurationTests.swift | 4 ++-- .../ModifierOrderTests.swift | 2 +- .../NameConfigurationTests.swift | 2 +- .../NestingRuleTests.swift | 4 ++-- .../NoEmptyBlockConfigurationTests.swift | 4 ++-- .../RuleConfigurationTests.swift | 10 +++++----- .../TodoRuleTests.swift | 2 +- .../TrailingCommaRuleTests.swift | 2 +- .../VerticalWhitespaceRuleTests.swift | 2 +- .../XCTSpecificMatcherRuleTests.swift | 2 +- Tests/SwiftLintTestHelpers/TestHelpers.swift | 6 +++--- 49 files changed, 102 insertions(+), 102 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift index 10c4d6b20a..bbf8d915ff 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/CaptureVariableRule.swift @@ -264,7 +264,7 @@ private extension SwiftLintFile { let path = self.path, let response = try? Request.index(file: path, arguments: compilerArguments).sendIfNotDisabled() else { - Issue.indexingError(path: path, ruleID: CaptureVariableRule.description.identifier).print() + Issue.indexingError(path: path, ruleID: CaptureVariableRule.identifier).print() return nil } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift index abecbf32c6..87a8775ebd 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/InertDeferRule.swift @@ -2,7 +2,7 @@ import SwiftSyntax // TODO: [12/23/2024] Remove deprecation warning after ~2 years. private let warnDeprecatedOnceImpl: Void = { - Issue.ruleDeprecated(ruleID: InertDeferRule.description.identifier).print() + Issue.ruleDeprecated(ruleID: InertDeferRule.identifier).print() }() private func warnDeprecatedOnce() { diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift index faa619e479..fb353a8ac6 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/TypesafeArrayInitRule.swift @@ -67,7 +67,7 @@ struct TypesafeArrayInitRule: AnalyzerRule { return [] } guard compilerArguments.isNotEmpty else { - Issue.missingCompilerArguments(path: file.path, ruleID: Self.description.identifier).print() + Issue.missingCompilerArguments(path: file.path, ruleID: Self.identifier).print() return [] } return Self.parentRule.validate(file: file) diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift index d8ce4a85be..445aba6edf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedCaptureListRule.swift @@ -2,7 +2,7 @@ import SwiftSyntax // TODO: [12/22/2024] Remove deprecation warning after ~2 years. private let warnDeprecatedOnceImpl: Void = { - Issue.ruleDeprecated(ruleID: UnusedCaptureListRule.description.identifier).print() + Issue.ruleDeprecated(ruleID: UnusedCaptureListRule.identifier).print() }() private func warnDeprecatedOnce() { diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift index d851ab72c0..33e3d23556 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedDeclarationRule.swift @@ -30,18 +30,18 @@ struct UnusedDeclarationRule: AnalyzerRule, CollectingRule { func collectInfo(for file: SwiftLintFile, compilerArguments: [String]) -> Self.FileUSRs { guard compilerArguments.isNotEmpty else { - Issue.missingCompilerArguments(path: file.path, ruleID: Self.description.identifier).print() + Issue.missingCompilerArguments(path: file.path, ruleID: Self.identifier).print() return .empty } guard let index = file.index(compilerArguments: compilerArguments), index.value.isNotEmpty else { - Issue.indexingError(path: file.path, ruleID: Self.description.identifier).print() + Issue.indexingError(path: file.path, ruleID: Self.identifier).print() return .empty } guard let editorOpen = (try? Request.editorOpen(file: file.file).sendIfNotDisabled()) .map(SourceKittenDictionary.init) else { - Issue.fileNotReadable(path: file.path, ruleID: Self.description.identifier).print() + Issue.fileNotReadable(path: file.path, ruleID: Self.identifier).print() return .empty } diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift index 175a6cb40c..6e1951a482 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/UnusedImportRule.swift @@ -84,7 +84,7 @@ struct UnusedImportRule: CorrectableRule, AnalyzerRule { private func importUsage(in file: SwiftLintFile, compilerArguments: [String]) -> [ImportUsage] { guard compilerArguments.isNotEmpty else { - Issue.missingCompilerArguments(path: file.path, ruleID: Self.description.identifier).print() + Issue.missingCompilerArguments(path: file.path, ruleID: Self.identifier).print() return [] } @@ -178,7 +178,7 @@ private extension SwiftLintFile { file: path!, offset: token.offset, arguments: compilerArguments ) guard let cursorInfo = (try? cursorInfoRequest.sendIfNotDisabled()).map(SourceKittenDictionary.init) else { - Issue.missingCursorInfo(path: path, ruleID: UnusedImportRule.description.identifier).print() + Issue.missingCursorInfo(path: path, ruleID: UnusedImportRule.identifier).print() continue } if nextIsModuleImport { @@ -213,7 +213,7 @@ private extension SwiftLintFile { func operatorImports(arguments: [String], processedTokenOffsets: Set) -> Set { guard let index = (try? Request.index(file: path!, arguments: arguments).sendIfNotDisabled()) .map(SourceKittenDictionary.init) else { - Issue.indexingError(path: path, ruleID: UnusedImportRule.description.identifier).print() + Issue.indexingError(path: path, ruleID: UnusedImportRule.identifier).print() return [] } @@ -236,7 +236,7 @@ private extension SwiftLintFile { ) guard let cursorInfo = (try? cursorInfoRequest.sendIfNotDisabled()) .map(SourceKittenDictionary.init) else { - Issue.missingCursorInfo(path: path, ruleID: UnusedImportRule.description.identifier).print() + Issue.missingCursorInfo(path: path, ruleID: UnusedImportRule.identifier).print() continue } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift index 5aa83a05ed..7d86574842 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitSelfRule.swift @@ -42,7 +42,7 @@ struct ExplicitSelfRule: CorrectableRule, AnalyzerRule { private func violationRanges(in file: SwiftLintFile, compilerArguments: [String]) -> [NSRange] { guard compilerArguments.isNotEmpty else { - Issue.missingCompilerArguments(path: file.path, ruleID: Self.description.identifier).print() + Issue.missingCompilerArguments(path: file.path, ruleID: Self.identifier).print() return [] } @@ -69,7 +69,7 @@ struct ExplicitSelfRule: CorrectableRule, AnalyzerRule { return cursorsMissingExplicitSelf.compactMap { cursorInfo in guard let byteOffset = (cursorInfo["swiftlint.offset"] as? Int64).flatMap(ByteCount.init) else { - Issue.genericWarning("Cannot convert offsets in '\(Self.description.identifier)' rule.").print() + Issue.genericWarning("Cannot convert offsets in '\(Self.identifier)' rule.").print() return nil } diff --git a/Source/SwiftLintCore/Documentation/RuleDocumentation.swift b/Source/SwiftLintCore/Documentation/RuleDocumentation.swift index c47a5d8383..00dd8f35e8 100644 --- a/Source/SwiftLintCore/Documentation/RuleDocumentation.swift +++ b/Source/SwiftLintCore/Documentation/RuleDocumentation.swift @@ -31,10 +31,10 @@ struct RuleDocumentation { var ruleName: String { ruleType.description.name } /// The identifier of the documented rule. - var ruleIdentifier: String { ruleType.description.identifier } + var ruleIdentifier: String { ruleType.identifier } /// The name of the file on disk for this rule documentation. - var fileName: String { "\(ruleType.description.identifier).md" } + var fileName: String { "\(ruleType.identifier).md" } /// The contents of the file for this rule documentation. var fileContents: String { @@ -81,7 +81,7 @@ private func h2(_ text: String) -> String { "## \(text)" } private func detailsSummary(_ rule: some Rule) -> String { let ruleDescription = """ - * **Identifier:** `\(type(of: rule).description.identifier)` + * **Identifier:** `\(type(of: rule).identifier)` * **Enabled by default:** \(rule is any OptInRule ? "No" : "Yes") * **Supports autocorrection:** \(rule is any CorrectableRule ? "Yes" : "No") * **Kind:** \(type(of: rule).description.kind) diff --git a/Source/SwiftLintCore/Extensions/Configuration+Cache.swift b/Source/SwiftLintCore/Extensions/Configuration+Cache.swift index 56debce0ce..c3e575a8b4 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Cache.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Cache.swift @@ -60,7 +60,7 @@ extension Configuration { } let cacheRulesDescriptions = rules - .map { rule in [type(of: rule).description.identifier, rule.cacheDescription] } + .map { rule in [type(of: rule).identifier, rule.cacheDescription] } .sorted { $0[0] < $1[0] } let jsonObject: [Any] = [rootDirectory, cacheRulesDescriptions] if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObject) { diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 1528591840..54dcf399da 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -66,7 +66,7 @@ extension Configuration { allRulesWrapped = try ruleList.allRulesWrapped(configurationDict: dict) } catch let RuleListError.duplicatedConfigurations(ruleType) { let aliases = ruleType.description.deprecatedAliases.map { "'\($0)'" }.joined(separator: ", ") - let identifier = ruleType.description.identifier + let identifier = ruleType.identifier throw Issue.genericWarning( "Multiple configurations found for '\(identifier)'. Check for any aliases: \(aliases)." ) diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift index 897fbfe39e..b5540cf3ad 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesMode.swift @@ -6,7 +6,7 @@ public extension Configuration { /// - returns: The rule for the specified ID, if configured in this configuration. func configuredRule(forID ruleID: String) -> (any Rule)? { rules.first { rule in - if type(of: rule).description.identifier == ruleID { + if type(of: rule).identifier == ruleID { if let customRules = rule as? CustomRules { return customRules.configuration.customRuleConfigurations.isNotEmpty } diff --git a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift index 2a947148a1..6e3295d951 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+RulesWrapper.swift @@ -11,7 +11,7 @@ internal extension Configuration { private var invalidRuleIdsWarnedAbout: Set = [] private var validRuleIdentifiers: Set { - let regularRuleIdentifiers = allRulesWrapped.map { type(of: $0.rule).description.identifier } + let regularRuleIdentifiers = allRulesWrapped.map { type(of: $0.rule).identifier } let configurationCustomRulesIdentifiers = (allRulesWrapped.first { $0.rule is CustomRules }?.rule as? CustomRules)?.customRuleIdentifiers ?? [] return Set(regularRuleIdentifiers + configurationCustomRulesIdentifiers) @@ -42,7 +42,7 @@ internal extension Configuration { customRulesFilter = { onlyRulesRuleIdentifiers.contains($0.identifier) } let onlyRulesRuleIdentifiers = validate(ruleIds: onlyRulesRuleIdentifiers, valid: validRuleIdentifiers) resultingRules = allRulesWrapped.filter { tuple in - onlyRulesRuleIdentifiers.contains(type(of: tuple.rule).description.identifier) + onlyRulesRuleIdentifiers.contains(type(of: tuple.rule).identifier) }.map(\.rule) case var .defaultConfiguration(disabledRuleIdentifiers, optInRuleIdentifiers): @@ -50,7 +50,7 @@ internal extension Configuration { disabledRuleIdentifiers = validate(ruleIds: disabledRuleIdentifiers, valid: validRuleIdentifiers) optInRuleIdentifiers = validate(optInRuleIds: optInRuleIdentifiers, valid: validRuleIdentifiers) resultingRules = allRulesWrapped.filter { tuple in - let id = type(of: tuple.rule).description.identifier + let id = type(of: tuple.rule).identifier return !disabledRuleIdentifiers.contains(id) && (!(tuple.rule is any OptInRule) || optInRuleIdentifiers.contains(id)) }.map(\.rule) @@ -65,7 +65,7 @@ internal extension Configuration { // Sort by name resultingRules = resultingRules.sorted { - type(of: $0).description.identifier < type(of: $1).description.identifier + type(of: $0).identifier < type(of: $1).identifier } // Store & return @@ -82,7 +82,7 @@ internal extension Configuration { case let .onlyConfiguration(onlyRules), let .onlyCommandLine(onlyRules): return validate( ruleIds: Set(allRulesWrapped - .map { type(of: $0.rule).description.identifier } + .map { type(of: $0.rule).identifier } .filter { !onlyRules.contains($0) }), valid: validRuleIdentifiers, silent: true @@ -249,7 +249,7 @@ internal extension Configuration { case var .onlyConfiguration(onlyRules): // Also add identifiers of child custom rules iff the custom_rules rule is enabled // (parent custom rules are already added) - if (onlyRules.contains { $0 == CustomRules.description.identifier }) { + if (onlyRules.contains { $0 == CustomRules.identifier }) { if let childCustomRulesRule = (child.allRulesWrapped.first { $0.rule is CustomRules })?.rule as? CustomRules { onlyRules = onlyRules.union( @@ -279,7 +279,7 @@ internal extension Configuration { .filter { !isOptInRule($0, allRulesWrapped: newAllRulesWrapped) }, - optIn: Set(newAllRulesWrapped.map { type(of: $0.rule).description.identifier } + optIn: Set(newAllRulesWrapped.map { type(of: $0.rule).identifier } .filter { !childDisabled.contains($0) && isOptInRule($0, allRulesWrapped: newAllRulesWrapped) @@ -298,7 +298,7 @@ internal extension Configuration { } let isOptInRule = allRulesWrapped - .first { type(of: $0.rule).description.identifier == identifier }?.rule is any OptInRule + .first { type(of: $0.rule).identifier == identifier }?.rule is any OptInRule Self.isOptInRuleCache[identifier] = isOptInRule return isOptInRule } diff --git a/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift b/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift index fb4aed94b8..4f63881029 100644 --- a/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift +++ b/Source/SwiftLintCore/Models/ChildOptionSeverityConfiguration.swift @@ -23,7 +23,7 @@ public struct ChildOptionSeverityConfiguration: RuleConfiguration, public mutating func apply(configuration: Any) throws { guard let configString = configuration as? String, let optionSeverity = ChildOptionSeverity(rawValue: configString.lowercased()) else { - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } self.optionSeverity = optionSeverity } diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index 944bbb6792..b8169afe11 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -309,7 +309,7 @@ extension Configuration: Hashable { hasher.combine(checkForUpdates) hasher.combine(basedOnCustomConfigurationFiles) hasher.combine(cachePath) - hasher.combine(rules.map { type(of: $0).description.identifier }) + hasher.combine(rules.map { type(of: $0).identifier }) hasher.combine(fileGraph) } @@ -344,6 +344,6 @@ extension Configuration: CustomStringConvertible { + "- Reporter: \(reporter ?? "default")\n" + "- Cache Path: \(cachePath as Optional)\n" + "- Computed Cache Description: \(computedCacheDescription as Optional)\n" - + "- Rules: \(rules.map { type(of: $0).description.identifier })" + + "- Rules: \(rules.map { type(of: $0).identifier })" } } diff --git a/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift b/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift index 05ff17312e..1abe3deae2 100644 --- a/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift +++ b/Source/SwiftLintCore/Models/HashableConfigurationRuleWrapperWrapper.swift @@ -5,11 +5,11 @@ internal struct HashableConfigurationRuleWrapperWrapper: Hashable { lhs: Self, rhs: Self ) -> Bool { // Only use identifier for equality check (not taking config into account) - type(of: lhs.configurationRuleWrapper.rule).description.identifier - == type(of: rhs.configurationRuleWrapper.rule).description.identifier + type(of: lhs.configurationRuleWrapper.rule).identifier + == type(of: rhs.configurationRuleWrapper.rule).identifier } func hash(into hasher: inout Hasher) { - hasher.combine(type(of: configurationRuleWrapper.rule).description.identifier) + hasher.combine(type(of: configurationRuleWrapper.rule).identifier) } } diff --git a/Source/SwiftLintCore/Models/Linter.swift b/Source/SwiftLintCore/Models/Linter.swift index c87065a557..68f111fdc9 100644 --- a/Source/SwiftLintCore/Models/Linter.swift +++ b/Source/SwiftLintCore/Models/Linter.swift @@ -89,7 +89,7 @@ private extension Rule { return nil } - let ruleID = Self.description.identifier + let ruleID = Self.identifier let violations: [StyleViolation] let ruleTime: (String, Double)? @@ -351,7 +351,7 @@ public struct CollectedLinter { let totalTime = -start.timeIntervalSinceNow let fractionedTime = totalTime / TimeInterval(rules.count) ruleTimes = rules.compactMap { rule in - let id = type(of: rule).description.identifier + let id = type(of: rule).identifier return (id, fractionedTime) } } @@ -414,7 +414,7 @@ public struct CollectedLinter { .configuration.customRuleConfigurations.map { RuleIdentifier($0.identifier) } ?? [] let allRuleIdentifiers = RuleRegistry.shared.list.allValidIdentifiers().map { RuleIdentifier($0) } let allValidIdentifiers = Set(allCustomIdentifiers + allRuleIdentifiers + [.all]) - let superfluousRuleIdentifier = RuleIdentifier(SuperfluousDisableCommandRule.description.identifier) + let superfluousRuleIdentifier = RuleIdentifier(SuperfluousDisableCommandRule.identifier) return regions.flatMap { region in region.disabledRuleIdentifiers.filter({ diff --git a/Source/SwiftLintCore/Models/RuleList.swift b/Source/SwiftLintCore/Models/RuleList.swift index e8dd55b5c8..79dab75ac6 100644 --- a/Source/SwiftLintCore/Models/RuleList.swift +++ b/Source/SwiftLintCore/Models/RuleList.swift @@ -27,7 +27,7 @@ public struct RuleList { var tmpAliases = [String: String]() for rule in rules { - let identifier = rule.description.identifier + let identifier = rule.identifier tmpList[identifier] = rule for alias in rule.description.deprecatedAliases { tmpAliases[alias] = identifier diff --git a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift index 65b44876f6..c4d3acf106 100644 --- a/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift +++ b/Source/SwiftLintCore/RuleConfigurations/RegexConfiguration.swift @@ -60,7 +60,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, public mutating func apply(configuration: Any) throws { guard let configurationDict = configuration as? [String: Any], let regexString = configurationDict[$regex.key] as? String else { - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } regex = try RegularExpression(pattern: regexString) @@ -92,7 +92,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, } if let captureGroup = configurationDict["capture_group"] as? Int { guard (0 ... regex.numberOfCaptureGroups).contains(captureGroup) else { - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } self.captureGroup = captureGroup } @@ -142,7 +142,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, if let kind = SyntaxKind(shortName: $0) { return kind } - throw Issue.invalidConfiguration(ruleID: Parent.description.identifier) + throw Issue.invalidConfiguration(ruleID: Parent.identifier) } return Set(kinds) } diff --git a/Source/SwiftLintCore/Rules/CustomRules.swift b/Source/SwiftLintCore/Rules/CustomRules.swift index e523c757a7..ec6a4f9000 100644 --- a/Source/SwiftLintCore/Rules/CustomRules.swift +++ b/Source/SwiftLintCore/Rules/CustomRules.swift @@ -90,7 +90,7 @@ struct CustomRules: Rule, CacheDescriptionProvider { func canBeDisabled(violation: StyleViolation, by ruleID: RuleIdentifier) -> Bool { switch ruleID { case let .single(identifier: id): - id == Self.description.identifier + id == Self.identifier ? customRuleIdentifiers.contains(violation.ruleIdentifier) : customRuleIdentifiers.contains(id) && violation.ruleIdentifier == id default: @@ -101,10 +101,10 @@ struct CustomRules: Rule, CacheDescriptionProvider { func isEnabled(in region: Region, for ruleID: String) -> Bool { if !Self.description.allIdentifiers.contains(ruleID), !customRuleIdentifiers.contains(ruleID), - Self.description.identifier != ruleID { + Self.identifier != ruleID { return true } - return !region.disabledRuleIdentifiers.contains(RuleIdentifier(Self.description.identifier)) + return !region.disabledRuleIdentifiers.contains(RuleIdentifier(Self.identifier)) && !region.disabledRuleIdentifiers.contains(RuleIdentifier(ruleID)) && !region.disabledRuleIdentifiers.contains(.all) } diff --git a/Source/SwiftLintFramework/RulesFilter.swift b/Source/SwiftLintFramework/RulesFilter.swift index 9f585f7be4..8a5d1d250e 100644 --- a/Source/SwiftLintFramework/RulesFilter.swift +++ b/Source/SwiftLintFramework/RulesFilter.swift @@ -26,7 +26,7 @@ package final class RulesFilter { let filtered: [any Rule.Type] = allRules.list.compactMap { ruleID, ruleType in let enabledRule = enabledRules.first { rule in - type(of: rule).description.identifier == ruleID + type(of: rule).identifier == ruleID } let isRuleEnabled = enabledRule != nil diff --git a/Tests/CLITests/RulesFilterTests.swift b/Tests/CLITests/RulesFilterTests.swift index 7c2f3fcfa4..8979db66c1 100644 --- a/Tests/CLITests/RulesFilterTests.swift +++ b/Tests/CLITests/RulesFilterTests.swift @@ -23,7 +23,7 @@ final class RulesFilterTests: XCTestCase { XCTAssertEqual( Set(filteredRules.list.keys), - Set([RuleMock2.description.identifier]) + Set([RuleMock2.identifier]) ) } @@ -48,7 +48,7 @@ final class RulesFilterTests: XCTestCase { XCTAssertEqual( Set(filteredRules.list.keys), - Set([RuleMock1.description.identifier, CorrectableRuleMock.description.identifier]) + Set([RuleMock1.identifier, CorrectableRuleMock.identifier]) ) } @@ -73,7 +73,7 @@ final class RulesFilterTests: XCTestCase { XCTAssertEqual( Set(filteredRules.list.keys), - Set([CorrectableRuleMock.description.identifier]) + Set([CorrectableRuleMock.identifier]) ) } @@ -98,7 +98,7 @@ final class RulesFilterTests: XCTestCase { XCTAssertEqual( Set(filteredRules.list.keys), - Set([CorrectableRuleMock.description.identifier]) + Set([CorrectableRuleMock.identifier]) ) } @@ -122,7 +122,7 @@ final class RulesFilterTests: XCTestCase { XCTAssertEqual( Set(filteredRules.list.keys), - Set([CorrectableRuleMock.description.identifier]) + Set([CorrectableRuleMock.identifier]) ) } } diff --git a/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift index bf39d734f5..68460fd73b 100644 --- a/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/CompilerProtocolInitRuleTests.swift @@ -2,7 +2,7 @@ import XCTest final class CompilerProtocolInitRuleTests: SwiftLintTestCase { - private let ruleID = CompilerProtocolInitRule.description.identifier + private let ruleID = CompilerProtocolInitRule.identifier func testViolationMessageForExpressibleByIntegerLiteral() throws { let config = try XCTUnwrap(makeConfig(nil, ruleID)) diff --git a/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift b/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift index 9460f22367..1066d61010 100644 --- a/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ComputedAccessorsOrderRuleTests.swift @@ -120,7 +120,7 @@ final class ComputedAccessorsOrderRuleTests: SwiftLintTestCase { } private func ruleViolations(_ example: Example, ruleConfiguration: Any? = nil) -> [StyleViolation] { - guard let config = makeConfig(ruleConfiguration, ComputedAccessorsOrderRule.description.identifier) else { + guard let config = makeConfig(ruleConfiguration, ComputedAccessorsOrderRule.identifier) else { return [] } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift index 7f9367dcef..c20e8b90b5 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationAliasesTests.swift @@ -28,7 +28,7 @@ final class ConfigurationAliasesTests: SwiftLintTestCase { // swiftlint:disable:next force_try let configuration = try! Configuration(dict: ["only_rules": ["mock"]], ruleList: testRuleList) let configuredIdentifiers = configuration.rules.map { - type(of: $0).description.identifier + type(of: $0).identifier } XCTAssertEqual(configuredIdentifiers, ["severity_level_mock"]) } diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift index 2c3c742e66..e928221e9b 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests+MultipleConfigs.swift @@ -55,8 +55,8 @@ extension ConfigurationTests { rulesMode: .defaultConfiguration( disabled: [], optIn: [ - ForceTryRule.description.identifier, - ForceCastRule.description.identifier, + ForceTryRule.identifier, + ForceCastRule.identifier, ] ) ) @@ -78,7 +78,7 @@ extension ConfigurationTests { } func testOnlyRuleMerging() { - let ruleIdentifier = TodoRule.description.identifier + let ruleIdentifier = TodoRule.identifier let onlyRuleConfiguration = Configuration.onlyRuleConfiguration(ruleIdentifier) let emptyDefaultConfiguration = Configuration.emptyDefaultConfiguration() @@ -90,7 +90,7 @@ extension ConfigurationTests { let mergedConfiguration2 = onlyRuleConfiguration.merged(withChild: disabledDefaultConfiguration) XCTAssertTrue(mergedConfiguration2.rules.isEmpty) - let enabledOnlyConfiguration = Configuration.enabledOnlyConfiguration(ForceTryRule.description.identifier) + let enabledOnlyConfiguration = Configuration.enabledOnlyConfiguration(ForceTryRule.identifier) let mergedConfiguration3 = onlyRuleConfiguration.merged(withChild: enabledOnlyConfiguration) XCTAssertEqual(mergedConfiguration3.rules.count, 1) XCTAssertTrue(mergedConfiguration3.rules[0] is TodoRule) @@ -362,7 +362,7 @@ extension ConfigurationTests { XCTAssertEqual(testCases.unique.count, 4 * 4) let ruleType = ImplicitReturnRule.self XCTAssertTrue((ruleType as Any) is any OptInRule.Type) - let ruleIdentifier = ruleType.description.identifier + let ruleIdentifier = ruleType.identifier for testCase in testCases { let parentConfiguration = Configuration(rulesMode: .defaultConfiguration( disabled: testCase.disabledInParent ? [ruleIdentifier] : [], @@ -396,7 +396,7 @@ extension ConfigurationTests { XCTAssertEqual(testCases.unique.count, 2 * 2) let ruleType = BlanketDisableCommandRule.self XCTAssertFalse(ruleType is any OptInRule.Type) - let ruleIdentifier = ruleType.description.identifier + let ruleIdentifier = ruleType.identifier for testCase in testCases { let parentConfiguration = Configuration( rulesMode: .defaultConfiguration(disabled: testCase.disabledInParent ? [ruleIdentifier] : [], optIn: []) @@ -428,7 +428,7 @@ extension ConfigurationTests { XCTAssertEqual(testCases.unique.count, 2 * 2) let ruleType = ImplicitReturnRule.self XCTAssertTrue((ruleType as Any) is any OptInRule.Type) - let ruleIdentifier = ruleType.description.identifier + let ruleIdentifier = ruleType.identifier let parentConfiguration = Configuration(rulesMode: .onlyConfiguration([ruleIdentifier])) for testCase in testCases { let childConfiguration = Configuration(rulesMode: .defaultConfiguration( @@ -635,8 +635,8 @@ extension ConfigurationTests { ) XCTAssertEqual( - configuration1.rules.map { type(of: $0).description.identifier }, - configuration2.rules.map { type(of: $0).description.identifier } + configuration1.rules.map { type(of: $0).identifier }, + configuration2.rules.map { type(of: $0).identifier } ) XCTAssertEqual( diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index f718aed784..ffca2d57ab 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -116,7 +116,7 @@ final class ConfigurationTests: SwiftLintTestCase { let config = try Configuration(dict: ["only_rules": only]) let configuredIdentifiers = config.rules.map { - type(of: $0).description.identifier + type(of: $0).identifier }.sorted() XCTAssertEqual(only, configuredIdentifiers) } @@ -178,7 +178,7 @@ final class ConfigurationTests: SwiftLintTestCase { let expectedIdentifiers = Set(RuleRegistry.shared.list.list.keys .filter({ !(["nesting", "todo"] + optInRules).contains($0) })) let configuredIdentifiers = Set(disabledConfig.rules.map { - type(of: $0).description.identifier + type(of: $0).identifier }) XCTAssertEqual(expectedIdentifiers, configuredIdentifiers) } @@ -205,7 +205,7 @@ final class ConfigurationTests: SwiftLintTestCase { let duplicateConfig2 = try? Configuration(dict: ["opt_in_rules": [optInRules.first!, optInRules.first!]]) XCTAssertEqual( - duplicateConfig2?.rules.filter { type(of: $0).description.identifier == optInRules.first! }.count, 1, + duplicateConfig2?.rules.filter { type(of: $0).identifier == optInRules.first! }.count, 1, "duplicate rules should be removed when initializing Configuration" ) @@ -435,14 +435,14 @@ final class ConfigurationTests: SwiftLintTestCase { func testConfiguresCorrectlyFromDict() throws { let ruleConfiguration = [1, 2] - let config = [RuleWithLevelsMock.description.identifier: ruleConfiguration] + let config = [RuleWithLevelsMock.identifier: ruleConfiguration] let rules = try testRuleList.allRulesWrapped(configurationDict: config).map(\.rule) // swiftlint:disable:next xct_specific_matcher XCTAssertTrue(rules == [try RuleWithLevelsMock(configuration: ruleConfiguration)]) } func testConfigureFallsBackCorrectly() throws { - let config = [RuleWithLevelsMock.description.identifier: ["a", "b"]] + let config = [RuleWithLevelsMock.identifier: ["a", "b"]] let rules = try testRuleList.allRulesWrapped(configurationDict: config).map(\.rule) // swiftlint:disable:next xct_specific_matcher XCTAssertTrue(rules == [RuleWithLevelsMock()]) diff --git a/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift b/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift index f8691673cd..83c162fba3 100644 --- a/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ContainsOverFirstNotNilRuleTests.swift @@ -21,7 +21,7 @@ final class ContainsOverFirstNotNilRuleTests: SwiftLintTestCase { // MARK: - Private private func violations(_ example: Example, config: Any? = nil) -> [StyleViolation] { - guard let config = makeConfig(config, ContainsOverFirstNotNilRule.description.identifier) else { + guard let config = makeConfig(config, ContainsOverFirstNotNilRule.identifier) else { return [] } diff --git a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift index 548fb98db2..4a4f11006c 100644 --- a/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/CustomRulesTests.swift @@ -66,7 +66,7 @@ final class CustomRulesTests: SwiftLintTestCase { func testCustomRuleConfigurationThrows() { let config = 17 var customRulesConfig = CustomRulesConfiguration() - checkError(Issue.invalidConfiguration(ruleID: CustomRules.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: CustomRules.identifier)) { try customRulesConfig.apply(configuration: config) } } @@ -106,7 +106,7 @@ final class CustomRulesTests: SwiftLintTestCase { XCTAssertEqual(customRulesConfig.customRuleConfigurations.count, 1) - let identifier = customRulesConfig.customRuleConfigurations.first?.description.identifier + let identifier = customRulesConfig.customRuleConfigurations.first?.identifier XCTAssertEqual(identifier, "my_custom_rule") } @@ -570,7 +570,7 @@ final class CustomRulesTests: SwiftLintTestCase { private extension StyleViolation { func isSuperfluousDisableCommandViolation(for ruleIdentifier: String) -> Bool { - self.ruleIdentifier == SuperfluousDisableCommandRule.description.identifier && + self.ruleIdentifier == SuperfluousDisableCommandRule.identifier && reason.contains("SwiftLint rule '\(ruleIdentifier)' did not trigger a violation") } } diff --git a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift index a03337b708..eb9638a82f 100644 --- a/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/CyclomaticComplexityConfigurationTests.swift @@ -71,7 +71,7 @@ final class CyclomaticComplexityConfigurationTests: SwiftLintTestCase { var configuration = CyclomaticComplexityConfiguration( length: SeverityLevelsConfiguration(warning: 100, error: 150) ) - checkError(Issue.invalidConfiguration(ruleID: CyclomaticComplexityRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: CyclomaticComplexityRule.identifier)) { try configuration.apply(configuration: badConfig) } } diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift index b130557f09..f9edd35491 100644 --- a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift @@ -139,7 +139,7 @@ final class DeploymentTargetConfigurationTests: SwiftLintTestCase { for badConfig in badConfigs { var configuration = DeploymentTargetConfiguration() - checkError(Issue.invalidConfiguration(ruleID: DeploymentTargetRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: DeploymentTargetRule.identifier)) { try configuration.apply(configuration: badConfig) } } diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift index 46c8b21066..b101b89b0c 100644 --- a/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift @@ -35,7 +35,7 @@ final class DeploymentTargetRuleTests: SwiftLintTestCase { } private func violations(_ example: Example, config: Any?) -> [StyleViolation] { - guard let config = makeConfig(config, DeploymentTargetRule.description.identifier) else { + guard let config = makeConfig(config, DeploymentTargetRule.identifier) else { return [] } diff --git a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift index 06f890bdea..a95bb4ec5a 100644 --- a/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExpiringTodoRuleTests.swift @@ -191,7 +191,7 @@ final class ExpiringTodoRuleTests: SwiftLintTestCase { ] } - return makeConfig(serializedConfig, ExpiringTodoRule.description.identifier)! + return makeConfig(serializedConfig, ExpiringTodoRule.identifier)! } } diff --git a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift index ea362d5228..ec413e59a4 100644 --- a/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceConfigurationTests.swift @@ -33,14 +33,14 @@ final class ExplicitTypeInterfaceConfigurationTests: SwiftLintTestCase { func testInvalidTypeOfCustomConfiguration() { var config = ExplicitTypeInterfaceConfiguration() - checkError(Issue.invalidConfiguration(ruleID: ExplicitTypeInterfaceRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ExplicitTypeInterfaceRule.identifier)) { try config.apply(configuration: "invalidKey") } } func testInvalidTypeOfValueInCustomConfiguration() { var config = ExplicitTypeInterfaceConfiguration() - checkError(Issue.invalidConfiguration(ruleID: ExplicitTypeInterfaceRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ExplicitTypeInterfaceRule.identifier)) { try config.apply(configuration: ["severity": "foo"]) } } diff --git a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift index 04e9a6cbab..d849b2996d 100644 --- a/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FunctionBodyLengthRuleTests.swift @@ -101,7 +101,7 @@ final class FunctionBodyLengthRuleTests: SwiftLintTestCase { } private func violations(_ example: Example, configuration: Any? = nil) -> [StyleViolation] { - let config = makeConfig(configuration, FunctionBodyLengthRule.description.identifier)! + let config = makeConfig(configuration, FunctionBodyLengthRule.identifier)! return SwiftLintFrameworkTests.violations(example, config: config) } } diff --git a/Tests/SwiftLintFrameworkTests/ImplicitGetterRuleTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitGetterRuleTests.swift index 8a83b92bbe..0905bf01f9 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitGetterRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitGetterRuleTests.swift @@ -3,7 +3,7 @@ import XCTest final class ImplicitGetterRuleTests: SwiftLintTestCase { func testPropertyReason() throws { - let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.description.identifier)) + let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.identifier)) let example = Example(""" class Foo { var foo: Int { @@ -20,7 +20,7 @@ final class ImplicitGetterRuleTests: SwiftLintTestCase { } func testSubscriptReason() throws { - let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.description.identifier)) + let config = try XCTUnwrap(makeConfig(nil, ImplicitGetterRule.identifier)) let example = Example(""" class Foo { subscript(i: Int) -> Int { diff --git a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift index c6a62deca1..b19dd28e02 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitReturnConfigurationTests.swift @@ -31,7 +31,7 @@ final class ImplicitReturnConfigurationTests: SwiftLintTestCase { var configuration = ImplicitReturnConfiguration() let config = ["included": ["foreach"]] as [String: any Sendable] - checkError(Issue.invalidConfiguration(ruleID: ImplicitReturnRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ImplicitReturnRule.identifier)) { try configuration.apply(configuration: config) } } diff --git a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift index 6dca068e61..6ba01c625c 100644 --- a/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ImplicitlyUnwrappedOptionalConfigurationTests.swift @@ -39,7 +39,7 @@ final class ImplicitlyUnwrappedOptionalConfigurationTests: SwiftLintTestCase { mode: .allExceptIBOutlets ) - checkError(Issue.invalidConfiguration(ruleID: ImplicitlyUnwrappedOptionalRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ImplicitlyUnwrappedOptionalRule.identifier)) { try configuration.apply(configuration: badConfig) } } diff --git a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift index 627797f814..b0234978bc 100644 --- a/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/IndentationWidthRuleTests.swift @@ -282,7 +282,7 @@ final class IndentationWidthRuleTests: SwiftLintTestCase { configDict["include_compiler_directives"] = includeCompilerDirectives configDict["include_multiline_strings"] = includeMultilineStrings - guard let config = makeConfig(configDict, IndentationWidthRule.description.identifier) else { + guard let config = makeConfig(configDict, IndentationWidthRule.identifier) else { XCTFail("Unable to create rule configuration.", file: (file), line: line) return 0 } diff --git a/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift index 01b59c8c9d..55360aabe8 100644 --- a/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/LineLengthConfigurationTests.swift @@ -71,7 +71,7 @@ final class LineLengthConfigurationTests: SwiftLintTestCase { func testLineLengthConfigurationThrowsOnBadConfig() { let config = ["warning": "unknown"] var configuration = LineLengthConfiguration(length: severityLevels) - checkError(Issue.invalidConfiguration(ruleID: LineLengthRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: LineLengthRule.identifier)) { try configuration.apply(configuration: config) } } @@ -84,7 +84,7 @@ final class LineLengthConfigurationTests: SwiftLintTestCase { for badConfig in badConfigs { var configuration = LineLengthConfiguration(length: severityLevels) - checkError(Issue.invalidConfiguration(ruleID: LineLengthRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: LineLengthRule.identifier)) { try configuration.apply(configuration: badConfig) } } diff --git a/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift b/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift index 4df00865d1..fdcff1f16f 100644 --- a/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift +++ b/Tests/SwiftLintFrameworkTests/ModifierOrderTests.swift @@ -383,7 +383,7 @@ final class ModifierOrderTests: SwiftLintTestCase { } func testViolationMessage() { - let ruleID = ModifierOrderRule.description.identifier + let ruleID = ModifierOrderRule.identifier guard let config = makeConfig(["preferred_modifier_order": ["acl", "final"]], ruleID) else { XCTFail("Failed to create configuration") return diff --git a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift index 9f7fac7979..fc39b2bf29 100644 --- a/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/NameConfigurationTests.swift @@ -67,7 +67,7 @@ final class NameConfigurationTests: SwiftLintTestCase { minLengthError: 0, maxLengthWarning: 0, maxLengthError: 0) - checkError(Issue.invalidConfiguration(ruleID: RuleMock.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: RuleMock.identifier)) { try nameConfig.apply(configuration: config) } } diff --git a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift index 4386d10d4f..435ca660be 100644 --- a/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/NestingRuleTests.swift @@ -200,7 +200,7 @@ final class NestingRuleTests: SwiftLintTestCase { }) let description = RuleDescription( - identifier: NestingRule.description.identifier, + identifier: NestingRule.identifier, name: NestingRule.description.name, description: NestingRule.description.description, kind: .metrics, @@ -499,7 +499,7 @@ final class NestingRuleTests: SwiftLintTestCase { ]) let description = RuleDescription( - identifier: NestingRule.description.identifier, + identifier: NestingRule.identifier, name: NestingRule.description.name, description: NestingRule.description.description, kind: .metrics, diff --git a/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift index 851f358587..22b22f58d6 100644 --- a/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/NoEmptyBlockConfigurationTests.swift @@ -31,14 +31,14 @@ final class NoEmptyBlockConfigurationTests: SwiftLintTestCase { func testInvalidTypeOfCustomConfiguration() { var config = NoEmptyBlockConfiguration() - checkError(Issue.invalidConfiguration(ruleID: NoEmptyBlockRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: NoEmptyBlockRule.identifier)) { try config.apply(configuration: "invalidKey") } } func testInvalidTypeOfValueInCustomConfiguration() { var config = NoEmptyBlockConfiguration() - checkError(Issue.invalidConfiguration(ruleID: NoEmptyBlockRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: NoEmptyBlockRule.identifier)) { try config.apply(configuration: ["severity": "foo"]) } } diff --git a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift index db0a56ddb9..f86fca1e21 100644 --- a/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/RuleConfigurationTests.swift @@ -37,7 +37,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { func testNestingConfigurationThrowsOnBadConfig() { let config = 17 var nestingConfig = defaultNestingConfiguration - checkError(Issue.invalidConfiguration(ruleID: NestingRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: NestingRule.identifier)) { try nestingConfig.apply(configuration: config) } } @@ -117,7 +117,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { func testRegexConfigurationThrows() { let config = 17 var regexConfig = RegexConfiguration(identifier: "") - checkError(Issue.invalidConfiguration(ruleID: RuleMock.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: RuleMock.identifier)) { try regexConfig.apply(configuration: config) } } @@ -137,7 +137,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { let config = "unknown" var configuration = TrailingWhitespaceConfiguration(ignoresEmptyLines: false, ignoresComments: true) - checkError(Issue.invalidConfiguration(ruleID: TrailingWhitespaceRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: TrailingWhitespaceRule.identifier)) { try configuration.apply(configuration: config) } } @@ -321,7 +321,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { var configuration = ModifierOrderConfiguration() let config = ["severity": "warning", "preferred_modifier_order": ["specialize"]] as [String: any Sendable] - checkError(Issue.invalidConfiguration(ruleID: ModifierOrderRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ModifierOrderRule.identifier)) { try configuration.apply(configuration: config) } } @@ -329,7 +329,7 @@ final class RuleConfigurationTests: SwiftLintTestCase { func testModifierOrderConfigurationThrowsOnNonModifiableGroup() { var configuration = ModifierOrderConfiguration() let config = ["severity": "warning", "preferred_modifier_order": ["atPrefixed"]] as [String: any Sendable] - checkError(Issue.invalidConfiguration(ruleID: ModifierOrderRule.description.identifier)) { + checkError(Issue.invalidConfiguration(ruleID: ModifierOrderRule.identifier)) { try configuration.apply(configuration: config) } } diff --git a/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift b/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift index 8058742dae..8130bc54cc 100644 --- a/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TodoRuleTests.swift @@ -41,7 +41,7 @@ final class TodoRuleTests: SwiftLintTestCase { } private func violations(_ example: Example, config: Any? = nil) -> [StyleViolation] { - let config = makeConfig(config, TodoRule.description.identifier)! + let config = makeConfig(config, TodoRule.identifier)! return SwiftLintFrameworkTests.violations(example, config: config) } } diff --git a/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift b/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift index dc26b39ebb..e7b4a8f361 100644 --- a/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/TrailingCommaRuleTests.swift @@ -69,7 +69,7 @@ final class TrailingCommaRuleTests: SwiftLintTestCase { } private func trailingCommaViolations(_ example: Example, ruleConfiguration: Any? = nil) -> [StyleViolation] { - let config = makeConfig(ruleConfiguration, TrailingCommaRule.description.identifier)! + let config = makeConfig(ruleConfiguration, TrailingCommaRule.identifier)! return violations(example, config: config) } } diff --git a/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift b/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift index 20d725b487..deba0b0844 100644 --- a/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/VerticalWhitespaceRuleTests.swift @@ -2,7 +2,7 @@ import XCTest final class VerticalWhitespaceRuleTests: SwiftLintTestCase { - private let ruleID = VerticalWhitespaceRule.description.identifier + private let ruleID = VerticalWhitespaceRule.identifier func testAttributesWithMaxEmptyLines() { // Test with custom `max_empty_lines` diff --git a/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift b/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift index d32351bbe2..90c78cfada 100644 --- a/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/XCTSpecificMatcherRuleTests.swift @@ -181,7 +181,7 @@ final class XCTSpecificMatcherRuleTests: SwiftLintTestCase { } private func violations(_ example: Example) -> [StyleViolation] { - guard let config = makeConfig(nil, XCTSpecificMatcherRule.description.identifier) else { return [] } + guard let config = makeConfig(nil, XCTSpecificMatcherRule.identifier) else { return [] } return SwiftLintFrameworkTests.violations(example, config: config) } diff --git a/Tests/SwiftLintTestHelpers/TestHelpers.swift b/Tests/SwiftLintTestHelpers/TestHelpers.swift index c28f43e055..06b09ac8b5 100644 --- a/Tests/SwiftLintTestHelpers/TestHelpers.swift +++ b/Tests/SwiftLintTestHelpers/TestHelpers.swift @@ -272,7 +272,7 @@ private extension String { public func makeConfig(_ ruleConfiguration: Any?, _ identifier: String, skipDisableCommandTests: Bool = false) -> Configuration? { - let superfluousDisableCommandRuleIdentifier = SuperfluousDisableCommandRule.description.identifier + let superfluousDisableCommandRuleIdentifier = SuperfluousDisableCommandRule.identifier let identifiers: Set = skipDisableCommandTests ? [identifier] : [identifier, superfluousDisableCommandRuleIdentifier] @@ -300,7 +300,7 @@ private func testCorrection(_ correction: (Example, Example), var config = configuration if let correctionConfiguration = correction.0.configuration, case let .onlyConfiguration(onlyRules) = configuration.rulesMode, - let ruleToConfigure = (onlyRules.first { $0 != SuperfluousDisableCommandRule.description.identifier }), + let ruleToConfigure = (onlyRules.first { $0 != SuperfluousDisableCommandRule.identifier }), case let configDict: [_: any Sendable] = ["only_rules": onlyRules, ruleToConfigure: correctionConfiguration], let typedConfiguration = try? Configuration(dict: configDict) { config = configuration.merged(withChild: typedConfiguration, rootDirectory: configuration.rootDirectory) @@ -425,7 +425,7 @@ public extension XCTestCase { for trigger in disabledTriggers { let violationsPartitionedByType = makeViolations(trigger) - .partitioned { $0.ruleIdentifier == SuperfluousDisableCommandRule.description.identifier } + .partitioned { $0.ruleIdentifier == SuperfluousDisableCommandRule.identifier } XCTAssert(violationsPartitionedByType.first.isEmpty, "Violation(s) still triggered although rule was disabled", From f410ea51a7ac242070f3e4e2a88dc2519ea9aabc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Wed, 30 Oct 2024 14:24:22 +0100 Subject: [PATCH 237/265] Support Swift version 6.0.2 (#5844) --- Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift index fb103a7b7e..aff4993cc8 100644 --- a/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift +++ b/Tests/SwiftLintFrameworkTests/SwiftVersionTests.swift @@ -3,7 +3,9 @@ import XCTest final class SwiftVersionTests: SwiftLintTestCase { func testDetectSwiftVersion() { -#if compiler(>=6.0.1) +#if compiler(>=6.0.2) + let version = "6.0.2" +#elseif compiler(>=6.0.1) let version = "6.0.1" #elseif compiler(>=6.0.0) let version = "6.0.0" From 23d6a7c3f56f2d0815774415a12b5405dfd1d9b0 Mon Sep 17 00:00:00 2001 From: Martin Redington Date: Wed, 30 Oct 2024 22:03:54 +0000 Subject: [PATCH 238/265] Added `lenient` command line option (#5801) --- CHANGELOG.md | 5 ++ README.md | 3 + .../Extensions/Configuration+Merging.swift | 1 + .../Extensions/Configuration+Parsing.swift | 2 + .../SwiftLintCore/Models/Configuration.swift | 11 +++ .../LintOrAnalyzeCommand.swift | 26 +++++-- .../ConfigurationTests.swift | 6 ++ .../LintOrAnalyzeOptionsTests.swift | 72 +++++++++++++++++++ 8 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 Tests/SwiftLintFrameworkTests/LintOrAnalyzeOptionsTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index b7f2100741..ffb00ebc19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,11 @@ argument `--use-script-input-file-lists`. [BlueVirusX](https://github.com/BlueVirusX) +* Adds a `lenient` configuration file setting, equivalent to the `--lenient` + command line option. + [Martin Redington](https://github.com/mildm8nnered) + [#5801](https://github.com/realm/SwiftLint/issues/5801) + #### Bug Fixes * Run command plugin in whole package if no targets are defined in the diff --git a/README.md b/README.md index 2d37e03326..39b7294f7e 100644 --- a/README.md +++ b/README.md @@ -723,6 +723,9 @@ allow_zero_lintable_files: false # If true, SwiftLint will treat all warnings as errors. strict: false +# If true, SwiftLint will treat all errors as warnings. +lenient: false + # The path to a baseline file, which will be used to filter out detected violations. baseline: Baseline.json diff --git a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift index 05e5dfd490..82a11e342d 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Merging.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Merging.swift @@ -26,6 +26,7 @@ extension Configuration { cachePath: cachePath, allowZeroLintableFiles: childConfiguration.allowZeroLintableFiles, strict: childConfiguration.strict, + lenient: childConfiguration.lenient, baseline: childConfiguration.baseline, writeBaseline: childConfiguration.writeBaseline, checkForUpdates: childConfiguration.checkForUpdates diff --git a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift index 54dcf399da..c8326c0776 100644 --- a/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift +++ b/Source/SwiftLintCore/Extensions/Configuration+Parsing.swift @@ -15,6 +15,7 @@ extension Configuration { case analyzerRules = "analyzer_rules" case allowZeroLintableFiles = "allow_zero_lintable_files" case strict = "strict" + case lenient = "lenient" case baseline = "baseline" case writeBaseline = "write_baseline" case checkForUpdates = "check_for_updates" @@ -103,6 +104,7 @@ extension Configuration { pinnedVersion: dict[Key.swiftlintVersion.rawValue].map { ($0 as? String) ?? String(describing: $0) }, allowZeroLintableFiles: dict[Key.allowZeroLintableFiles.rawValue] as? Bool ?? false, strict: dict[Key.strict.rawValue] as? Bool ?? false, + lenient: dict[Key.lenient.rawValue] as? Bool ?? false, baseline: dict[Key.baseline.rawValue] as? String, writeBaseline: dict[Key.writeBaseline.rawValue] as? String, checkForUpdates: dict[Key.checkForUpdates.rawValue] as? Bool ?? false diff --git a/Source/SwiftLintCore/Models/Configuration.swift b/Source/SwiftLintCore/Models/Configuration.swift index b8169afe11..bf5d6d9bc1 100644 --- a/Source/SwiftLintCore/Models/Configuration.swift +++ b/Source/SwiftLintCore/Models/Configuration.swift @@ -38,6 +38,9 @@ public struct Configuration { /// Treat warnings as errors. public let strict: Bool + /// Treat errors as warnings. + public let lenient: Bool + /// The path to read a baseline from. public let baseline: String? @@ -83,6 +86,7 @@ public struct Configuration { cachePath: String?, allowZeroLintableFiles: Bool, strict: Bool, + lenient: Bool, baseline: String?, writeBaseline: String?, checkForUpdates: Bool @@ -97,6 +101,7 @@ public struct Configuration { self.cachePath = cachePath self.allowZeroLintableFiles = allowZeroLintableFiles self.strict = strict + self.lenient = lenient self.baseline = baseline self.writeBaseline = writeBaseline self.checkForUpdates = checkForUpdates @@ -117,6 +122,7 @@ public struct Configuration { cachePath = configuration.cachePath allowZeroLintableFiles = configuration.allowZeroLintableFiles strict = configuration.strict + lenient = configuration.lenient baseline = configuration.baseline writeBaseline = configuration.writeBaseline checkForUpdates = configuration.checkForUpdates @@ -143,6 +149,7 @@ public struct Configuration { /// - parameter allowZeroLintableFiles: Allow SwiftLint to exit successfully when passed ignored or unlintable /// files. /// - parameter strict: Treat warnings as errors. + /// - parameter lenient: Treat errors as warnings. /// - parameter baseline: The path to read a baseline from. /// - parameter writeBaseline: The path to write a baseline to. /// - parameter checkForUpdates: Check for updates to SwiftLint. @@ -160,6 +167,7 @@ public struct Configuration { pinnedVersion: String? = nil, allowZeroLintableFiles: Bool = false, strict: Bool = false, + lenient: Bool = false, baseline: String? = nil, writeBaseline: String? = nil, checkForUpdates: Bool = false @@ -189,6 +197,7 @@ public struct Configuration { cachePath: cachePath, allowZeroLintableFiles: allowZeroLintableFiles, strict: strict, + lenient: lenient, baseline: baseline, writeBaseline: writeBaseline, checkForUpdates: checkForUpdates @@ -304,6 +313,7 @@ extension Configuration: Hashable { hasher.combine(reporter) hasher.combine(allowZeroLintableFiles) hasher.combine(strict) + hasher.combine(lenient) hasher.combine(baseline) hasher.combine(writeBaseline) hasher.combine(checkForUpdates) @@ -325,6 +335,7 @@ extension Configuration: Hashable { lhs.fileGraph == rhs.fileGraph && lhs.allowZeroLintableFiles == rhs.allowZeroLintableFiles && lhs.strict == rhs.strict && + lhs.lenient == rhs.lenient && lhs.baseline == rhs.baseline && lhs.writeBaseline == rhs.writeBaseline && lhs.checkForUpdates == rhs.checkForUpdates && diff --git a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift index f9e24151b4..746342c301 100644 --- a/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift +++ b/Source/SwiftLintFramework/LintOrAnalyzeCommand.swift @@ -169,6 +169,7 @@ package struct LintOrAnalyzeCommand { currentViolations = applyLeniency( options: options, strict: builder.configuration.strict, + lenient: builder.configuration.lenient, violations: violationsBeforeLeniency ) visitorMutationQueue.sync { @@ -179,6 +180,7 @@ package struct LintOrAnalyzeCommand { currentViolations = applyLeniency( options: options, strict: builder.configuration.strict, + lenient: builder.configuration.lenient, violations: linter.styleViolations(using: builder.storage) ) } @@ -273,15 +275,16 @@ package struct LintOrAnalyzeCommand { private static func applyLeniency( options: LintOrAnalyzeOptions, strict: Bool, + lenient: Bool, violations: [StyleViolation] ) -> [StyleViolation] { - let strict = (strict && !options.lenient) || options.strict + let leniency = options.leniency(strict: strict, lenient: lenient) - switch (options.lenient, strict) { + switch leniency { case (false, false): return violations - case (true, false): + case (false, true): return violations.map { if $0.severity == .error { return $0.with(severity: .warning) @@ -289,7 +292,7 @@ package struct LintOrAnalyzeCommand { return $0 } - case (false, true): + case (true, false): return violations.map { if $0.severity == .warning { return $0.with(severity: .error) @@ -298,7 +301,7 @@ package struct LintOrAnalyzeCommand { } case (true, true): - queuedFatalError("Invalid command line options: 'lenient' and 'strict' are mutually exclusive.") + queuedFatalError("Invalid command line or config options: 'strict' and 'lenient' are mutually exclusive.") } } @@ -394,8 +397,8 @@ private class LintOrAnalyzeResultBuilder { } } -private extension LintOrAnalyzeOptions { - func writeToOutput(_ string: String) { +extension LintOrAnalyzeOptions { + fileprivate func writeToOutput(_ string: String) { guard let outFile = output else { queuedPrint(string) return @@ -411,6 +414,15 @@ private extension LintOrAnalyzeOptions { Issue.fileNotWritable(path: outFile).print() } } + + typealias Leniency = (strict: Bool, lenient: Bool) + + // Config file settings can be overridden by either `--strict` or `--lenient` command line options. + func leniency(strict configurationStrict: Bool, lenient configurationLenient: Bool) -> Leniency { + let strict = self.strict || (configurationStrict && !self.lenient) + let lenient = self.lenient || (configurationLenient && !self.strict) + return Leniency(strict: strict, lenient: lenient) + } } private actor CorrectionsBuilder { diff --git a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift index ffca2d57ab..9fd493a068 100644 --- a/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift +++ b/Tests/SwiftLintFrameworkTests/ConfigurationTests.swift @@ -56,6 +56,7 @@ final class ConfigurationTests: SwiftLintTestCase { XCTAssertEqual(reporterFrom(identifier: config.reporter).identifier, "xcode") XCTAssertFalse(config.allowZeroLintableFiles) XCTAssertFalse(config.strict) + XCTAssertFalse(config.lenient) XCTAssertNil(config.baseline) XCTAssertNil(config.writeBaseline) XCTAssertFalse(config.checkForUpdates) @@ -458,6 +459,11 @@ final class ConfigurationTests: SwiftLintTestCase { XCTAssertTrue(configuration.strict) } + func testLenient() throws { + let configuration = try Configuration(dict: ["lenient": true]) + XCTAssertTrue(configuration.lenient) + } + func testBaseline() throws { let baselinePath = "Baseline.json" let configuration = try Configuration(dict: ["baseline": baselinePath]) diff --git a/Tests/SwiftLintFrameworkTests/LintOrAnalyzeOptionsTests.swift b/Tests/SwiftLintFrameworkTests/LintOrAnalyzeOptionsTests.swift new file mode 100644 index 0000000000..07ec490791 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/LintOrAnalyzeOptionsTests.swift @@ -0,0 +1,72 @@ +@testable import SwiftLintFramework +import XCTest + +final class LintOrAnalyzeOptionsTests: XCTestCase { + private typealias Leniency = LintOrAnalyzeOptions.Leniency + + func testLeniency() { + let parameters = [ + Leniency(strict: false, lenient: false), + Leniency(strict: true, lenient: true), + Leniency(strict: true, lenient: false), + Leniency(strict: false, lenient: true), + ] + + for commandLine in parameters { + let options = LintOrAnalyzeOptions(leniency: commandLine) + for configuration in parameters { + let leniency = options.leniency(strict: configuration.strict, lenient: configuration.lenient) + if commandLine.strict { + // Command line takes precedence. + XCTAssertTrue(leniency.strict) + if !commandLine.lenient { + // `--strict` should disable configuration lenience. + XCTAssertFalse(leniency.lenient) + } + } else if commandLine.lenient { + // Command line takes precedence, and should override + // `strict` in the configuration. + XCTAssertTrue(leniency.lenient) + XCTAssertFalse(leniency.strict) + } else if configuration.strict { + XCTAssertTrue(leniency.strict) + } else if configuration.lenient { + XCTAssertTrue(leniency.lenient) + } + } + } + } +} + +private extension LintOrAnalyzeOptions { + init(leniency: Leniency) { + self.init(mode: .lint, + paths: [], + useSTDIN: true, + configurationFiles: [], + strict: leniency.strict, + lenient: leniency.lenient, + forceExclude: false, + useExcludingByPrefix: false, + useScriptInputFiles: false, + useScriptInputFileLists: false, + benchmark: false, + reporter: nil, + baseline: nil, + writeBaseline: nil, + workingDirectory: nil, + quiet: false, + output: nil, + progress: false, + cachePath: nil, + ignoreCache: false, + enableAllRules: false, + onlyRule: [], + autocorrect: false, + format: false, + compilerLogPath: nil, + compileCommands: nil, + checkForUpdates: false + ) + } +} From a7318316d997b8db8ee440fab1b9312a2a4b9287 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2024 11:14:54 -0500 Subject: [PATCH 239/265] Bump rexml from 3.3.6 to 3.3.9 (#5842) Bumps the bundler group with 1 update in the / directory: [rexml](https://github.com/ruby/rexml). Updates `rexml` from 3.3.6 to 3.3.9 - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.6...v3.3.9) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect dependency-group: bundler ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5e6967364c..c0a88b3b3d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -122,8 +122,7 @@ GEM public_suffix (4.0.7) rchardet (1.8.0) redcarpet (3.6.0) - rexml (3.3.6) - strscan + rexml (3.3.9) rouge (4.3.0) ruby-macho (2.5.1) ruby2_keywords (0.0.5) @@ -134,7 +133,6 @@ GEM faraday (>= 0.17.3, < 3) sqlite3 (1.7.3-arm64-darwin) sqlite3 (1.7.3-x86_64-linux) - strscan (3.1.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) typhoeus (1.4.0) From 3344fc6d31b921b333f601b185f2da75e342a567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 10 Nov 2024 15:32:16 +0100 Subject: [PATCH 240/265] Add cache path and directories only when commands accept them (#5851) --- CHANGELOG.md | 5 +++++ .../SwiftLintCommandPlugin.swift | 22 +++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffb00ebc19..cfdf749b3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5167](https://github.com/realm/SwiftLint/issues/5167) +* Only pass cache path and directory paths to commands that accept these arguments + in the command plugin. + [SimplyDanny](https://github.com/SimplyDanny) + [#5848](https://github.com/realm/SwiftLint/issues/5848) + * Do not throw deprecation warning if deprecated property is not presented in configuration. [chipp](https://github.com/chipp) diff --git a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift index d254ff8fdd..e1f562fd18 100644 --- a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift +++ b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift @@ -1,6 +1,19 @@ import Foundation import PackagePlugin +private let commandsNotExpectingPaths: Set = [ + "docs", + "generate-docs", + "baseline", + "reporters", + "rules", + "version", +] + +private let commandsWithoutCachPathOption: Set = commandsNotExpectingPaths.union([ + "analyze", +]) + @main struct SwiftLintCommandPlugin: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) throws { @@ -13,7 +26,7 @@ struct SwiftLintCommandPlugin: CommandPlugin { let targets = targetNames.isEmpty ? context.package.targets : try context.package.targets(named: targetNames) - guard !targets.isEmpty else { + if targets.isEmpty || !commandsNotExpectingPaths.isDisjoint(with: arguments) { try run(with: context, arguments: arguments) return } @@ -34,11 +47,12 @@ struct SwiftLintCommandPlugin: CommandPlugin { process.currentDirectoryURL = URL(fileURLWithPath: context.package.directory.string) process.executableURL = URL(fileURLWithPath: try context.tool(named: "swiftlint").path.string) process.arguments = arguments - if !arguments.contains("analyze") { - // The analyze command does not support the `--cache-path` argument. + if commandsWithoutCachPathOption.isDisjoint(with: arguments) { process.arguments! += ["--cache-path", "\(context.pluginWorkDirectory.string)"] } - process.arguments! += [directory] + if commandsNotExpectingPaths.isDisjoint(with: arguments) { + process.arguments! += [directory] + } try process.run() process.waitUntilExit() From fb3ce5adb226878de61f4754591868a71d5ffa1e Mon Sep 17 00:00:00 2001 From: Jared Grubb <1256381+jaredgrubb@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:27:59 -0800 Subject: [PATCH 241/265] Add `ignore_properties` option to `redundant_type_annotation` rule (#5839) --- CHANGELOG.md | 7 ++++++ .../RedundantTypeAnnotationRule.swift | 25 ++++++++++++++++++- ...RedundantTypeAnnotationConfiguration.swift | 2 ++ .../default_rule_configurations.yml | 1 + 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfdf749b3a..3be513f1c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,13 @@ [Martin Redington](https://github.com/mildm8nnered) [#5801](https://github.com/realm/SwiftLint/issues/5801) +* The `redundant_type_annotation` rule gains a new option, + `ignore_properties`, that skips enforcement on members in a + type declaration (like a `struct`). This helps the rule coexist with + the `explicit_type_interface` rule that requires such redundancy. + [jaredgrubb](https://github.com/jaredgrubb) + [#3750](https://github.com/realm/SwiftLint/issues/3750) + #### Bug Fixes * Run command plugin in whole package if no targets are defined in the diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift index 019ff40ac0..ac7b3047bc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/RedundantTypeAnnotationRule.swift @@ -57,6 +57,12 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { Example("var dbl: Double = 0.0"), Example("var int: Int = 0"), Example("var str: String = \"str\""), + Example(""" + struct Foo { + var url: URL = URL() + let myVar: Int? = 0, s: String = "" + } + """, configuration: ["ignore_properties": true]), ], triggeringExamples: [ Example("var url↓:URL=URL()"), @@ -88,6 +94,13 @@ struct RedundantTypeAnnotationRule: OptInRule, SwiftSyntaxCorrectableRule { } } """), + Example(""" + class ViewController: UIViewController { + func someMethod() { + let myVar↓: Int = Int(5) + } + } + """, configuration: ["ignore_properties": true]), Example("let a↓: [Int] = [Int]()"), Example("let a↓: A.B = A.B()"), Example(""" @@ -183,7 +196,7 @@ private extension RedundantTypeAnnotationRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: PatternBindingSyntax) { if let varDecl = node.parent?.parent?.as(VariableDeclSyntax.self), - configuration.ignoreAttributes.allSatisfy({ !varDecl.attributes.contains(attributeNamed: $0) }), + !configuration.shouldSkipRuleCheck(for: varDecl), let typeAnnotation = node.typeAnnotation, let initializer = node.initializer?.value { collectViolation(forType: typeAnnotation, withInitializer: initializer) @@ -261,3 +274,13 @@ private extension SyntaxKind { } } } + +extension RedundantTypeAnnotationConfiguration { + func shouldSkipRuleCheck(for varDecl: VariableDeclSyntax) -> Bool { + if ignoreAttributes.contains(where: { varDecl.attributes.contains(attributeNamed: $0) }) { + return true + } + + return ignoreProperties && varDecl.parent?.is(MemberBlockItemSyntax.self) == true + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift index 3eb9596298..7bb54dacfa 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/RedundantTypeAnnotationConfiguration.swift @@ -8,6 +8,8 @@ struct RedundantTypeAnnotationConfiguration: SeverityBasedRuleConfiguration { var severityConfiguration = SeverityConfiguration(.warning) @ConfigurationElement(key: "ignore_attributes") var ignoreAttributes = Set(["IBInspectable"]) + @ConfigurationElement(key: "ignore_properties") + private(set) var ignoreProperties = false @ConfigurationElement(key: "consider_default_literal_types_redundant") private(set) var considerDefaultLiteralTypesRedundant = false } diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 57148068b8..f9014e5743 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -473,6 +473,7 @@ redundant_string_enum_value: redundant_type_annotation: severity: warning ignore_attributes: ["IBInspectable"] + ignore_properties: false consider_default_literal_types_redundant: false redundant_void_return: severity: warning From 707a63daf0ec5054e22fe32edc3614fa27efa5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 16 Nov 2024 11:25:50 +0100 Subject: [PATCH 242/265] Allow closures being directly called to be wrapped into parentheses (#5856) --- CHANGELOG.md | 5 +++++ .../Rules/Style/ControlStatementRule.swift | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3be513f1c8..f02dc71941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5787](https://github.com/realm/SwiftLint/issues/5787) +* Stop triggering the `control_statement` rule on closures being directly + called as conditions. + [SimplyDanny](https://github.com/SimplyDanny) + [#5846](https://github.com/realm/SwiftLint/issues/5846) + * Do not trigger `self_in_property_initialization` rule on `self` in key paths expressions. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift index 8afd46d354..1ba85155d5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ControlStatementRule.swift @@ -29,6 +29,8 @@ struct ControlStatementRule: Rule { Example("switch (lhs, rhs) {}"), Example("if (f() { g() {} }) {}"), Example("if (a + f() {} == 1) {}"), + Example("if ({ true }()) {}"), + Example("if ({if i < 1 { true } else { false }}()) {}", excludeFromDocumentation: true), ], triggeringExamples: [ Example("↓if (condition) {}"), @@ -176,7 +178,7 @@ private extension ExprSyntax { private func containsTrailingClosure(_ node: Syntax) -> Bool { switch node.as(SyntaxEnum.self) { case .functionCallExpr(let node): - node.trailingClosure != nil + node.trailingClosure != nil || node.calledExpression.is(ClosureExprSyntax.self) case .sequenceExpr(let node): node.elements.contains { containsTrailingClosure(Syntax($0)) } default: false From cafed078fad538266b3e2dfeacce77f92e7fe77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 16 Nov 2024 22:54:59 +0100 Subject: [PATCH 243/265] Silence `superfluous_else` rule for availability conditions (#5857) --- CHANGELOG.md | 5 +++++ .../Rules/Style/SuperfluousElseRule.swift | 14 ++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f02dc71941..53845564f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,11 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5787](https://github.com/realm/SwiftLint/issues/5787) +* Silence `superfluous_else` rule on `if` expressions with only a single + availability condition. + [SimplyDanny](https://github.com/SimplyDanny) + [#5833](https://github.com/realm/SwiftLint/issues/5833) + * Stop triggering the `control_statement` rule on closures being directly called as conditions. [SimplyDanny](https://github.com/SimplyDanny) diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift index c2d5bfffbf..d15ddd7322 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/SuperfluousElseRule.swift @@ -69,6 +69,13 @@ struct SuperfluousElseRule: OptInRule { } } """), + Example(""" + if #available(iOS 13, *) { + return + } else { + deprecatedFunction() + } + """), ], triggeringExamples: [ Example(""" @@ -324,10 +331,9 @@ private extension SuperfluousElseRule { private extension IfExprSyntax { var superfluousElse: TokenSyntax? { - if elseKeyword == nil { - return nil - } - if !lastStatementExitsScope(in: body) { + guard elseKeyword != nil, + conditions.onlyElement?.condition.is(AvailabilityConditionSyntax.self) != true, + lastStatementExitsScope(in: body) else { return nil } if let parent = parent?.as(IfExprSyntax.self) { From 9e61e81748b4f14018a0f8e8fd616abac478dda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 17 Nov 2024 00:00:57 +0100 Subject: [PATCH 244/265] Rework algorithm used in `function_default_parameter_at_end` rule (#5858) --- .../FunctionDefaultParameterAtEndRule.swift | 99 ++++++++----------- 1 file changed, 42 insertions(+), 57 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift index 764162b808..bbbdd4916c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift @@ -42,11 +42,14 @@ struct FunctionDefaultParameterAtEndRule: OptInRule { Example(""" func expect(file: String = #file, _ expression: @autoclosure () -> (() throws -> T)) -> Expectation {} """, excludeFromDocumentation: true), + Example("func foo(bar: Int, baz: Int = 0, z: () -> Void) {}"), + Example("func foo(bar: Int, baz: Int = 0, z: () -> Void, x: Int = 0) {}"), ], triggeringExamples: [ - Example("↓func foo(bar: Int = 0, baz: String) {}"), - Example("private ↓func foo(bar: Int = 0, baz: String) {}"), - Example("public ↓init?(for date: Date = Date(), coordinate: CLLocationCoordinate2D) {}"), + Example("func foo(↓bar: Int = 0, baz: String) {}"), + Example("private func foo(↓bar: Int = 0, baz: String) {}"), + Example("public init?(↓for date: Date = Date(), coordinate: CLLocationCoordinate2D) {}"), + Example("func foo(bar: Int, ↓baz: Int = 0, z: () -> Void, x: Int) {}"), ] ) } @@ -54,76 +57,58 @@ struct FunctionDefaultParameterAtEndRule: OptInRule { private extension FunctionDefaultParameterAtEndRule { final class Visitor: ViolationsSyntaxVisitor { override func visitPost(_ node: FunctionDeclSyntax) { - guard !node.modifiers.contains(keyword: .override), node.signature.containsViolation else { - return + if !node.modifiers.contains(keyword: .override) { + collectViolations(for: node.signature) } - - violations.append(node.funcKeyword.positionAfterSkippingLeadingTrivia) } override func visitPost(_ node: InitializerDeclSyntax) { - guard !node.modifiers.contains(keyword: .override), node.signature.containsViolation else { - return + if !node.modifiers.contains(keyword: .override) { + collectViolations(for: node.signature) } - - violations.append(node.initKeyword.positionAfterSkippingLeadingTrivia) - } - } -} - -private extension FunctionSignatureSyntax { - var containsViolation: Bool { - let params = parameterClause.parameters.filter { param in - !param.isClosure } - guard params.isNotEmpty else { - return false - } - - let defaultParams = params.filter { param in - param.defaultValue != nil - } - guard defaultParams.isNotEmpty else { - return false - } - - let lastParameters = params.suffix(defaultParams.count) - let lastParametersWithDefaultValue = lastParameters.filter { param in - param.defaultValue != nil + private func collectViolations(for signature: FunctionSignatureSyntax) { + if signature.parameterClause.parameters.count < 2 { + return + } + var previousWithDefault = true + for param in signature.parameterClause.parameters.reversed() { + if param.isClosure { + continue + } + let hasDefault = param.defaultValue != nil + if !previousWithDefault, hasDefault { + violations.append(param.positionAfterSkippingLeadingTrivia) + } + previousWithDefault = hasDefault + } } - - return lastParameters.count != lastParametersWithDefaultValue.count } } private extension FunctionParameterSyntax { var isClosure: Bool { - if isEscaping || type.is(FunctionTypeSyntax.self) { - return true - } - - if let optionalType = type.as(OptionalTypeSyntax.self), - let tuple = optionalType.wrappedType.as(TupleTypeSyntax.self) { - return tuple.elements.onlyElement?.type.as(FunctionTypeSyntax.self) != nil - } - - if let tuple = type.as(TupleTypeSyntax.self) { - return tuple.elements.onlyElement?.type.as(FunctionTypeSyntax.self) != nil - } - - if let attrType = type.as(AttributedTypeSyntax.self) { - return attrType.baseType.is(FunctionTypeSyntax.self) - } - - return false + isEscaping || type.isFunctionType } var isEscaping: Bool { - guard let attrType = type.as(AttributedTypeSyntax.self) else { - return false - } + type.as(AttributedTypeSyntax.self)?.attributes.contains(attributeNamed: "escaping") == true + } +} - return attrType.attributes.contains(attributeNamed: "escaping") +private extension TypeSyntax { + var isFunctionType: Bool { + if `is`(FunctionTypeSyntax.self) { + true + } else if let optionalType = `as`(OptionalTypeSyntax.self) { + optionalType.wrappedType.isFunctionType + } else if let tupleType = `as`(TupleTypeSyntax.self) { + tupleType.elements.onlyElement?.type.isFunctionType == true + } else if let attributedType = `as`(AttributedTypeSyntax.self) { + attributedType.baseType.isFunctionType + } else { + false + } } } From 025b1e7f739bcef71b0cb1f6e9a0d82f07fc56de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 17 Nov 2024 15:35:09 +0100 Subject: [PATCH 245/265] Allow inherited isolation parameter to be first in function signatures (#5859) --- CHANGELOG.md | 6 ++++++ .../FunctionDefaultParameterAtEndRule.swift | 21 ++++++++++++++++--- ...onDefaultParameterAtEndConfiguration.swift | 13 ++++++++++++ .../default_rule_configurations.yml | 1 + 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionDefaultParameterAtEndConfiguration.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 53845564f2..3f6380f8d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,12 @@ [jaredgrubb](https://github.com/jaredgrubb) [#3750](https://github.com/realm/SwiftLint/issues/3750) +* Allow inherited isolation parameter to be first in function signatures + depending on the new option `ignore_first_isolation_inheritance_parameter` + which is `true` by default. + [SimplyDanny](https://github.com/SimplyDanny) + [#5793](https://github.com/realm/SwiftLint/issues/5793) + #### Bug Fixes * Run command plugin in whole package if no targets are defined in the diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift index bbbdd4916c..a949725fbf 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FunctionDefaultParameterAtEndRule.swift @@ -2,7 +2,7 @@ import SwiftSyntax @SwiftSyntaxRule struct FunctionDefaultParameterAtEndRule: OptInRule { - var configuration = SeverityConfiguration(.warning) + var configuration = FunctionDefaultParameterAtEndConfiguration() static let description = RuleDescription( identifier: "function_default_parameter_at_end", @@ -44,12 +44,17 @@ struct FunctionDefaultParameterAtEndRule: OptInRule { """, excludeFromDocumentation: true), Example("func foo(bar: Int, baz: Int = 0, z: () -> Void) {}"), Example("func foo(bar: Int, baz: Int = 0, z: () -> Void, x: Int = 0) {}"), + Example("func foo(isolation: isolated (any Actor)? = #isolation, bar: String) {}"), ], triggeringExamples: [ Example("func foo(↓bar: Int = 0, baz: String) {}"), Example("private func foo(↓bar: Int = 0, baz: String) {}"), Example("public init?(↓for date: Date = Date(), coordinate: CLLocationCoordinate2D) {}"), Example("func foo(bar: Int, ↓baz: Int = 0, z: () -> Void, x: Int) {}"), + Example( + "func foo(isolation: isolated (any Actor)? = #isolation, bar: String) {}", + configuration: ["ignore_first_isolation_inheritance_parameter": false] + ), ] ) } @@ -69,16 +74,22 @@ private extension FunctionDefaultParameterAtEndRule { } private func collectViolations(for signature: FunctionSignatureSyntax) { - if signature.parameterClause.parameters.count < 2 { + let numberOfParameters = signature.parameterClause.parameters.count + if numberOfParameters < 2 { return } var previousWithDefault = true - for param in signature.parameterClause.parameters.reversed() { + for (index, param) in signature.parameterClause.parameters.reversed().enumerated() { if param.isClosure { continue } let hasDefault = param.defaultValue != nil if !previousWithDefault, hasDefault { + if index + 1 == numberOfParameters, + param.isInheritedIsolation, + configuration.ignoreFirstIsolationInheritanceParameter { + break // It's the last element anyway. + } violations.append(param.positionAfterSkippingLeadingTrivia) } previousWithDefault = hasDefault @@ -95,6 +106,10 @@ private extension FunctionParameterSyntax { var isEscaping: Bool { type.as(AttributedTypeSyntax.self)?.attributes.contains(attributeNamed: "escaping") == true } + + var isInheritedIsolation: Bool { + defaultValue?.value.as(MacroExpansionExprSyntax.self)?.macroName.text == "isolation" + } } private extension TypeSyntax { diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionDefaultParameterAtEndConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionDefaultParameterAtEndConfiguration.swift new file mode 100644 index 0000000000..71d4d33bbd --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FunctionDefaultParameterAtEndConfiguration.swift @@ -0,0 +1,13 @@ +import SwiftLintCore + +@AutoConfigParser +struct FunctionDefaultParameterAtEndConfiguration: SeverityBasedRuleConfiguration { + // swiftlint:disable:previous type_name + + typealias Parent = FunctionDefaultParameterAtEndRule + + @ConfigurationElement(key: "severity") + private(set) var severityConfiguration = SeverityConfiguration(.warning) + @ConfigurationElement(key: "ignore_first_isolation_inheritance_parameter") + private(set) var ignoreFirstIsolationInheritanceParameter = true +} diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index f9014e5743..bbb19d493b 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -204,6 +204,7 @@ function_body_length: error: 100 function_default_parameter_at_end: severity: warning + ignore_first_isolation_inheritance_parameter: true function_parameter_count: warning: 5 error: 8 From 2c7e7230b0af3c7160bff936e9518e83c76dcbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 17 Nov 2024 15:40:39 +0100 Subject: [PATCH 246/265] Support type casting on configuration option values defined by environment variables (#5860) --- CHANGELOG.md | 6 +++ Source/SwiftLintCore/Models/YamlParser.swift | 42 +++++++----------- .../YamlParserTests.swift | 44 +++++++++++++++++++ 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f6380f8d6..86b26568b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,12 @@ [Martin Redington](https://github.com/mildm8nnered) [#5801](https://github.com/realm/SwiftLint/issues/5801) +* Support type casting on configuration option values defined by environment variables. + Without a cast, these values would always be treated as strings leading to a potentially + invalid configuration. + [SimplyDanny](https://github.com/SimplyDanny) + [#5774](https://github.com/realm/SwiftLint/issues/5774) + * The `redundant_type_annotation` rule gains a new option, `ignore_properties`, that skips enforcement on members in a type declaration (like a `struct`). This helps the rule coexist with diff --git a/Source/SwiftLintCore/Models/YamlParser.swift b/Source/SwiftLintCore/Models/YamlParser.swift index ab4af13f87..018478a927 100644 --- a/Source/SwiftLintCore/Models/YamlParser.swift +++ b/Source/SwiftLintCore/Models/YamlParser.swift @@ -31,40 +31,28 @@ private extension Constructor { static func customScalarMap(env: [String: String]) -> ScalarMap { var map = defaultScalarMap - map[.str] = String.constructExpandingEnvVars(env: env) - map[.bool] = Bool.constructUsingOnlyTrueAndFalse - + map[.str] = { $0.string.expandingEnvVars(env: env) } + map[.bool] = { + switch $0.string.expandingEnvVars(env: env).lowercased() { + case "true": true + case "false": false + default: nil + } + } + map[.int] = { Int($0.string.expandingEnvVars(env: env)) } + map[.float] = { Double($0.string.expandingEnvVars(env: env)) } return map } } private extension String { - static func constructExpandingEnvVars(env: [String: String]) -> (_ scalar: Node.Scalar) -> String? { - { (scalar: Node.Scalar) -> String? in - scalar.string.expandingEnvVars(env: env) - } - } - func expandingEnvVars(env: [String: String]) -> String { - var result = self - for (key, value) in env { - result = result.replacingOccurrences(of: "${\(key)}", with: value) + guard contains("${") else { + // No environment variables used. + return self } - - return result - } -} - -private extension Bool { - // swiftlint:disable:next discouraged_optional_boolean - static func constructUsingOnlyTrueAndFalse(from scalar: Node.Scalar) -> Bool? { - switch scalar.string.lowercased() { - case "true": - return true - case "false": - return false - default: - return nil + return env.reduce(into: self) { result, envVar in + result = result.replacingOccurrences(of: "${\(envVar.key)}", with: envVar.value) } } } diff --git a/Tests/SwiftLintFrameworkTests/YamlParserTests.swift b/Tests/SwiftLintFrameworkTests/YamlParserTests.swift index 4ab1322673..4e36027c76 100644 --- a/Tests/SwiftLintFrameworkTests/YamlParserTests.swift +++ b/Tests/SwiftLintFrameworkTests/YamlParserTests.swift @@ -53,4 +53,48 @@ final class YamlParserTests: SwiftLintTestCase { _ = try YamlParser.parse("|\na", env: [:]) } } + + func testTreatAllEnvVarsAsStringsWithoutCasting() throws { + let env = [ + "INT": "1", + "FLOAT": "1.0", + "BOOL": "true", + "STRING": "string", + ] + let string = """ + int: ${INT} + float: ${FLOAT} + bool: ${BOOL} + string: ${STRING} + """ + + let result = try YamlParser.parse(string, env: env) + + XCTAssertEqual(result["int"] as? String, "1") + XCTAssertEqual(result["float"] as? String, "1.0") + XCTAssertEqual(result["bool"] as? String, "true") + XCTAssertEqual(result["string"] as? String, "string") + } + + func testRespectCastsOnEnvVars() throws { + let env = [ + "INT": "1", + "FLOAT": "1.0", + "BOOL": "true", + "STRING": "string", + ] + let string = """ + int: !!int ${INT} + float: !!float ${FLOAT} + bool: !!bool ${BOOL} + string: !!str ${STRING} + """ + + let result = try YamlParser.parse(string, env: env) + + XCTAssertEqual(result["int"] as? Int, 1) + XCTAssertEqual(result["float"] as? Double, 1.0) + XCTAssertEqual(result["bool"] as? Bool, true) + XCTAssertEqual(result["string"] as? String, "string") + } } From 086f1b37e2e75155aa2f80b44b7dec0aad3d02d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 17 Nov 2024 15:55:57 +0100 Subject: [PATCH 247/265] Sync build settings and options (#5861) --- Package.swift | 8 +++++--- Tests/BUILD | 13 ++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 2789c2fef6..0e85adeb96 100644 --- a/Package.swift +++ b/Package.swift @@ -90,7 +90,7 @@ let package = Package( .target( name: "SwiftLintExtraRules", dependencies: ["SwiftLintCore"], - swiftSettings: strictConcurrency + swiftSettings: swiftFeatures + strictConcurrency ), .target( name: "SwiftLintFramework", @@ -108,7 +108,8 @@ let package = Package( dependencies: [ "SwiftLintFramework" ], - path: "Tests/SwiftLintTestHelpers" + path: "Tests/SwiftLintTestHelpers", + swiftSettings: swiftFeatures ), .testTarget( name: "SwiftLintFrameworkTests", @@ -146,7 +147,8 @@ let package = Package( dependencies: [ "SwiftLintFramework", "SwiftLintTestHelpers", - ] + ], + swiftSettings: swiftFeatures ), .macro( name: "SwiftLintCoreMacros", diff --git a/Tests/BUILD b/Tests/BUILD index 01aa65395c..2c846a7625 100644 --- a/Tests/BUILD +++ b/Tests/BUILD @@ -2,7 +2,18 @@ load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library", "swift_test") exports_files(["BUILD"]) -copts = ["-enable-upcoming-feature", "ExistentialAny"] +copts = [ + "-enable-upcoming-feature", + "ExistentialAny", + "-enable-upcoming-feature", + "ConciseMagicFile", + "-enable-upcoming-feature", + "ImportObjcForwardDeclarations", + "-enable-upcoming-feature", + "ForwardTrailingClosures", + "-enable-upcoming-feature", + "ImplicitOpenExistentials", +] # CLITests From c784adcb034fb20d1d2445f595125206d16227c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 19 Nov 2024 22:58:57 +0100 Subject: [PATCH 248/265] Pass only remaining arguments to `swiftlint` command (#5865) Missing part of 7904d9a. --- .../SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift index e1f562fd18..ec82ec5782 100644 --- a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift +++ b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift @@ -26,8 +26,9 @@ struct SwiftLintCommandPlugin: CommandPlugin { let targets = targetNames.isEmpty ? context.package.targets : try context.package.targets(named: targetNames) - if targets.isEmpty || !commandsNotExpectingPaths.isDisjoint(with: arguments) { - try run(with: context, arguments: arguments) + let remainingArguments = argExtractor.remainingArguments + if targets.isEmpty || !commandsNotExpectingPaths.isDisjoint(with: remainingArguments) { + try run(with: context, arguments: remainingArguments) return } for target in targets { @@ -35,7 +36,7 @@ struct SwiftLintCommandPlugin: CommandPlugin { Diagnostics.warning("Target '\(target.name)' is not a source module; skipping it") continue } - try run(in: target.directory.string, for: target.name, with: context, arguments: arguments) + try run(in: target.directory.string, for: target.name, with: context, arguments: remainingArguments) } } From 2a723d00428a441d5289459ca18ec9c2a844886b Mon Sep 17 00:00:00 2001 From: Kim de Vos Date: Sun, 24 Nov 2024 15:14:08 +0100 Subject: [PATCH 249/265] Add new option `max_number_of_single_line_parameters ` to `multiline_parameters` rule (#5781) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- CHANGELOG.md | 8 ++++ .../MultilineParametersConfiguration.swift | 25 ++++++++++++ .../Rules/Style/MultilineParametersRule.swift | 6 +++ .../MultilineParametersRuleExamples.swift | 14 +++++++ ...ultilineParametersConfigurationTests.swift | 39 +++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 Tests/SwiftLintFrameworkTests/MultilineParametersConfigurationTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 86b26568b8..38ccb1a959 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,14 @@ [SimplyDanny](https://github.com/SimplyDanny) [#5774](https://github.com/realm/SwiftLint/issues/5774) +* Add new option `max_number_of_single_line_parameters` that allows only the specified maximum + number of parameters to be on one line when `allows_single_line = true`. If the limit is + exceeded, the rule will still trigger. Confusing option combinations like `allows_single_line = false` + together with `max_number_of_single_line_parameters > 1` will be reported. + [kimdv](https://github.com/kimdv) + [SimplyDanny](https://github.com/SimplyDanny) + [#5781](https://github.com/realm/SwiftLint/issues/5781) + * The `redundant_type_annotation` rule gains a new option, `ignore_properties`, that skips enforcement on members in a type declaration (like a `struct`). This helps the rule coexist with diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift index f8705d7cb0..22c3cd470c 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/MultilineParametersConfiguration.swift @@ -8,4 +8,29 @@ struct MultilineParametersConfiguration: SeverityBasedRuleConfiguration { private(set) var severityConfiguration = SeverityConfiguration(.warning) @ConfigurationElement(key: "allows_single_line") private(set) var allowsSingleLine = true + @ConfigurationElement(key: "max_number_of_single_line_parameters") + private(set) var maxNumberOfSingleLineParameters: Int? + + func validate() throws { + guard let maxNumberOfSingleLineParameters else { + return + } + guard maxNumberOfSingleLineParameters >= 1 else { + Issue.inconsistentConfiguration( + ruleID: Parent.identifier, + message: "Option '\($maxNumberOfSingleLineParameters.key)' should be >= 1." + ).print() + return + } + + if maxNumberOfSingleLineParameters > 1, !allowsSingleLine { + Issue.inconsistentConfiguration( + ruleID: Parent.identifier, + message: """ + Option '\($maxNumberOfSingleLineParameters.key)' has no effect when \ + '\($allowsSingleLine.key)' is false. + """ + ).print() + } + } } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRule.swift index 281e97a504..72f25152c0 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRule.swift @@ -43,6 +43,12 @@ private extension MultilineParametersRule { numberOfParameters += 1 } + if let maxNumberOfSingleLineParameters = configuration.maxNumberOfSingleLineParameters, + configuration.allowsSingleLine, + numberOfParameters > maxNumberOfSingleLineParameters { + return true + } + guard linesWithParameters.count > (configuration.allowsSingleLine ? 1 : 0), numberOfParameters != linesWithParameters.count else { return false diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift index e87e35359b..4abcb60e39 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/MultilineParametersRuleExamples.swift @@ -197,6 +197,13 @@ internal struct MultilineParametersRuleExamples { ) { } } """, configuration: ["allows_single_line": false]), + Example("func foo(param1: Int, param2: Bool, param3: [String]) { }", + configuration: ["max_number_of_single_line_parameters": 3]), + Example(""" + func foo(param1: Int, + param2: Bool, + param3: [String]) { } + """, configuration: ["max_number_of_single_line_parameters": 3]), ] static let triggeringExamples: [Example] = [ @@ -336,5 +343,12 @@ internal struct MultilineParametersRuleExamples { configuration: ["allows_single_line": false]), Example("func ↓foo(param1: Int, param2: Bool, param3: [String]) { }", configuration: ["allows_single_line": false]), + Example("func ↓foo(param1: Int, param2: Bool, param3: [String]) { }", + configuration: ["max_number_of_single_line_parameters": 2]), + Example(""" + func ↓foo(param1: Int, + param2: Bool, param3: [String]) { } + """, + configuration: ["max_number_of_single_line_parameters": 3]), ] } diff --git a/Tests/SwiftLintFrameworkTests/MultilineParametersConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/MultilineParametersConfigurationTests.swift new file mode 100644 index 0000000000..2114d6409e --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/MultilineParametersConfigurationTests.swift @@ -0,0 +1,39 @@ +@testable import SwiftLintBuiltInRules +@testable import SwiftLintCore +import XCTest + +final class MultilineParametersConfigurationTests: SwiftLintTestCase { + func testInvalidMaxNumberOfSingleLineParameters() throws { + for maxNumberOfSingleLineParameters in [0, -1] { + var config = MultilineParametersConfiguration() + + XCTAssertEqual( + try Issue.captureConsole { + try config.apply( + configuration: ["max_number_of_single_line_parameters": maxNumberOfSingleLineParameters] + ) + }, + """ + warning: Inconsistent configuration for 'multiline_parameters' rule: Option \ + 'max_number_of_single_line_parameters' should be >= 1. + """ + ) + } + } + + func testInvalidMaxNumberOfSingleLineParametersWithSingleLineEnabled() throws { + var config = MultilineParametersConfiguration() + + XCTAssertEqual( + try Issue.captureConsole { + try config.apply( + configuration: ["max_number_of_single_line_parameters": 2, "allows_single_line": false] + ) + }, + """ + warning: Inconsistent configuration for 'multiline_parameters' rule: Option \ + 'max_number_of_single_line_parameters' has no effect when 'allows_single_line' is false. + """ + ) + } +} From 236c29ac2820644bf70d303eeb710b9d67d74fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 24 Nov 2024 15:26:07 +0100 Subject: [PATCH 250/265] Create releases as drafts --- tools/create-github-release.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/create-github-release.sh b/tools/create-github-release.sh index 1c9ff0cefe..7a671b9d20 100755 --- a/tools/create-github-release.sh +++ b/tools/create-github-release.sh @@ -12,11 +12,11 @@ release_notes=$(mktemp) # Create GitHub Release release_title="$(sed -n '1s/^## //p' CHANGELOG.md)" -gh release create "$version" --title "$release_title" -F "$release_notes" \ - "bazel.tar.gz" \ - "bazel.tar.gz.sha256" \ - "portable_swiftlint.zip" \ - "SwiftLint.pkg" \ +gh release create "$version" --title "$release_title" -F "$release_notes" --draft \ + "bazel.tar.gz" \ + "bazel.tar.gz.sha256" \ + "portable_swiftlint.zip" \ + "SwiftLint.pkg" \ "SwiftLintBinary-macos.artifactbundle.zip" rm "$release_notes" From 25f2776977e663305bee71309ea1e34d435065f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 24 Nov 2024 16:06:56 +0100 Subject: [PATCH 251/265] Release 0.57.1 --- CHANGELOG.md | 2 +- MODULE.bazel | 2 +- Package.swift | 4 ++-- Source/SwiftLintCore/Models/Version.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38ccb1a959..c138090148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Main +## 0.57.1: Squeaky Clean Cycle #### Breaking diff --git a/MODULE.bazel b/MODULE.bazel index 8ec7b30033..ff17e604d9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "swiftlint", - version = "0.57.0", + version = "0.57.1", compatibility_level = 1, repo_name = "SwiftLint", ) diff --git a/Package.swift b/Package.swift index 0e85adeb96..ed79593181 100644 --- a/Package.swift +++ b/Package.swift @@ -174,8 +174,8 @@ let package = Package( package.targets.append( .binaryTarget( name: "SwiftLintBinary", - url: "https://github.com/realm/SwiftLint/releases/download/0.57.0/SwiftLintBinary-macos.artifactbundle.zip", - checksum: "a1bbafe57538077f3abe4cfb004b0464dcd87e8c23611a2153c675574b858b3a" + url: "https://github.com/realm/SwiftLint/releases/download/0.57.1/SwiftLintBinary-macos.artifactbundle.zip", + checksum: "c88bf3e5bc1326d8ca66bc3f9eae786f2094c5172cd70b26b5f07686bb883899" ) ) #endif diff --git a/Source/SwiftLintCore/Models/Version.swift b/Source/SwiftLintCore/Models/Version.swift index d5a8f6e690..9d10c86ea1 100644 --- a/Source/SwiftLintCore/Models/Version.swift +++ b/Source/SwiftLintCore/Models/Version.swift @@ -9,7 +9,7 @@ public struct Version: VersionComparable { } /// The current SwiftLint version. - public static let current = Self(value: "0.57.0") + public static let current = Self(value: "0.57.1") /// Public initializer. /// From 554fd5647edc4bf56f56777c539049580ba34469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 24 Nov 2024 16:07:33 +0100 Subject: [PATCH 252/265] Add new changelog section --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c138090148..67c05bad84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## Main + +#### Breaking + +* None. + +#### Experimental + +* None. + +#### Enhancements + +* None. + +#### Bug Fixes + +* None. + ## 0.57.1: Squeaky Clean Cycle #### Breaking From ece675cae9586c844cf21fa8cc770f38ca2fddb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 24 Nov 2024 16:58:57 +0100 Subject: [PATCH 253/265] Do not use defined event names When this workflow is called from another, the event type will be the one of the caller. Therefore, checking agains `workflow_call` doesn't work. --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 47f6f9f583..7736846b9e 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set Docker tag - if: github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' + if: github.event_name != 'push' && ${{ inputs.tag }} run: echo "DOCKER_TAG=${{ inputs.tag }}" >> $GITHUB_ENV - name: Use default Docker tag if: github.event_name == 'push' From 8ff2518c19848589b3ea423e978fa6855d91c4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 24 Nov 2024 16:59:47 +0100 Subject: [PATCH 254/265] Use Bash <4 compatible method to UPPERCASE a string --- .github/workflows/release.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 51345f51b3..9f6acc511a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,8 +46,9 @@ jobs: - name: Retrieve author in uppercase id: retrieve_author run: | - AUTHOR=${{ github.event.release.author.login }} - echo "name=${AUTHOR@U}" >> $GITHUB_OUTPUT + author=${{ github.event.release.author.login }} + AUTHOR=$(echo $author | tr '[:lower:]' '[:upper:]') + echo "name=${AUTHOR}" >> $GITHUB_OUTPUT - name: Deploy to CocoaPods run: make pod_publish env: From e9ce8ce8bb44e1525c20c141e8e54ae1d427cc46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 24 Nov 2024 17:11:28 +0100 Subject: [PATCH 255/265] Update Gems --- Gemfile.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile.lock b/Gemfile.lock index c0a88b3b3d..c67e893bb2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -154,6 +154,7 @@ PLATFORMS arm64-darwin-21 arm64-darwin-22 arm64-darwin-23 + arm64-darwin-24 x86_64-linux DEPENDENCIES From 9d9156fcc63eeb366598dd2b7134b412395d463f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 26 Nov 2024 19:58:30 +0100 Subject: [PATCH 256/265] Add Xcode command plugin (#5867) --- CHANGELOG.md | 3 +- .../CommandContext.swift | 92 +++++++++++++++++++ .../SwiftLintCommandPlugin.swift | 51 ++++++---- 3 files changed, 125 insertions(+), 21 deletions(-) create mode 100644 Plugins/SwiftLintCommandPlugin/CommandContext.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 67c05bad84..afedac98c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ #### Enhancements -* None. +* Add Xcode command plugin allowing to run SwiftLint from within Xcode. + [SimplyDanny](https://github.com/SimplyDanny) #### Bug Fixes diff --git a/Plugins/SwiftLintCommandPlugin/CommandContext.swift b/Plugins/SwiftLintCommandPlugin/CommandContext.swift new file mode 100644 index 0000000000..bbe39f4640 --- /dev/null +++ b/Plugins/SwiftLintCommandPlugin/CommandContext.swift @@ -0,0 +1,92 @@ +import PackagePlugin + +protocol CommandContext { + var tool: String { get throws } + + var cacheDirectory: String { get } + + var workingDirectory: String { get } + + var unitName: String { get } + + var subUnitName: String { get } + + func targets(named names: [String]) throws -> [(paths: [String], name: String)] +} + +extension PluginContext: CommandContext { + var tool: String { + get throws { + try tool(named: "swiftlint").path.string + } + } + + var cacheDirectory: String { + pluginWorkDirectory.string + } + + var workingDirectory: String { + package.directory.string + } + + var unitName: String { + "package" + } + + var subUnitName: String { + "module" + } + + func targets(named names: [String]) throws -> [(paths: [String], name: String)] { + let targets = names.isEmpty + ? package.targets + : try package.targets(named: names) + return targets.compactMap { target in + guard let target = target.sourceModule else { + Diagnostics.warning("Target '\(target.name)' is not a source module; skipping it") + return nil + } + // Packages have a 1-to-1 mapping between targets and directories. + return (paths: [target.directory.string], name: target.name) + } + } +} + +#if canImport(XcodeProjectPlugin) + +import XcodeProjectPlugin + +extension XcodePluginContext: CommandContext { + var tool: String { + get throws { + try tool(named: "swiftlint").path.string + } + } + + var cacheDirectory: String { + pluginWorkDirectory.string + } + + var workingDirectory: String { + xcodeProject.directory.string + } + + var unitName: String { + "project" + } + + var subUnitName: String { + "target" + } + + func targets(named names: [String]) throws -> [(paths: [String], name: String)] { + if names.isEmpty { + return [(paths: [xcodeProject.directory.string], name: xcodeProject.displayName)] + } + return xcodeProject.targets + .filter { names.contains($0.displayName) } + .map { (paths: $0.inputFiles.map(\.path.string), name: $0.displayName) } + } +} + +#endif diff --git a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift index ec82ec5782..21754b569d 100644 --- a/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift +++ b/Plugins/SwiftLintCommandPlugin/SwiftLintCommandPlugin.swift @@ -17,48 +17,59 @@ private let commandsWithoutCachPathOption: Set = commandsNotExpectingPat @main struct SwiftLintCommandPlugin: CommandPlugin { func performCommand(context: PluginContext, arguments: [String]) throws { + try lintFiles(context: context, arguments: arguments) + } +} + +#if canImport(XcodeProjectPlugin) + +import XcodeProjectPlugin + +extension SwiftLintCommandPlugin: XcodeCommandPlugin { + func performCommand(context: XcodePluginContext, arguments: [String]) throws { + try lintFiles(context: context, arguments: arguments) + } +} + +#endif + +extension SwiftLintCommandPlugin { + private func lintFiles(context: some CommandContext, arguments: [String]) throws { guard !arguments.contains("--cache-path") else { Diagnostics.error("Caching is managed by the plugin and so setting `--cache-path` is not allowed") return } var argExtractor = ArgumentExtractor(arguments) let targetNames = argExtractor.extractOption(named: "target") - let targets = targetNames.isEmpty - ? context.package.targets - : try context.package.targets(named: targetNames) let remainingArguments = argExtractor.remainingArguments - if targets.isEmpty || !commandsNotExpectingPaths.isDisjoint(with: remainingArguments) { - try run(with: context, arguments: remainingArguments) + guard !targetNames.isEmpty, commandsNotExpectingPaths.isDisjoint(with: remainingArguments) else { + try lintFiles(with: context, arguments: remainingArguments) return } - for target in targets { - guard let target = target.sourceModule else { - Diagnostics.warning("Target '\(target.name)' is not a source module; skipping it") - continue - } - try run(in: target.directory.string, for: target.name, with: context, arguments: remainingArguments) + for target in try context.targets(named: targetNames) { + try lintFiles(in: target.paths, for: target.name, with: context, arguments: remainingArguments) } } - private func run(in directory: String = ".", - for targetName: String? = nil, - with context: PluginContext, - arguments: [String]) throws { + private func lintFiles(in paths: [String] = ["."], + for targetName: String? = nil, + with context: some CommandContext, + arguments: [String]) throws { let process = Process() - process.currentDirectoryURL = URL(fileURLWithPath: context.package.directory.string) - process.executableURL = URL(fileURLWithPath: try context.tool(named: "swiftlint").path.string) + process.currentDirectoryURL = URL(fileURLWithPath: context.workingDirectory) + process.executableURL = URL(fileURLWithPath: try context.tool) process.arguments = arguments if commandsWithoutCachPathOption.isDisjoint(with: arguments) { - process.arguments! += ["--cache-path", "\(context.pluginWorkDirectory.string)"] + process.arguments! += ["--cache-path", context.cacheDirectory] } if commandsNotExpectingPaths.isDisjoint(with: arguments) { - process.arguments! += [directory] + process.arguments! += paths } try process.run() process.waitUntilExit() - let module = targetName.map { "module '\($0)'" } ?? "package" + let module = targetName.map { "\(context.subUnitName) '\($0)'" } ?? context.unitName switch process.terminationReason { case .exit: Diagnostics.remark("Finished running in \(module)") From 75e5e05eef3a7a80655c76ffda0aa8294f672626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Tue, 26 Nov 2024 19:59:22 +0100 Subject: [PATCH 257/265] Require write permission for command plugin (#5870) --- CHANGELOG.md | 3 ++- Package.swift | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afedac98c6..e0c71144eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ #### Breaking -* None. +* The command plugin now requires write permissions so that it works with the `--fix` option without an error. + [SimplyDanny](https://github.com/SimplyDanny) #### Experimental diff --git a/Package.swift b/Package.swift index ed79593181..04539c6de3 100644 --- a/Package.swift +++ b/Package.swift @@ -45,7 +45,14 @@ let package = Package( ), .plugin( name: "SwiftLintCommandPlugin", - capability: .command(intent: .custom(verb: "swiftlint", description: "SwiftLint Command Plugin")), + capability: .command( + intent: .custom(verb: "swiftlint", description: "SwiftLint Command Plugin"), + permissions: [ + .writeToPackageDirectory( + reason: "When this command is run with the `--fix` option it may modify source files." + ), + ] + ), dependencies: swiftLintPluginDependencies ), .executableTarget( From b9d33e43ec8102c0de689bf33e4f2395a24835d4 Mon Sep 17 00:00:00 2001 From: fraioli Date: Tue, 26 Nov 2024 12:47:49 -0800 Subject: [PATCH 258/265] Update `file_name` rule to allow fully-qualified names of nested types (#5841) --- CHANGELOG.md | 6 ++ .../Rules/Idiomatic/FileNameRule.swift | 95 ++++++++++++++++--- .../FileNameConfiguration.swift | 2 + .../default_rule_configurations.yml | 1 + .../FileNameRuleTests.swift | 61 ++++++++---- ...Multiple.Levels.Deeply.Nested.MyType.swift | 9 ++ .../FileNameRuleFixtures/MyType.swift | 3 + .../FileNameRuleFixtures/Nested.MyType.swift | 4 + 8 files changed, 147 insertions(+), 34 deletions(-) create mode 100644 Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Multiple.Levels.Deeply.Nested.MyType.swift create mode 100644 Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/MyType.swift create mode 100644 Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Nested.MyType.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c71144eb..d109fa83bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,12 @@ [Martin Redington](https://github.com/mildm8nnered) [#5711](https://github.com/realm/SwiftLint/issues/5711) +* Fixes `file_name` rule to match fully-qualified names of nested types. + Additionally adds a `require_fully_qualified_names` boolean option to enforce + that file names match nested types only using their fully-qualified name. + [fraioli](https://github.com/fraioli) + [#5840](https://github.com/realm/SwiftLint/issues/5840) + ## 0.57.0: Squeaky Clean Cycle #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift index d3554619eb..fa8999122d 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/FileNameRule.swift @@ -35,7 +35,9 @@ struct FileNameRule: OptInRule, SourceKitFreeRule { } // Process nested type separator - let allDeclaredTypeNames = TypeNameCollectingVisitor(viewMode: .sourceAccurate) + let allDeclaredTypeNames = TypeNameCollectingVisitor( + requireFullyQualifiedNames: configuration.requireFullyQualifiedNames + ) .walk(tree: file.syntaxTree, handler: \.names) .map { $0.replacingOccurrences(of: ".", with: configuration.nestedTypeSeparator) @@ -56,33 +58,96 @@ struct FileNameRule: OptInRule, SourceKitFreeRule { } private class TypeNameCollectingVisitor: SyntaxVisitor { + /// All of a visited node's ancestor type names if that node is nested, starting with the furthest + /// ancestor and ending with the direct parent + private var ancestorNames = Stack() + + /// All of the type names found in the file private(set) var names: Set = [] - override func visitPost(_ node: ClassDeclSyntax) { - names.insert(node.name.text) + /// If true, nested types are only allowed in the file name when used by their fully-qualified name + /// (e.g. `My.Nested.Type` and not just `Type`) + private let requireFullyQualifiedNames: Bool + + init(requireFullyQualifiedNames: Bool) { + self.requireFullyQualifiedNames = requireFullyQualifiedNames + super.init(viewMode: .sourceAccurate) + } + + /// Calls `visit(name:)` using the name of the provided node + private func visit(node: some NamedDeclSyntax) -> SyntaxVisitorContinueKind { + visit(name: node.name.trimmedDescription) + } + + /// Visits a node with the provided name, storing that name as an ancestor type name to prepend to + /// any children to form their fully-qualified names + private func visit(name: String) -> SyntaxVisitorContinueKind { + let fullyQualifiedName = (ancestorNames + [name]).joined(separator: ".") + names.insert(fullyQualifiedName) + + // If the options don't require only fully-qualified names, then we will allow this node's + // name to be used by itself + if !requireFullyQualifiedNames { + names.insert(name) + } + + ancestorNames.push(name) + return .visitChildren + } + + override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { + visit(node: node) + } + + override func visitPost(_: ClassDeclSyntax) { + ancestorNames.pop() + } + + override func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind { + visit(node: node) + } + + override func visitPost(_: ActorDeclSyntax) { + ancestorNames.pop() + } + + override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { + visit(node: node) + } + + override func visitPost(_: StructDeclSyntax) { + ancestorNames.pop() + } + + override func visit(_ node: TypeAliasDeclSyntax) -> SyntaxVisitorContinueKind { + visit(node: node) + } + + override func visitPost(_: TypeAliasDeclSyntax) { + ancestorNames.pop() } - override func visitPost(_ node: ActorDeclSyntax) { - names.insert(node.name.text) + override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { + visit(node: node) } - override func visitPost(_ node: StructDeclSyntax) { - names.insert(node.name.text) + override func visitPost(_: EnumDeclSyntax) { + ancestorNames.pop() } - override func visitPost(_ node: TypeAliasDeclSyntax) { - names.insert(node.name.text) + override func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { + visit(node: node) } - override func visitPost(_ node: EnumDeclSyntax) { - names.insert(node.name.text) + override func visitPost(_: ProtocolDeclSyntax) { + ancestorNames.pop() } - override func visitPost(_ node: ProtocolDeclSyntax) { - names.insert(node.name.text) + override func visit(_ node: ExtensionDeclSyntax) -> SyntaxVisitorContinueKind { + visit(name: node.extendedType.trimmedDescription) } - override func visitPost(_ node: ExtensionDeclSyntax) { - names.insert(node.extendedType.trimmedDescription) + override func visitPost(_: ExtensionDeclSyntax) { + ancestorNames.pop() } } diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift index 08d414eacd..7aa8be61b5 100644 --- a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/FileNameConfiguration.swift @@ -14,4 +14,6 @@ struct FileNameConfiguration: SeverityBasedRuleConfiguration { private(set) var suffixPattern = "\\+.*" @ConfigurationElement(key: "nested_type_separator") private(set) var nestedTypeSeparator = "." + @ConfigurationElement(key: "require_fully_qualified_names") + private(set) var requireFullyQualifiedNames = false } diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index bbb19d493b..772b29252c 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -177,6 +177,7 @@ file_name: prefix_pattern: "" suffix_pattern: "\+.*" nested_type_separator: "." + require_fully_qualified_names: false file_name_no_space: severity: warning excluded: [] diff --git a/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift b/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift index 30f3167966..4e3a2923fa 100644 --- a/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/FileNameRuleTests.swift @@ -5,26 +5,33 @@ private let fixturesDirectory = "\(TestResources.path)/FileNameRuleFixtures" final class FileNameRuleTests: SwiftLintTestCase { private func validate(fileName: String, - excludedOverride: [String]? = nil, + excluded: [String]? = nil, prefixPattern: String? = nil, suffixPattern: String? = nil, - nestedTypeSeparator: String? = nil) throws -> [StyleViolation] { + nestedTypeSeparator: String? = nil, + requireFullyQualifiedNames: Bool = false) throws -> [StyleViolation] { let file = SwiftLintFile(path: fixturesDirectory.stringByAppendingPathComponent(fileName))! - let rule: FileNameRule - if let excluded = excludedOverride { - rule = try FileNameRule(configuration: ["excluded": excluded]) - } else if let prefixPattern, let suffixPattern { - rule = try FileNameRule(configuration: ["prefix_pattern": prefixPattern, "suffix_pattern": suffixPattern]) - } else if let prefixPattern { - rule = try FileNameRule(configuration: ["prefix_pattern": prefixPattern]) - } else if let suffixPattern { - rule = try FileNameRule(configuration: ["suffix_pattern": suffixPattern]) - } else if let nestedTypeSeparator { - rule = try FileNameRule(configuration: ["nested_type_separator": nestedTypeSeparator]) - } else { - rule = FileNameRule() + + var configuration = [String: Any]() + + if let excluded { + configuration["excluded"] = excluded + } + if let prefixPattern { + configuration["prefix_pattern"] = prefixPattern + } + if let suffixPattern { + configuration["suffix_pattern"] = suffixPattern + } + if let nestedTypeSeparator { + configuration["nested_type_separator"] = nestedTypeSeparator + } + if requireFullyQualifiedNames { + configuration["require_fully_qualified_names"] = requireFullyQualifiedNames } + let rule = try FileNameRule(configuration: configuration) + return rule.validate(file: file) } @@ -52,14 +59,30 @@ final class FileNameRuleTests: SwiftLintTestCase { XCTAssert(try validate(fileName: "Notification.Name+Extension.swift").isEmpty) } + func testNestedTypeDoesntTrigger() { + XCTAssert(try validate(fileName: "Nested.MyType.swift").isEmpty) + } + + func testMultipleLevelsDeeplyNestedTypeDoesntTrigger() { + XCTAssert(try validate(fileName: "Multiple.Levels.Deeply.Nested.MyType.swift").isEmpty) + } + + func testNestedTypeNotFullyQualifiedDoesntTrigger() { + XCTAssert(try validate(fileName: "MyType.swift").isEmpty) + } + + func testNestedTypeNotFullyQualifiedDoesTriggerWithOverride() { + XCTAssert(try validate(fileName: "MyType.swift", requireFullyQualifiedNames: true).isNotEmpty) + } + func testNestedTypeSeparatorDoesntTrigger() { XCTAssert(try validate(fileName: "NotificationName+Extension.swift", nestedTypeSeparator: "").isEmpty) XCTAssert(try validate(fileName: "Notification__Name+Extension.swift", nestedTypeSeparator: "__").isEmpty) } func testWrongNestedTypeSeparatorDoesTrigger() { - XCTAssert(try !validate(fileName: "Notification__Name+Extension.swift", nestedTypeSeparator: ".").isEmpty) - XCTAssert(try !validate(fileName: "NotificationName+Extension.swift", nestedTypeSeparator: "__").isEmpty) + XCTAssert(try validate(fileName: "Notification__Name+Extension.swift", nestedTypeSeparator: ".").isNotEmpty) + XCTAssert(try validate(fileName: "NotificationName+Extension.swift", nestedTypeSeparator: "__").isNotEmpty) } func testMisspelledNameDoesTrigger() { @@ -67,11 +90,11 @@ final class FileNameRuleTests: SwiftLintTestCase { } func testMisspelledNameDoesntTriggerWithOverride() { - XCTAssert(try validate(fileName: "MyStructf.swift", excludedOverride: ["MyStructf.swift"]).isEmpty) + XCTAssert(try validate(fileName: "MyStructf.swift", excluded: ["MyStructf.swift"]).isEmpty) } func testMainDoesTriggerWithoutOverride() { - XCTAssertEqual(try validate(fileName: "main.swift", excludedOverride: []).count, 1) + XCTAssertEqual(try validate(fileName: "main.swift", excluded: []).count, 1) } func testCustomSuffixPattern() { diff --git a/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Multiple.Levels.Deeply.Nested.MyType.swift b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Multiple.Levels.Deeply.Nested.MyType.swift new file mode 100644 index 0000000000..46bb755a47 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Multiple.Levels.Deeply.Nested.MyType.swift @@ -0,0 +1,9 @@ +extension Multiple { + enum Levels { + class Deeply { + struct Nested { + actor MyType {} + } + } + } +} diff --git a/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/MyType.swift b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/MyType.swift new file mode 100644 index 0000000000..7c72b6af9d --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/MyType.swift @@ -0,0 +1,3 @@ +enum Nested { + struct MyType {} +} diff --git a/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Nested.MyType.swift b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Nested.MyType.swift new file mode 100644 index 0000000000..a57866f72a --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/Resources/FileNameRuleFixtures/Nested.MyType.swift @@ -0,0 +1,4 @@ +enum Nested { + struct MyType { + } +} From 0ce122e716d0042e51ed8609028e3bef19a7cfcc Mon Sep 17 00:00:00 2001 From: jkolarik-paylocity <138468976+jkolarik-paylocity@users.noreply.github.com> Date: Wed, 27 Nov 2024 22:15:25 +0100 Subject: [PATCH 259/265] Add new `async_without_await` rule (#5869) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Danny Mösch --- .swiftlint.yml | 1 + CHANGELOG.md | 4 + .../Models/BuiltInRules.swift | 1 + .../Rules/Lint/AsyncWithoutAwaitRule.swift | 156 ++++++++ .../Lint/AsyncWithoutAwaitRuleExamples.swift | 338 ++++++++++++++++++ Tests/GeneratedTests/GeneratedTests.swift | 6 + .../default_rule_configurations.yml | 2 + 7 files changed, 508 insertions(+) create mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRule.swift create mode 100644 Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRuleExamples.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 8dc4c564ed..59dcb36fcc 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -15,6 +15,7 @@ opt_in_rules: - all disabled_rules: - anonymous_argument_in_multiline_closure + - async_without_await - conditional_returns_on_newline - contrasted_opening_brace - convenience_type diff --git a/CHANGELOG.md b/CHANGELOG.md index d109fa83bb..10aa857e7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ * Add Xcode command plugin allowing to run SwiftLint from within Xcode. [SimplyDanny](https://github.com/SimplyDanny) + +* Add new `async_without_await` opt-in rule that checks if an `async` declaration contains at least one `await`. + [Jan Kolarik](https://github.com/jkolarik-paylocity) + [#5082](https://github.com/realm/SwiftLint/issues/5082) #### Bug Fixes diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index eeb3abce7c..075d9b8fd2 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -7,6 +7,7 @@ public let builtInRules: [any Rule.Type] = [ AccessibilityTraitForButtonRule.self, AnonymousArgumentInMultilineClosureRule.self, ArrayInitRule.self, + AsyncWithoutAwaitRule.self, AttributeNameSpacingRule.self, AttributesRule.self, BalancedXCTestLifecycleRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRule.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRule.swift new file mode 100644 index 0000000000..0604a9fc60 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRule.swift @@ -0,0 +1,156 @@ +import SwiftLintCore +import SwiftSyntax + +@SwiftSyntaxRule +struct AsyncWithoutAwaitRule: SwiftSyntaxCorrectableRule, OptInRule { + var configuration = SeverityConfiguration(.warning) + + static let description = RuleDescription( + identifier: "async_without_await", + name: "Async Without Await", + description: "Declaration should not be async if it doesn't use await", + kind: .lint, + nonTriggeringExamples: AsyncWithoutAwaitRuleExamples.nonTriggeringExamples, + triggeringExamples: AsyncWithoutAwaitRuleExamples.triggeringExamples, + corrections: AsyncWithoutAwaitRuleExamples.corrections + ) +} +private extension AsyncWithoutAwaitRule { + private struct FuncInfo { + var containsAwait = false + let asyncToken: TokenSyntax? + + init(asyncToken: TokenSyntax?) { + self.asyncToken = asyncToken + } + } + + final class Visitor: ViolationsSyntaxVisitor { + private var functionScopes = Stack() + private var pendingAsync: TokenSyntax? + + override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { + guard node.body != nil else { + return .visitChildren + } + + let asyncToken = node.signature.effectSpecifiers?.asyncSpecifier + functionScopes.push(.init(asyncToken: asyncToken)) + + return .visitChildren + } + + override func visitPost(_ node: FunctionDeclSyntax) { + if node.body != nil { + checkViolation() + } + } + + override func visit(_: ClosureExprSyntax) -> SyntaxVisitorContinueKind { + functionScopes.push(.init(asyncToken: pendingAsync)) + pendingAsync = nil + + return .visitChildren + } + + override func visitPost(_: ClosureExprSyntax) { + checkViolation() + } + + override func visitPost(_: AwaitExprSyntax) { + functionScopes.modifyLast { + $0.containsAwait = true + } + } + + override func visitPost(_ node: FunctionTypeSyntax) { + if let asyncNode = node.effectSpecifiers?.asyncSpecifier { + pendingAsync = asyncNode + } + } + + override func visit(_ node: AccessorDeclSyntax) -> SyntaxVisitorContinueKind { + guard node.body != nil else { + return .visitChildren + } + + let asyncToken = node.effectSpecifiers?.asyncSpecifier + functionScopes.push(.init(asyncToken: asyncToken)) + + return .visitChildren + } + + override func visitPost(_ node: AccessorDeclSyntax) { + if node.body != nil { + checkViolation() + } + } + + override func visitPost(_: PatternBindingSyntax) { + pendingAsync = nil + } + + override func visit(_ node: InitializerDeclSyntax) -> SyntaxVisitorContinueKind { + guard node.body != nil else { + return .visitChildren + } + + let asyncToken = node.signature.effectSpecifiers?.asyncSpecifier + functionScopes.push(.init(asyncToken: asyncToken)) + + return .visitChildren + } + + override func visitPost(_ node: InitializerDeclSyntax) { + if node.body != nil { + checkViolation() + } + } + + override func visitPost(_: TypeAliasDeclSyntax) { + pendingAsync = nil + } + + override func visitPost(_ node: ForStmtSyntax) { + if node.awaitKeyword != nil { + functionScopes.modifyLast { + $0.containsAwait = true + } + } + } + + override func visitPost(_ node: VariableDeclSyntax) { + if node.bindingSpecifier.tokenKind == .keyword(.let), + node.modifiers.contains(keyword: .async) { + functionScopes.modifyLast { + $0.containsAwait = true + } + } + } + + override func visit(_: FunctionParameterSyntax) -> SyntaxVisitorContinueKind { + .skipChildren + } + + override func visitPost(_: ReturnClauseSyntax) { + pendingAsync = nil + } + + private func checkViolation() { + guard let info = functionScopes.pop(), + let asyncToken = info.asyncToken, + !info.containsAwait else { + return + } + + violations.append( + at: asyncToken.positionAfterSkippingLeadingTrivia, + correction: .init( + start: asyncToken.positionAfterSkippingLeadingTrivia, + end: asyncToken.endPosition, + replacement: "" + ) + ) + } + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRuleExamples.swift new file mode 100644 index 0000000000..205dcae8fc --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Lint/AsyncWithoutAwaitRuleExamples.swift @@ -0,0 +1,338 @@ +internal struct AsyncWithoutAwaitRuleExamples { + static let nonTriggeringExamples = [ + Example(""" + func test() { + func test() async { + await test() + } + }, + """), + Example(""" + func test() { + func test() async { + await test().value + } + }, + """), + Example(""" + func test() async { + await scheduler.task { foo { bar() } } + } + """), + Example(""" + func test() async { + perform(await try foo().value) + } + """), + Example(""" + func test() async { + perform(try await foo()) + } + """), + Example(""" + func test() async { + await perform() + func baz() { + qux() + } + } + """), + Example(""" + let x: () async -> Void = { + await test() + } + """), + Example(""" + let x: () async -> Void = { + await { await test() }() + } + """), + Example(""" + func test() async { + await foo() + } + let x = { bar() } + """), + Example(""" + let x: (() async -> Void)? = { + await { await test() }() + } + """), + Example(""" + let x: (() async -> Void)? = nil + let x: () -> Void = { test() } + """), + Example(""" + var test: Int { + get async throws { + try await foo() + } + } + var foo: Int { + get throws { + try bar() + } + } + """), + Example(""" + init() async { + await foo() + } + """), + Example(""" + init() async { + func test() async { + await foo() + } + await { await foo() }() + } + """), + Example(""" + subscript(row: Int) -> Double { + get async { + await foo() + } + } + """), + Example(""" + func foo() async -> Int + func bar() async -> Int + """), + Example(""" + var foo: Int { get async } + var bar: Int { get async } + """), + Example(""" + init(foo: bar) async + init(baz: qux) async + let baz = { qux() } + """), + Example(""" + typealias Foo = () async -> Void + typealias Bar = () async -> Void + let baz = { qux() } + """), + Example(""" + func test() async { + for await foo in bar {} + } + """), + Example(""" + func test() async { + while let foo = await bar() {} + } + """), + Example(""" + func test() async { + async let foo = bar() + let baz = await foo + } + """), + Example(""" + func test() async { + async let foo = bar() + await foo + } + """), + Example(""" + func test() async { + async let foo = bar() + } + """), + Example("func foo(bar: () async -> Void) { { } }"), + Example("func foo(bar: () async -> Void = { await baz() }) { {} }"), + Example("func foo() -> (() async -> Void)? { {} }"), + Example(""" + func foo( + bar: () async -> Void, + baz: () -> Void = {} + ) { { } } + """), + Example("func foo(bar: () async -> Void = {}) { }"), + ] + + static let triggeringExamples = [ + Example(""" + func test() ↓async { + perform() + } + """), + Example(""" + func test() { + func baz() ↓async { + qux() + } + perform() + func baz() { + qux() + } + } + """), + Example(""" + func test() ↓async { + func baz() async { + await qux() + } + } + """), + Example(""" + func test() ↓async { + func foo() ↓async {} + let bar = { await foo() } + } + """), + Example(""" + func test() ↓async { + let bar = { + func foo() ↓async {} + } + } + """), + Example("let x: (() ↓async -> Void)? = { test() }"), + Example(""" + var test: Int { + get ↓async throws { + foo() + } + } + """), + Example(""" + var test: Int { + get ↓async throws { + func foo() ↓async {} + let bar = { await foo() } + } + } + """), + Example(""" + var test: Int { + get throws { + func foo() {} + let bar: () ↓async -> Void = { foo() } + } + } + """), + Example("init() ↓async {}"), + Example(""" + init() ↓async { + func foo() ↓async {} + let bar: () ↓async -> Void = { foo() } + } + """), + Example(""" + subscript(row: Int) -> Double { + get ↓async { + 1.0 + } + } + """), + Example(""" + func test() ↓async { + for foo in bar {} + } + """), + Example(""" + func test() ↓async { + while let foo = bar() {} + } + """), + ] + + static let corrections = [ + Example("func test() ↓async {}"): Example("func test() {}"), + Example("func test() ↓async throws {}"): Example("func test() throws {}"), + Example(""" + func test() { + func baz() ↓async { + qux() + } + perform() + func baz() { + qux() + } + } + """): + Example(""" + func test() { + func baz() { + qux() + } + perform() + func baz() { + qux() + } + } + """), + Example(""" + func test() ↓async{ + func baz() async { + await qux() + } + } + """): + Example(""" + func test() { + func baz() async { + await qux() + } + } + """), + Example(""" + func test() ↓async { + func foo() ↓async {} + let bar = { await foo() } + } + """): + Example(""" + func test() { + func foo() {} + let bar = { await foo() } + } + """), + Example("let x: () ↓async -> Void = { test() }"): + Example("let x: () -> Void = { test() }"), + Example(""" + var test: Int { + get ↓async throws { + func foo() ↓async {} + let bar = { await foo() } + } + } + """): + Example(""" + var test: Int { + get throws { + func foo() {} + let bar = { await foo() } + } + } + """), + Example("init() ↓async {}"): Example("init() {}"), + Example(""" + init() ↓async { + func foo() ↓async {} + let bar: () ↓async -> Void = { foo() } + } + """): + Example(""" + init() { + func foo() {} + let bar: () -> Void = { foo() } + } + """), + Example(""" + subscript(row: Int) -> Double { + get ↓async { + foo() + } + } + """): + Example(""" + subscript(row: Int) -> Double { + get { + foo() + } + } + """), + ] +} diff --git a/Tests/GeneratedTests/GeneratedTests.swift b/Tests/GeneratedTests/GeneratedTests.swift index d00101a90b..202bd725f9 100644 --- a/Tests/GeneratedTests/GeneratedTests.swift +++ b/Tests/GeneratedTests/GeneratedTests.swift @@ -31,6 +31,12 @@ final class ArrayInitRuleGeneratedTests: SwiftLintTestCase { } } +final class AsyncWithoutAwaitRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(AsyncWithoutAwaitRule.description) + } +} + final class AttributeNameSpacingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(AttributeNameSpacingRule.description) diff --git a/Tests/IntegrationTests/default_rule_configurations.yml b/Tests/IntegrationTests/default_rule_configurations.yml index 772b29252c..7ec4ddeae4 100644 --- a/Tests/IntegrationTests/default_rule_configurations.yml +++ b/Tests/IntegrationTests/default_rule_configurations.yml @@ -6,6 +6,8 @@ anonymous_argument_in_multiline_closure: severity: warning array_init: severity: warning +async_without_await: + severity: warning attribute_name_spacing: severity: error attributes: From daebaa31152e3f1c48785996e35cbe972832a601 Mon Sep 17 00:00:00 2001 From: Bradley Mackey Date: Wed, 27 Nov 2024 21:30:22 +0000 Subject: [PATCH 260/265] Include AMD64 Linux binary in `artifactbundle` (#5866) --- CHANGELOG.md | 5 +++ Dockerfile | 1 + Makefile | 35 ++++++++++++------- Package.swift | 1 + tools/create-github-release.sh | 2 +- ...macos.json.template => info.json.template} | 4 +++ tools/update-artifact-bundle.sh | 4 +-- 7 files changed, 37 insertions(+), 15 deletions(-) rename tools/{info-macos.json.template => info.json.template} (68%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10aa857e7d..9aa9ed4c54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ * The command plugin now requires write permissions so that it works with the `--fix` option without an error. [SimplyDanny](https://github.com/SimplyDanny) +* The artifact bundle name has changed. `SwiftLintBinary-macos.artifactbundle.zip` is now called + `SwiftLintBinary.artifactbundle.zip`. It now includes an AMD64 Linux binary. + [Bradley Mackey](https://github.com/bradleymackey) + [#5514](https://github.com/realm/SwiftLint/issues/5514) + #### Experimental * None. diff --git a/Dockerfile b/Dockerfile index 146675d8e6..d4b0c2f92e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,7 @@ RUN swift package update ARG SWIFT_FLAGS="-c release -Xswiftc -static-stdlib -Xlinker -l_CFURLSessionInterface -Xlinker -l_CFXMLInterface -Xlinker -lcurl -Xlinker -lxml2 -Xswiftc -I. -Xlinker -fuse-ld=lld -Xlinker -L/usr/lib/swift/linux" RUN swift build $SWIFT_FLAGS --product swiftlint RUN mv `swift build $SWIFT_FLAGS --show-bin-path`/swiftlint /usr/bin +RUN strip /usr/bin/swiftlint # Runtime image FROM ${RUNTIME_IMAGE} diff --git a/Makefile b/Makefile index b20fa4e15c..b624d78cac 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,8 @@ SWIFT_BUILD_FLAGS=--configuration release -Xlinker -dead_strip SWIFTLINT_EXECUTABLE_PARENT=.build/universal SWIFTLINT_EXECUTABLE=$(SWIFTLINT_EXECUTABLE_PARENT)/swiftlint +SWIFTLINT_EXECUTABLE_LINUX_PARENT=.build/linux +SWIFTLINT_EXECUTABLE_LINUX_AMD64=$(SWIFTLINT_EXECUTABLE_LINUX_PARENT)/swiftlint_linux_amd64 ARTIFACT_BUNDLE_PATH=$(TEMPORARY_FOLDER)/SwiftLintBinary.artifactbundle @@ -26,7 +28,7 @@ OUTPUT_PACKAGE=SwiftLint.pkg VERSION_STRING=$(shell ./tools/get-version) -.PHONY: all clean build install package test uninstall docs +.PHONY: all clean build build_linux install package test uninstall docs all: build @@ -78,6 +80,11 @@ build: chmod +w "$(SWIFTLINT_EXECUTABLE)" strip -rSTX "$(SWIFTLINT_EXECUTABLE)" +build_linux: + mkdir -p "$(SWIFTLINT_EXECUTABLE_LINUX_PARENT)" + docker run --platform linux/amd64 "ghcr.io/realm/swiftlint:$(VERSION_STRING)" cat /usr/bin/swiftlint > "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" + chmod +x "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" + build_with_disable_sandbox: swift build --disable-sandbox $(SWIFT_BUILD_FLAGS) @@ -93,6 +100,10 @@ installables: build install -d "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" install "$(SWIFTLINT_EXECUTABLE)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" +installables_linux: build_linux + install -d "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" + install "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(TEMPORARY_FOLDER)$(BINARIES_FOLDER)" + prefix_install: build_with_disable_sandbox install -d "$(PREFIX)/bin/" install "$(SWIFTLINT_EXECUTABLE)" "$(PREFIX)/bin/" @@ -102,24 +113,24 @@ portable_zip: installables cp -f "$(LICENSE_PATH)" "$(TEMPORARY_FOLDER)" (cd "$(TEMPORARY_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./portable_swiftlint.zip" -spm_artifactbundle_macos: installables +spm_artifactbundle: installables installables_linux mkdir -p "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-macos/bin" - sed 's/__VERSION__/$(VERSION_STRING)/g' tools/info-macos.json.template > "$(ARTIFACT_BUNDLE_PATH)/info.json" - cp -f "$(SWIFTLINT_EXECUTABLE)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-macos/bin" + mkdir -p "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-linux-gnu/bin" + sed 's/__VERSION__/$(VERSION_STRING)/g' tools/info.json.template > "$(ARTIFACT_BUNDLE_PATH)/info.json" + cp -f "$(SWIFTLINT_EXECUTABLE)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-macos/bin/swiftlint" + cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-linux-gnu/bin/swiftlint" cp -f "$(LICENSE_PATH)" "$(ARTIFACT_BUNDLE_PATH)" - (cd "$(TEMPORARY_FOLDER)"; zip -yr - "SwiftLintBinary.artifactbundle") > "./SwiftLintBinary-macos.artifactbundle.zip" + (cd "$(TEMPORARY_FOLDER)"; zip -yr - "SwiftLintBinary.artifactbundle") > "./SwiftLintBinary.artifactbundle.zip" -zip_linux: docker_image +zip_linux: docker_image build_linux $(eval TMP_FOLDER := $(shell mktemp -d)) - docker run swiftlint cat /usr/bin/swiftlint > "$(TMP_FOLDER)/swiftlint" - chmod +x "$(TMP_FOLDER)/swiftlint" + cp -f $(SWIFTLINT_EXECUTABLE_LINUX_AMD64) "$(TMP_FOLDER)/swiftlint" cp -f "$(LICENSE_PATH)" "$(TMP_FOLDER)" (cd "$(TMP_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./swiftlint_linux.zip" -zip_linux_release: +zip_linux_release: build_linux $(eval TMP_FOLDER := $(shell mktemp -d)) - docker run --platform linux/amd64 "ghcr.io/realm/swiftlint:$(VERSION_STRING)" cat /usr/bin/swiftlint > "$(TMP_FOLDER)/swiftlint" - chmod +x "$(TMP_FOLDER)/swiftlint" + cp -f "$(SWIFTLINT_EXECUTABLE_LINUX_AMD64)" "$(TMP_FOLDER)/swiftlint" cp -f "$(LICENSE_PATH)" "$(TMP_FOLDER)" (cd "$(TMP_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./swiftlint_linux.zip" gh release upload "$(VERSION_STRING)" swiftlint_linux.zip @@ -182,7 +193,7 @@ endif make package make bazel_release make portable_zip - make spm_artifactbundle_macos + make spm_artifactbundle ./tools/update-artifact-bundle.sh "$(NEW_VERSION)" git commit -a -m "Release $(NEW_VERSION)" git tag -a $(NEW_VERSION) -m "$(NEW_VERSION_AND_NAME)" diff --git a/Package.swift b/Package.swift index 04539c6de3..85cdce9d31 100644 --- a/Package.swift +++ b/Package.swift @@ -178,6 +178,7 @@ let package = Package( ) #if os(macOS) +// TODO: in the next release the artifactbundle is not suffixed with "-macos" package.targets.append( .binaryTarget( name: "SwiftLintBinary", diff --git a/tools/create-github-release.sh b/tools/create-github-release.sh index 7a671b9d20..8256ac5a6c 100755 --- a/tools/create-github-release.sh +++ b/tools/create-github-release.sh @@ -17,6 +17,6 @@ gh release create "$version" --title "$release_title" -F "$release_notes" --draf "bazel.tar.gz.sha256" \ "portable_swiftlint.zip" \ "SwiftLint.pkg" \ - "SwiftLintBinary-macos.artifactbundle.zip" + "SwiftLintBinary.artifactbundle.zip" rm "$release_notes" diff --git a/tools/info-macos.json.template b/tools/info.json.template similarity index 68% rename from tools/info-macos.json.template rename to tools/info.json.template index ef75578a64..0829f935da 100644 --- a/tools/info-macos.json.template +++ b/tools/info.json.template @@ -8,6 +8,10 @@ { "path": "swiftlint-__VERSION__-macos/bin/swiftlint", "supportedTriples": ["x86_64-apple-macosx", "arm64-apple-macosx"] + }, + { + "path": "swiftlint-__VERSION__-linux-gnu/bin/swiftlint", + "supportedTriples": ["x86_64-unknown-linux-gnu"] } ] } diff --git a/tools/update-artifact-bundle.sh b/tools/update-artifact-bundle.sh index c98ef2b4e2..032a423757 100755 --- a/tools/update-artifact-bundle.sh +++ b/tools/update-artifact-bundle.sh @@ -3,11 +3,11 @@ set -euo pipefail readonly version="$1" -readonly artifactbundle="SwiftLintBinary-macos.artifactbundle.zip" +readonly artifactbundle="SwiftLintBinary.artifactbundle.zip" readonly checksum="$(shasum -a 256 "$artifactbundle" | cut -d " " -f1 | xargs)" sed -i '' \ - "s/.*\/releases\/download\/.*/ url: \"https:\/\/github.com\/realm\/SwiftLint\/releases\/download\/$version\/SwiftLintBinary-macos\.artifactbundle\.zip\",/g" \ + "s/.*\/releases\/download\/.*/ url: \"https:\/\/github.com\/realm\/SwiftLint\/releases\/download\/$version\/SwiftLintBinary\.artifactbundle\.zip\",/g" \ Package.swift sed -i '' \ From 172d85ab7a17b25b1e74f9ff01541dc10010a73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 29 Nov 2024 00:00:44 +0100 Subject: [PATCH 261/265] Add pre-defined internal Swift 6 version (#5872) --- .../SwiftLintCore/Models/SwiftVersion.swift | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/Source/SwiftLintCore/Models/SwiftVersion.swift b/Source/SwiftLintCore/Models/SwiftVersion.swift index 27bc80c658..4918793ed1 100644 --- a/Source/SwiftLintCore/Models/SwiftVersion.swift +++ b/Source/SwiftLintCore/Models/SwiftVersion.swift @@ -45,41 +45,37 @@ extension VersionComparable { } public extension SwiftVersion { - /// Swift 5.0.x - https://swift.org/download/#swift-50 + /// Swift 5 static let five = SwiftVersion(rawValue: "5.0.0") - /// Swift 5.1.x - https://swift.org/download/#swift-51 + /// Swift 5.1 static let fiveDotOne = SwiftVersion(rawValue: "5.1.0") - /// Swift 5.2.x - https://swift.org/download/#swift-52 + /// Swift 5.2 static let fiveDotTwo = SwiftVersion(rawValue: "5.2.0") - /// Swift 5.3.x - https://swift.org/download/#swift-53 + /// Swift 5.3 static let fiveDotThree = SwiftVersion(rawValue: "5.3.0") - /// Swift 5.4.x - https://swift.org/download/#swift-54 + /// Swift 5.4 static let fiveDotFour = SwiftVersion(rawValue: "5.4.0") - /// Swift 5.5.x - https://swift.org/download/#swift-55 + /// Swift 5.5 static let fiveDotFive = SwiftVersion(rawValue: "5.5.0") - /// Swift 5.6.x - https://swift.org/download/#swift-56 + /// Swift 5.6 static let fiveDotSix = SwiftVersion(rawValue: "5.6.0") - /// Swift 5.7.x - https://swift.org/download/#swift-57 + /// Swift 5.7 static let fiveDotSeven = SwiftVersion(rawValue: "5.7.0") - /// Swift 5.8.x - https://swift.org/download/#swift-58 + /// Swift 5.8 static let fiveDotEight = SwiftVersion(rawValue: "5.8.0") - /// Swift 5.9.x - https://swift.org/download/#swift-59 + /// Swift 5.9 static let fiveDotNine = SwiftVersion(rawValue: "5.9.0") + /// Swift 6 + static let six = SwiftVersion(rawValue: "6.0.0") /// The current detected Swift compiler version, based on the currently accessible SourceKit version. /// /// - note: Override by setting the `SWIFTLINT_SWIFT_VERSION` environment variable. static let current: SwiftVersion = { - // Allow forcing the Swift version, useful in cases where SourceKit isn't available + // Allow forcing the Swift version, useful in cases where SourceKit isn't available. if let envVersion = ProcessInfo.processInfo.environment["SWIFTLINT_SWIFT_VERSION"] { - switch envVersion { - case "5": - return .five - default: - return .five - } + return SwiftVersion(rawValue: envVersion) } - if !Request.disableSourceKit { // This request was added in Swift 5.1 let params: SourceKitObject = ["key.request": UID("source.request.compiler_version")] @@ -88,7 +84,6 @@ public extension SwiftVersion { return SwiftVersion(rawValue: "\(major).\(minor).\(patch)") } } - return .five }() } From 341a5a16d2ae04a14956a37df0356315457434c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 29 Nov 2024 23:22:51 +0100 Subject: [PATCH 262/265] Disable `prefer_key_path` temporarily (#5877) Re-enable once we require Swift 6. --- .swiftlint.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 59dcb36fcc..2529e986ae 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -38,6 +38,7 @@ disabled_rules: - no_grouping_extension - no_magic_numbers - one_declaration_per_file + - prefer_key_path # Re-enable once we are on Swift 6. - prefer_nimble - prefixed_toplevel_constant - required_deinit @@ -79,8 +80,6 @@ identifier_name: large_tuple: 3 number_separator: minimum_length: 5 -prefer_key_path: - restrict_to_standard_functions: false redundant_type_annotation: consider_default_literal_types_redundant: true single_test_class: *unit_test_configuration From b22c2b5c4c53401115a4a0353e9b82682fe2fd5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Fri, 29 Nov 2024 23:52:37 +0100 Subject: [PATCH 263/265] Treat `compactMap` as standard function (#5876) --- .../Rules/Idiomatic/PreferKeyPathRule.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift index 127564620d..1427a250c3 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift @@ -44,6 +44,7 @@ struct PreferKeyPathRule: OptInRule { Example("f.allSatisfy ↓{ (a: A) in a.b }"), Example("f.first ↓{ (a b: A) in b.c }"), Example("f.contains ↓{ $0.0.a }"), + Example("f.compactMap ↓{ $0.a.b.c.d }"), Example("f.flatMap ↓{ $0.a.b }"), Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: extendedMode), ], @@ -78,6 +79,8 @@ struct PreferKeyPathRule: OptInRule { Example("f.first(where: \\.a)"), Example("f.drop ↓{ element in element.a }"): Example("f.drop(while: \\.a)"), + Example("f.compactMap ↓{ $0.a.b.c.d }"): + Example("f.compactMap(\\.a.b.c.d)"), ] ) } @@ -191,6 +194,7 @@ private extension ClosureExprSyntax { private let argumentLabelByStandardFunction: [String: String?] = [ "allSatisfy": nil, "contains": "where", + "compactMap": nil, "drop": "while", "filter": nil, "first": "where", From c45427e08b9aa7c5d1bacba3fe0562d6df8e44db Mon Sep 17 00:00:00 2001 From: Jared Grubb <1256381+jaredgrubb@users.noreply.github.com> Date: Sat, 30 Nov 2024 17:17:08 -0800 Subject: [PATCH 264/265] Handle `@unknown default` in `vertical_whitespace_between_cases` rule (#5843) --- CHANGELOG.md | 5 +++++ .../Style/VerticalWhitespaceBetweenCasesRule.swift | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aa9ed4c54..13f85c7dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,6 +145,11 @@ [fraioli](https://github.com/fraioli) [#5840](https://github.com/realm/SwiftLint/issues/5840) +* Fixes an issue where the `vertical_whitespace_between_cases` rule does not + recognize `@unknown default`. + [Jared Grubb](https://github.com/jaredtrubb) + [#5788](https://github.com/realm/SwiftLint/issues/3511) + ## 0.57.0: Squeaky Clean Cycle #### Breaking diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift index c5609af0bf..9b964d2f00 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/VerticalWhitespaceBetweenCasesRule.swift @@ -23,6 +23,8 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { default: print("x is invalid") + @unknown default: + print("x is out of this world") } """), Example(""" @@ -42,6 +44,7 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { case 0..<5: print("x is low") case 5..<10: print("x is high") default: print("x is invalid") + @unknown default: print("x is out of this world") } """), // Testing handling of trailing spaces: do not convert to """ style @@ -63,6 +66,8 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { return "x is valid" ↓default: return "x is invalid" + ↓@unknown default: + print("x is out of this world") } """): Example(""" switch x { @@ -71,6 +76,9 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { default: return "x is invalid" + + @unknown default: + print("x is out of this world") } """), Example(""" @@ -127,7 +135,7 @@ struct VerticalWhitespaceBetweenCasesRule: Rule { """), ] - private let pattern = "([^\\n{][ \\t]*\\n)([ \\t]*(?:case[^\\n]+|default):[ \\t]*\\n)" + private let pattern = "([^\\n{][ \\t]*\\n)([ \\t]*(?:case[^\\n]+|default|@unknown default):[ \\t]*\\n)" private func violationRanges(in file: SwiftLintFile) -> [NSRange] { file.violatingRanges(for: pattern).filter { From f13c54cf88c05b991ee2a928222bb531e660a6ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 1 Dec 2024 19:30:29 +0100 Subject: [PATCH 265/265] Replace identity expressions with `\.self` (#5871) --- CHANGELOG.md | 5 +- .../Rules/Idiomatic/PreferKeyPathRule.swift | 59 +++++++++++-------- .../PreferKeyPathRuleTests.swift | 29 +++++++++ 3 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 Tests/SwiftLintFrameworkTests/PreferKeyPathRuleTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 13f85c7dec..5b716a67cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,11 +18,14 @@ * Add Xcode command plugin allowing to run SwiftLint from within Xcode. [SimplyDanny](https://github.com/SimplyDanny) - + * Add new `async_without_await` opt-in rule that checks if an `async` declaration contains at least one `await`. [Jan Kolarik](https://github.com/jkolarik-paylocity) [#5082](https://github.com/realm/SwiftLint/issues/5082) +* Support replacing identity expressions with `\.self` in `prefer_key_path` rule from Swift 6 on. + [SimplyDanny](https://github.com/SimplyDanny) + #### Bug Fixes * None. diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift index 1427a250c3..6f3c2819f7 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/PreferKeyPathRule.swift @@ -19,10 +19,8 @@ struct PreferKeyPathRule: OptInRule { Example("f { $0.a }"), Example("let f = { $0.a }(b)"), Example("f {}", configuration: extendedMode), - Example("f { $0 }", configuration: extendedMode), Example("f() { g() }", configuration: extendedMode), Example("f { a.b.c }", configuration: extendedMode), - Example("f { a in a }", configuration: extendedMode), Example("f { a, b in a.b }", configuration: extendedMode), Example("f { (a, b) in a.b }", configuration: extendedMode), Example("f { $0.a } g: { $0.b }", configuration: extendedMode), @@ -30,6 +28,7 @@ struct PreferKeyPathRule: OptInRule { Example("f.map(1) { $0.a }"), Example("f.filter({ $0.a }, x)"), Example("#Predicate { $0.a }"), + Example("let transform: (Int) -> Int = nil ?? { $0.a }"), ], triggeringExamples: [ Example("f.map ↓{ $0.a }"), @@ -47,6 +46,7 @@ struct PreferKeyPathRule: OptInRule { Example("f.compactMap ↓{ $0.a.b.c.d }"), Example("f.flatMap ↓{ $0.a.b }"), Example("let f: (Int) -> Int = ↓{ $0.bigEndian }", configuration: extendedMode), + Example("transform = ↓{ $0.a }"), ], corrections: [ Example("f.map { $0.a }"): @@ -91,7 +91,9 @@ private extension PreferKeyPathRule { if node.isInvalid(restrictToStandardFunctions: configuration.restrictToStandardFunctions) { return } - if node.onlyExprStmt?.accesses(identifier: node.onlyParameter) == true { + if let onlyStmt = node.onlyExprStmt, + SwiftVersion.current >= .six || !onlyStmt.is(DeclReferenceExprSyntax.self), + onlyStmt.accesses(identifier: node.onlyParameter) { violations.append(node.positionAfterSkippingLeadingTrivia) } } @@ -104,7 +106,7 @@ private extension PreferKeyPathRule { !closure.isInvalid(restrictToStandardFunctions: configuration.restrictToStandardFunctions), let expr = closure.onlyExprStmt, expr.accesses(identifier: closure.onlyParameter) == true, - let declName = expr.as(MemberAccessExprSyntax.self), + let replacement = expr.asKeyPath, let calleeName = node.calleeName else { return super.visit(node) } @@ -115,7 +117,7 @@ private extension PreferKeyPathRule { } let newArg = LabeledExprSyntax( label: argumentLabelByStandardFunction[calleeName, default: nil], - expression: declName.asKeyPath + expression: replacement ) node = node.with(\.arguments, [newArg] ) @@ -134,9 +136,9 @@ private extension PreferKeyPathRule { } if let expr = node.onlyExprStmt, expr.accesses(identifier: node.onlyParameter) == true, - let declName = expr.as(MemberAccessExprSyntax.self) { + let replacement = expr.asKeyPath { correctionPositions.append(node.positionAfterSkippingLeadingTrivia) - let node = declName.asKeyPath + let node = replacement .with(\.leadingTrivia, node.leadingTrivia) .with(\.trailingTrivia, node.trailingTrivia) return super.visit(node) @@ -149,11 +151,11 @@ private extension PreferKeyPathRule { private extension ExprSyntax { func accesses(identifier: String?) -> Bool { if let base = `as`(MemberAccessExprSyntax.self)?.base { - if let declRef = base.as(DeclReferenceExprSyntax.self) { - return declRef.baseName.text == identifier ?? "$0" - } return base.accesses(identifier: identifier) } + if let declRef = `as`(DeclReferenceExprSyntax.self) { + return declRef.baseName.text == identifier ?? "$0" + } return false } } @@ -179,15 +181,20 @@ private extension ClosureExprSyntax { func isInvalid(restrictToStandardFunctions: Bool) -> Bool { guard keyPathInParent != \FunctionCallExprSyntax.calledExpression, - let parentKind = parent?.kind, - ![.macroExpansionExpr, .multipleTrailingClosureElement].contains(parentKind) else { + let parent, + ![.macroExpansionExpr, .multipleTrailingClosureElement].contains(parent.kind), + previousToken(viewMode: .sourceAccurate)?.text != "??" else { return true } - if let call = parent?.as(LabeledExprSyntax.self)?.parent?.parent?.as(FunctionCallExprSyntax.self) { + if let call = parent.as(LabeledExprSyntax.self)?.parent?.parent?.as(FunctionCallExprSyntax.self) { // Closure is function argument. return restrictToStandardFunctions && !call.isStandardFunction } - return parent?.as(FunctionCallExprSyntax.self)?.isStandardFunction == false + if let call = parent.as(FunctionCallExprSyntax.self) { + // Trailing closure. + return call.additionalTrailingClosures.isNotEmpty || restrictToStandardFunctions && !call.isStandardFunction + } + return false } } @@ -218,16 +225,22 @@ private extension FunctionCallExprSyntax { } } -private extension MemberAccessExprSyntax { - var asKeyPath: ExprSyntax { - var this = base - var elements = [declName] - while this?.is(DeclReferenceExprSyntax.self) != true { - if let memberAccess = this?.as(MemberAccessExprSyntax.self) { - elements.append(memberAccess.declName) - this = memberAccess.base +private extension ExprSyntax { + var asKeyPath: ExprSyntax? { + if let memberAccess = `as`(MemberAccessExprSyntax.self) { + var this = memberAccess.base + var elements = [memberAccess.declName] + while this?.is(DeclReferenceExprSyntax.self) != true { + if let memberAccess = this?.as(MemberAccessExprSyntax.self) { + elements.append(memberAccess.declName) + this = memberAccess.base + } } + return "\\.\(raw: elements.reversed().map(\.baseName.text).joined(separator: "."))" as ExprSyntax + } + if SwiftVersion.current >= .six, `is`(DeclReferenceExprSyntax.self) { + return "\\.self" } - return "\\.\(raw: elements.reversed().map(\.baseName.text).joined(separator: "."))" as ExprSyntax + return nil } } diff --git a/Tests/SwiftLintFrameworkTests/PreferKeyPathRuleTests.swift b/Tests/SwiftLintFrameworkTests/PreferKeyPathRuleTests.swift new file mode 100644 index 0000000000..4b99289fc0 --- /dev/null +++ b/Tests/SwiftLintFrameworkTests/PreferKeyPathRuleTests.swift @@ -0,0 +1,29 @@ +@testable import SwiftLintBuiltInRules +import XCTest + +final class PreferKeyPathRuleTests: SwiftLintTestCase { + private static let extendedMode = ["restrict_to_standard_functions": false] + + func testIdentityExpressionInSwift6() throws { + try XCTSkipIf(SwiftVersion.current < .six) + + let description = PreferKeyPathRule.description + .with(nonTriggeringExamples: [ + Example("f.filter { a in b }"), + Example("f.g { $1 }", configuration: Self.extendedMode), + ]) + .with(triggeringExamples: [ + Example("f.compactMap ↓{ $0 }"), + Example("f.map ↓{ a in a }"), + Example("f.g { $0 }", configuration: Self.extendedMode), + ]) + .with(corrections: [ + Example("f.map ↓{ $0 }"): + Example("f.map(\\.self)"), + Example("f.g { $0 }", configuration: Self.extendedMode): + Example("f.g(\\.self)"), + ]) + + verifyRule(description) + } +}