diff --git a/.swiftlint.yml b/.swiftlint.yml index 3f27461534..8d337ced0d 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -25,6 +25,7 @@ disabled_rules: - discouraged_optional_collection - explicit_acl - explicit_enum_raw_value + - explicit_return - explicit_top_level_acl - explicit_type_interface - file_types_order diff --git a/CHANGELOG.md b/CHANGELOG.md index f6455ddce4..d113412bce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,13 @@ built-in rules in accordance with the SARIF specification. [ahmadalfy](https://github.com/ahmadalfy) [#6499](https://github.com/realm/SwiftLint/issues/6499) + +* Add `explicit_return` opt-in rule that warns against omitting the `return` + keyword inside closures, functions and getters. + [m-chojnacki](https://github.com/m-chojnacki) + [talanov](https://github.com/talanov) + [#3632](https://github.com/realm/SwiftLint/issues/3632) + [#3859](https://github.com/realm/SwiftLint/issues/3859) * Add `allow_underscore_prefixed_names` option to `unused_parameter` so underscore-prefixed parameter names can be treated as intentionally diff --git a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift index b6341fe12e..db01438f0d 100644 --- a/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift +++ b/Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift @@ -62,6 +62,7 @@ public let builtInRules: [any Rule.Type] = [ ExplicitACLRule.self, ExplicitEnumRawValueRule.self, ExplicitInitRule.self, + ExplicitReturnRule.self, ExplicitSelfRule.self, ExplicitTopLevelACLRule.self, ExplicitTypeInterfaceRule.self, diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitReturnConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitReturnConfiguration.swift new file mode 100644 index 0000000000..61ef5ba868 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/ExplicitReturnConfiguration.swift @@ -0,0 +1,32 @@ +import SwiftLintCore + +@AutoConfigParser +struct ExplicitReturnConfiguration: SeverityBasedRuleConfiguration { + @AcceptableByConfigurationElement + enum ReturnKind: String, CaseIterable, Comparable { + case closure + case function + case getter + case `subscript` + case initializer + + static func < (lhs: Self, rhs: Self) -> Bool { + lhs.rawValue < rhs.rawValue + } + } + + static let defaultIncludedKinds: Set = [.function, .getter, .subscript, .initializer] + + @ConfigurationElement(key: "severity") + private(set) var severityConfiguration = SeverityConfiguration(.warning) + @ConfigurationElement(key: "included") + private(set) var includedKinds = Self.defaultIncludedKinds + + init(includedKinds: Set = Self.defaultIncludedKinds) { + self.includedKinds = includedKinds + } + + func isKindIncluded(_ kind: ReturnKind) -> Bool { + includedKinds.contains(kind) + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitReturnRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitReturnRule.swift new file mode 100644 index 0000000000..515a282f09 --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitReturnRule.swift @@ -0,0 +1,115 @@ +import Foundation +import SwiftSyntax + +@SwiftSyntaxRule(correctable: true, optIn: true) +struct ExplicitReturnRule: Rule { + var configuration = ExplicitReturnConfiguration() + + static let description = RuleDescription( + identifier: "explicit_return", + name: "Explicit Return", + description: "Prefer explicit returns in closures, functions and getters", + kind: .style, + nonTriggeringExamples: ExplicitReturnRuleExamples.nonTriggeringExamples, + triggeringExamples: ExplicitReturnRuleExamples.triggeringExamples, + corrections: ExplicitReturnRuleExamples.corrections + ) +} + +private extension ExplicitReturnRule { + final class Visitor: ViolationsSyntaxVisitor { + override var skippableDeclarations: [any DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] } + + override func visitPost(_ node: AccessorDeclSyntax) { + if configuration.isKindIncluded(.getter), + node.accessorSpecifier.tokenKind == .keyword(.get), + let body = node.body { + collectViolation(in: body.statements) + } + } + + override func visitPost(_ node: ClosureExprSyntax) { + if configuration.isKindIncluded(.closure) { + collectViolation(in: node.statements, isInsideClosure: true) + } + } + + override func visitPost(_ node: FunctionDeclSyntax) { + if configuration.isKindIncluded(.function), + node.signature.allowsImplicitReturns, + let body = node.body { + collectViolation(in: body.statements) + } + } + + override func visitPost(_ node: InitializerDeclSyntax) { + if configuration.isKindIncluded(.initializer), + node.optionalMark != nil, + let body = node.body { + collectViolation(in: body.statements) + } + } + + override func visitPost(_ node: PatternBindingSyntax) { + if configuration.isKindIncluded(.getter), + case let .getter(itemList) = node.accessorBlock?.accessors { + collectViolation(in: itemList) + } + } + + override func visitPost(_ node: SubscriptDeclSyntax) { + if configuration.isKindIncluded(.subscript), + case let .getter(itemList) = node.accessorBlock?.accessors { + collectViolation(in: itemList) + } + } + + private func collectViolation(in itemList: CodeBlockItemListSyntax, isInsideClosure: Bool = false) { + guard let onlyItem = itemList.onlyElement?.item, + !onlyItem.is(ReturnStmtSyntax.self), + Syntax(onlyItem).isProtocol((any ExprSyntaxProtocol).self) else { + return + } + if isInsideClosure, Syntax(onlyItem).isFunctionCallExpr { + return + } + let position = onlyItem.positionAfterSkippingLeadingTrivia + violations.append( + at: position, + correction: .init( + start: position, + end: position, + replacement: "return " + ) + ) + } + } +} + +private extension Syntax { + var isFunctionCallExpr: Bool { + if `is`(FunctionCallExprSyntax.self) { + return true + } + if let tryExpr = `as`(TryExprSyntax.self) { + return Syntax(tryExpr.expression).isFunctionCallExpr + } + if let awaitExpr = `as`(AwaitExprSyntax.self) { + return Syntax(awaitExpr.expression).isFunctionCallExpr + } + return false + } +} + +private extension FunctionSignatureSyntax { + var allowsImplicitReturns: Bool { + guard let returnClause else { return false } + if let identifierType = returnClause.type.as(IdentifierTypeSyntax.self) { + return identifierType.name.text != "Void" && identifierType.name.text != "Never" + } + if let tupleType = returnClause.type.as(TupleTypeSyntax.self) { + return !tupleType.elements.isEmpty + } + return true + } +} diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitReturnRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitReturnRuleExamples.swift new file mode 100644 index 0000000000..9d5239bb4f --- /dev/null +++ b/Source/SwiftLintBuiltInRules/Rules/Style/ExplicitReturnRuleExamples.swift @@ -0,0 +1,514 @@ +// swiftlint:disable file_length +// swiftlint:disable:next type_body_length +internal struct ExplicitReturnRuleExamples { + private static let closureConfig: [String: any Sendable] = [ + "included": ["closure", "function", "getter", "subscript", "initializer"], + ] + + internal struct ClosureExamples { + static let nonTriggeringExamples = [ + Example(""" + foo.map { + return $0 + 1 + } + """, configuration: closureConfig), + Example(""" + foo.map({ + return $0 + 1 + }) + """, configuration: closureConfig), + Example(""" + foo.map { value in + return value + 1 + } + """, configuration: closureConfig), + Example(""" + [1, 2].first(where: { + return true + }) + """, configuration: closureConfig), + Example(""" + [1, 2].first(where: { + bar($0) + return true + }) + """, configuration: closureConfig), + Example(""" + runOn(.main, { + controller?.present(alert, animated: true, completion: nil) + }) + """, configuration: closureConfig), + Example(""" + foo.bar(failure: { error in + cont.resume(throwing: error) + }) + """, configuration: closureConfig), + Example(""" + foo.map { + someFunc($0) + } + """, configuration: closureConfig), + Example(""" + foo.map { + try someFunc($0) + } + """, configuration: closureConfig), + Example(""" + foo.map { + await someFunc($0) + } + """, configuration: closureConfig), + ] + + static let triggeringExamples = [ + Example(""" + foo.map { value in + ↓value + 1 + } + """, configuration: closureConfig), + Example(""" + foo.map { + ↓$0 + 1 + } + """, configuration: closureConfig), + Example("foo.map({ ↓$0 + 1 })", configuration: closureConfig), + Example(""" + [1, 2].first(where: { + ↓true + }) + """, configuration: closureConfig), + ] + + static let corrections: [Example: Example] = [ + Example(""" + foo.map { value in + // Important comment + value + 1 + } + """, configuration: closureConfig): Example(""" + foo.map { value in + // Important comment + return value + 1 + } + """), + Example(""" + foo.map { + $0 + 1 + } + """, configuration: closureConfig): Example(""" + foo.map { + return $0 + 1 + } + """), + Example("foo.map({ $0 + 1 })", configuration: closureConfig): + Example("foo.map({ return $0 + 1 })"), + Example(""" + [1, 2].first(where: { + true + }) + """, configuration: closureConfig): Example(""" + [1, 2].first(where: { + return true + }) + """), + ] + } + + struct FunctionExamples { + static let nonTriggeringExamples = [ + Example(""" + func foo() -> Int { + return 0 + } + """), + Example(""" + class Foo { + func foo() -> Int { return 0 } + } + """), + Example(""" + func fetch() -> Data? { + do { + return try loadData() + } catch { + return nil + } + } + """), + Example(""" + func f() -> Int { + let i = 4 + return i + } + """), + Example(""" + func f() -> Int { + return 3 + let i = 2 + } + """), + Example(""" + func f() -> Int { + return g() + func g() -> Int { return 4 } + } + """), + Example(""" + func foo() { + bar() + } + """), + Example(""" + func foo() -> Void { + bar() + } + """), + Example(""" + func foo() -> () { + bar() + } + """), + Example(""" + func foo() -> Never { + fatalError() + } + """), + Example(""" + func foo() throws { + throw Foo.bar + } + """), + Example(""" + func foo() -> Int { + bar() + return 0 + } + """), + ] + + static let triggeringExamples = [ + Example(""" + func foo() -> Int { + ↓0 + } + """), + Example(""" + class Foo { + func foo() -> Int { ↓0 } + } + """), + Example(""" + static func foo() -> Int { + ↓0 + } + """), + Example(""" + func foo() -> (Int, String) { + ↓(0, "bar") + } + """), + ] + + static let corrections = [ + Example(""" + func foo() -> Int { + 0 + } + """): Example(""" + func foo() -> Int { + return 0 + } + """), + Example(""" + class Foo { + func foo() -> Int { + 0 + } + } + """): Example(""" + class Foo { + func foo() -> Int { + return 0 + } + } + """), + Example(""" + static func foo() -> Int { + 0 + } + """): Example(""" + static func foo() -> Int { + return 0 + } + """), + Example(""" + func foo() -> (Int, String) { + (0, "bar") + } + """): Example(""" + func foo() -> (Int, String) { + return (0, "bar") + } + """), + ] + } + + struct GetterExamples { + static let nonTriggeringExamples = [ + Example("var foo: Bool { return true }"), + Example(""" + class Foo { + var bar: Int { + get { + return 0 + } + } + } + """), + Example(""" + class Foo { + static var bar: Int { + return 0 + } + } + """), + Example(""" + var foo: Bool { + bar() + return true + } + """), + ] + + static let triggeringExamples = [ + Example("var foo: Bool { ↓true }"), + Example(""" + class Foo { + var bar: Int { + get { + ↓0 + } + } + } + """), + Example(""" + class Foo { + static var bar: Int { + ↓0 + } + } + """), + ] + + static let corrections = [ + Example("var foo: Bool { true }"): Example("var foo: Bool { return true }"), + Example(""" + class Foo { + var bar: Int { + get { + 0 + } + } + } + """): Example(""" + class Foo { + var bar: Int { + get { + return 0 + } + } + } + """), + Example(""" + class Foo { + static var bar: Int { + 0 + } + } + """): Example(""" + class Foo { + static var bar: Int { + return 0 + } + } + """), + ] + } + + struct InitializerExamples { + static let nonTriggeringExamples = [ + Example(""" + class C { + let i: Int + init(i: Int) { + if i < 3 { + self.i = 1 + return + } + self.i = 2 + } + } + """), + Example(""" + class C { + init?() { + let i = 1 + return nil + } + } + """), + Example(""" + class C { + init?() { + return nil + } + } + """), + Example(""" + class C { + init() {} + } + """), + Example(""" + class C { + init() { + setup() + } + } + """), + ] + + static let triggeringExamples = [ + Example(""" + class C { + init?() { + ↓nil + } + } + """), + ] + + static let corrections = [ + Example(""" + class C { + init?() { + nil + } + } + """): Example(""" + class C { + init?() { + return nil + } + } + """), + ] + } + + struct SubscriptExamples { + static let nonTriggeringExamples = [ + Example(""" + class C { + subscript(i: Int) -> Int { + let res = i + return res + } + } + """), + Example(""" + class C { + subscript(i: Int) -> Int { + return i + } + } + """), + ] + + static let triggeringExamples = [ + Example(""" + class C { + subscript(i: Int) -> Int { + ↓i + } + } + """), + ] + + static let corrections = [ + Example(""" + class C { + subscript(i: Int) -> Int { + i + } + } + """): Example(""" + class C { + subscript(i: Int) -> Int { + return i + } + } + """), + ] + } + + struct MixedExamples { + static let corrections: [Example: Example] = [ + Example(""" + func foo() -> Int { + ↓[1, 2].first(where: { + ↓true + })! + } + """, configuration: closureConfig): Example(""" + func foo() -> Int { + return [1, 2].first(where: { + return true + })! + } + """), + Example(""" + func foo() -> Int { + ↓[1, 2].first(where: { + true + })! + } + """): Example(""" + func foo() -> Int { + return [1, 2].first(where: { + true + })! + } + """), + ] + } + + static let nonTriggeringExamples = + ClosureExamples.nonTriggeringExamples + + FunctionExamples.nonTriggeringExamples + + GetterExamples.nonTriggeringExamples + + InitializerExamples.nonTriggeringExamples + + SubscriptExamples.nonTriggeringExamples + + static let triggeringExamples = + ClosureExamples.triggeringExamples + + FunctionExamples.triggeringExamples + + GetterExamples.triggeringExamples + + InitializerExamples.triggeringExamples + + SubscriptExamples.triggeringExamples + + static var corrections: [Example: Example] { + [ + ClosureExamples.corrections, + FunctionExamples.corrections, + GetterExamples.corrections, + InitializerExamples.corrections, + SubscriptExamples.corrections, + MixedExamples.corrections, + ] + .reduce(into: [:]) { result, element in + result.merge(element) { _, _ in + preconditionFailure("Duplicate correction in explicit return rule examples.") + } + } + } +} diff --git a/Tests/FileSystemAccessTests/ExplicitReturnConfigurationTests.swift b/Tests/FileSystemAccessTests/ExplicitReturnConfigurationTests.swift new file mode 100644 index 0000000000..270bde6bb2 --- /dev/null +++ b/Tests/FileSystemAccessTests/ExplicitReturnConfigurationTests.swift @@ -0,0 +1,39 @@ +@testable import SwiftLintBuiltInRules +import TestHelpers +import XCTest + +final class ExplicitReturnConfigurationTests: SwiftLintTestCase { + func testExplicitReturnConfigurationFromDictionary() throws { + var configuration = ExplicitReturnConfiguration(includedKinds: Set()) + let config: [String: Any] = [ + "severity": "error", + "included": [ + "closure", + "function", + "getter", + "initializer", + "subscript", + ], + ] + + try configuration.apply(configuration: config) + let expectedKinds: Set = Set([ + .closure, + .function, + .getter, + .initializer, + .subscript, + ]) + XCTAssertEqual(configuration.severityConfiguration.severity, .error) + XCTAssertEqual(configuration.includedKinds, expectedKinds) + } + + func testExplicitReturnConfigurationThrowsOnUnrecognizedModifierGroup() { + var configuration = ExplicitReturnConfiguration() + let config = ["included": ["foreach"]] as [String: any Sendable] + + checkError(Issue.invalidConfiguration(ruleID: ExplicitReturnRule.identifier)) { + try configuration.apply(configuration: config) + } + } +} diff --git a/Tests/FileSystemAccessTests/ExplicitReturnRuleTests.swift b/Tests/FileSystemAccessTests/ExplicitReturnRuleTests.swift new file mode 100644 index 0000000000..8b1f2330e7 --- /dev/null +++ b/Tests/FileSystemAccessTests/ExplicitReturnRuleTests.swift @@ -0,0 +1,98 @@ +@testable import SwiftLintBuiltInRules +import TestHelpers + +final class ExplicitReturnRuleTests: SwiftLintTestCase { + func testOnlyClosureKindIncluded() { + var nonTriggeringExamples = ExplicitReturnRuleExamples.nonTriggeringExamples + + ExplicitReturnRuleExamples.triggeringExamples + nonTriggeringExamples.removeAll( + where: ExplicitReturnRuleExamples.ClosureExamples.triggeringExamples.contains + ) + nonTriggeringExamples.removeAll { $0.configuration != nil } + + verifySubset( + nonTriggeringExamples: nonTriggeringExamples, + triggeringExamples: ExplicitReturnRuleExamples.ClosureExamples.triggeringExamples, + corrections: ExplicitReturnRuleExamples.ClosureExamples.corrections, + kind: .closure + ) + } + + func testOnlyFunctionKindIncluded() { + var nonTriggeringExamples = ExplicitReturnRuleExamples.nonTriggeringExamples + + ExplicitReturnRuleExamples.triggeringExamples + nonTriggeringExamples.removeAll( + where: ExplicitReturnRuleExamples.FunctionExamples.triggeringExamples.contains + ) + nonTriggeringExamples.removeAll { $0.configuration != nil } + + verifySubset( + nonTriggeringExamples: nonTriggeringExamples, + triggeringExamples: ExplicitReturnRuleExamples.FunctionExamples.triggeringExamples, + corrections: ExplicitReturnRuleExamples.FunctionExamples.corrections, + kind: .function + ) + } + + func testOnlyGetterKindIncluded() { + var nonTriggeringExamples = ExplicitReturnRuleExamples.nonTriggeringExamples + + ExplicitReturnRuleExamples.triggeringExamples + nonTriggeringExamples.removeAll( + where: ExplicitReturnRuleExamples.GetterExamples.triggeringExamples.contains + ) + nonTriggeringExamples.removeAll { $0.configuration != nil } + + verifySubset( + nonTriggeringExamples: nonTriggeringExamples, + triggeringExamples: ExplicitReturnRuleExamples.GetterExamples.triggeringExamples, + corrections: ExplicitReturnRuleExamples.GetterExamples.corrections, + kind: .getter + ) + } + + func testOnlyInitializerKindIncluded() { + var nonTriggeringExamples = ExplicitReturnRuleExamples.nonTriggeringExamples + + ExplicitReturnRuleExamples.triggeringExamples + nonTriggeringExamples.removeAll( + where: ExplicitReturnRuleExamples.InitializerExamples.triggeringExamples.contains + ) + nonTriggeringExamples.removeAll { $0.configuration != nil } + + verifySubset( + nonTriggeringExamples: nonTriggeringExamples, + triggeringExamples: ExplicitReturnRuleExamples.InitializerExamples.triggeringExamples, + corrections: ExplicitReturnRuleExamples.InitializerExamples.corrections, + kind: .initializer + ) + } + + func testOnlySubscriptKindIncluded() { + var nonTriggeringExamples = ExplicitReturnRuleExamples.nonTriggeringExamples + + ExplicitReturnRuleExamples.triggeringExamples + nonTriggeringExamples.removeAll( + where: ExplicitReturnRuleExamples.SubscriptExamples.triggeringExamples.contains + ) + nonTriggeringExamples.removeAll { $0.configuration != nil } + + verifySubset( + nonTriggeringExamples: nonTriggeringExamples, + triggeringExamples: ExplicitReturnRuleExamples.SubscriptExamples.triggeringExamples, + corrections: ExplicitReturnRuleExamples.SubscriptExamples.corrections, + kind: .subscript + ) + } + + private func verifySubset( + nonTriggeringExamples: [Example], + triggeringExamples: [Example], + corrections: [Example: Example], + kind: ExplicitReturnConfiguration.ReturnKind + ) { + let description = ExplicitReturnRule.description + .with(nonTriggeringExamples: nonTriggeringExamples.removingViolationMarker()) + .with(triggeringExamples: triggeringExamples) + .with(corrections: corrections) + + verifyRule(description, ruleConfiguration: ["included": [kind.rawValue]]) + } +} diff --git a/Tests/GeneratedTests/GeneratedTests_03.swift b/Tests/GeneratedTests/GeneratedTests_03.swift index 0ee3ec83be..64055bb3c2 100644 --- a/Tests/GeneratedTests/GeneratedTests_03.swift +++ b/Tests/GeneratedTests/GeneratedTests_03.swift @@ -67,6 +67,12 @@ final class ExplicitInitRuleGeneratedTests: SwiftLintTestCase { } } +final class ExplicitReturnRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(ExplicitReturnRule.description) + } +} + final class ExplicitSelfRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ExplicitSelfRule.description) @@ -150,9 +156,3 @@ final class FlatMapOverMapReduceRuleGeneratedTests: SwiftLintTestCase { verifyRule(FlatMapOverMapReduceRule.description) } } - -final class ForWhereRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(ForWhereRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_04.swift b/Tests/GeneratedTests/GeneratedTests_04.swift index 182ec2dc64..bb57e9b71c 100644 --- a/Tests/GeneratedTests/GeneratedTests_04.swift +++ b/Tests/GeneratedTests/GeneratedTests_04.swift @@ -7,6 +7,12 @@ @testable import SwiftLintCore import TestHelpers +final class ForWhereRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(ForWhereRule.description) + } +} + final class ForceCastRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(ForceCastRule.description) @@ -150,9 +156,3 @@ final class LastWhereRuleGeneratedTests: SwiftLintTestCase { verifyRule(LastWhereRule.description) } } - -final class LeadingWhitespaceRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(LeadingWhitespaceRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_05.swift b/Tests/GeneratedTests/GeneratedTests_05.swift index de1f84b7cc..5c4083be83 100644 --- a/Tests/GeneratedTests/GeneratedTests_05.swift +++ b/Tests/GeneratedTests/GeneratedTests_05.swift @@ -7,6 +7,12 @@ @testable import SwiftLintCore import TestHelpers +final class LeadingWhitespaceRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(LeadingWhitespaceRule.description) + } +} + final class LegacyCGGeometryFunctionsRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(LegacyCGGeometryFunctionsRule.description) @@ -150,9 +156,3 @@ final class MultipleClosuresWithTrailingClosureRuleGeneratedTests: SwiftLintTest verifyRule(MultipleClosuresWithTrailingClosureRule.description) } } - -final class NSLocalizedStringKeyRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(NSLocalizedStringKeyRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_06.swift b/Tests/GeneratedTests/GeneratedTests_06.swift index 56f4065ffc..7319dcce3a 100644 --- a/Tests/GeneratedTests/GeneratedTests_06.swift +++ b/Tests/GeneratedTests/GeneratedTests_06.swift @@ -7,6 +7,12 @@ @testable import SwiftLintCore import TestHelpers +final class NSLocalizedStringKeyRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(NSLocalizedStringKeyRule.description) + } +} + final class NSLocalizedStringRequireBundleRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(NSLocalizedStringRequireBundleRule.description) @@ -150,9 +156,3 @@ final class OverrideInExtensionRuleGeneratedTests: SwiftLintTestCase { verifyRule(OverrideInExtensionRule.description) } } - -final class PatternMatchingKeywordsRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(PatternMatchingKeywordsRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_07.swift b/Tests/GeneratedTests/GeneratedTests_07.swift index cf4a0b2f2c..2637e38154 100644 --- a/Tests/GeneratedTests/GeneratedTests_07.swift +++ b/Tests/GeneratedTests/GeneratedTests_07.swift @@ -7,6 +7,12 @@ @testable import SwiftLintCore import TestHelpers +final class PatternMatchingKeywordsRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(PatternMatchingKeywordsRule.description) + } +} + final class PeriodSpacingRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(PeriodSpacingRule.description) @@ -150,9 +156,3 @@ final class ReduceBooleanRuleGeneratedTests: SwiftLintTestCase { verifyRule(ReduceBooleanRule.description) } } - -final class ReduceIntoRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(ReduceIntoRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_08.swift b/Tests/GeneratedTests/GeneratedTests_08.swift index 52a3277c6f..982498744b 100644 --- a/Tests/GeneratedTests/GeneratedTests_08.swift +++ b/Tests/GeneratedTests/GeneratedTests_08.swift @@ -7,6 +7,12 @@ @testable import SwiftLintCore import TestHelpers +final class ReduceIntoRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(ReduceIntoRule.description) + } +} + final class RedundantDiscardableLetRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(RedundantDiscardableLetRule.description) @@ -150,9 +156,3 @@ final class StaticOperatorRuleGeneratedTests: SwiftLintTestCase { verifyRule(StaticOperatorRule.description) } } - -final class StaticOverFinalClassRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(StaticOverFinalClassRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_09.swift b/Tests/GeneratedTests/GeneratedTests_09.swift index 28abe745ff..7d910e9c49 100644 --- a/Tests/GeneratedTests/GeneratedTests_09.swift +++ b/Tests/GeneratedTests/GeneratedTests_09.swift @@ -7,6 +7,12 @@ @testable import SwiftLintCore import TestHelpers +final class StaticOverFinalClassRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(StaticOverFinalClassRule.description) + } +} + final class StrictFilePrivateRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(StrictFilePrivateRule.description) @@ -150,9 +156,3 @@ final class UnneededOverrideRuleGeneratedTests: SwiftLintTestCase { verifyRule(UnneededOverrideRule.description) } } - -final class UnneededParenthesesInClosureArgumentRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(UnneededParenthesesInClosureArgumentRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_10.swift b/Tests/GeneratedTests/GeneratedTests_10.swift index 46bb104908..af361d1172 100644 --- a/Tests/GeneratedTests/GeneratedTests_10.swift +++ b/Tests/GeneratedTests/GeneratedTests_10.swift @@ -7,6 +7,12 @@ @testable import SwiftLintCore import TestHelpers +final class UnneededParenthesesInClosureArgumentRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(UnneededParenthesesInClosureArgumentRule.description) + } +} + final class UnneededSynthesizedInitializerRuleGeneratedTests: SwiftLintTestCase { func testWithDefaultConfiguration() { verifyRule(UnneededSynthesizedInitializerRule.description) @@ -150,9 +156,3 @@ final class XCTSpecificMatcherRuleGeneratedTests: SwiftLintTestCase { verifyRule(XCTSpecificMatcherRule.description) } } - -final class YodaConditionRuleGeneratedTests: SwiftLintTestCase { - func testWithDefaultConfiguration() { - verifyRule(YodaConditionRule.description) - } -} diff --git a/Tests/GeneratedTests/GeneratedTests_11.swift b/Tests/GeneratedTests/GeneratedTests_11.swift new file mode 100644 index 0000000000..758f00504c --- /dev/null +++ b/Tests/GeneratedTests/GeneratedTests_11.swift @@ -0,0 +1,14 @@ +// GENERATED FILE. DO NOT EDIT! + +// swiftlint:disable:next blanket_disable_command superfluous_disable_command +// swiftlint:disable single_test_class type_name + +@testable import SwiftLintBuiltInRules +@testable import SwiftLintCore +import TestHelpers + +final class YodaConditionRuleGeneratedTests: SwiftLintTestCase { + func testWithDefaultConfiguration() { + verifyRule(YodaConditionRule.description) + } +} diff --git a/Tests/IntegrationTests/Resources/default_rule_configurations.yml b/Tests/IntegrationTests/Resources/default_rule_configurations.yml index fb30c62bd2..fec2e538a1 100644 --- a/Tests/IntegrationTests/Resources/default_rule_configurations.yml +++ b/Tests/IntegrationTests/Resources/default_rule_configurations.yml @@ -336,6 +336,12 @@ explicit_init: meta: opt-in: true correctable: true +explicit_return: + severity: warning + included: [function, getter, initializer, subscript] + meta: + opt-in: true + correctable: true explicit_self: severity: warning meta: diff --git a/Tests/generated_tests.bzl b/Tests/generated_tests.bzl index 689f1a5310..e82cc1832d 100644 --- a/Tests/generated_tests.bzl +++ b/Tests/generated_tests.bzl @@ -14,7 +14,8 @@ GENERATED_TEST_TARGETS = [ "//Tests:GeneratedTests_07", "//Tests:GeneratedTests_08", "//Tests:GeneratedTests_09", - "//Tests:GeneratedTests_10" + "//Tests:GeneratedTests_10", + "//Tests:GeneratedTests_11" ] def generated_tests(): @@ -29,6 +30,7 @@ def generated_tests(): generated_test_shard("08") generated_test_shard("09") generated_test_shard("10") + generated_test_shard("11") native.test_suite( name = "GeneratedTests",