From c9705546053561fbee6a8b0861456ba974fcca7a Mon Sep 17 00:00:00 2001 From: Leonardo Rodrigues Date: Mon, 1 Apr 2024 15:37:09 +1100 Subject: [PATCH] Add ignore_multiline_condition_statements option for opening_brace rule --- .../OpeningBraceConfiguration.swift | 2 + .../Rules/Style/OpeningBraceRule.swift | 53 ++++++++++++++--- .../OpeningBraceRuleTests.swift | 57 ++++++++++++++++++- 3 files changed, 102 insertions(+), 10 deletions(-) diff --git a/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift b/Source/SwiftLintBuiltInRules/Rules/RuleConfigurations/OpeningBraceConfiguration.swift index 85f40e1da0b..3ee5afa98ed 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: "ignore_multiline_condition_statements") + private(set) var ignoreMultilineConditionStatement = true } diff --git a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift index e12ff4f840b..227dea97dfc 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Style/OpeningBraceRule.swift @@ -69,6 +69,9 @@ private extension OpeningBraceRule { override func visitPost(_ node: CatchClauseSyntax) { let body = node.body + if isIgnoredMultilineConditionStatement(body, keywordToken: node.catchKeyword) { + return + } if let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) @@ -77,6 +80,9 @@ private extension OpeningBraceRule { override func visitPost(_ node: DeferStmtSyntax) { let body = node.body + if isIgnoredMultilineConditionStatement(body, keywordToken: node.deferKeyword) { + return + } if let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) @@ -85,6 +91,9 @@ private extension OpeningBraceRule { override func visitPost(_ node: DoStmtSyntax) { let body = node.body + if isIgnoredMultilineConditionStatement(body, keywordToken: node.doKeyword) { + return + } if let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) @@ -93,6 +102,9 @@ private extension OpeningBraceRule { override func visitPost(_ node: ForStmtSyntax) { let body = node.body + if isIgnoredMultilineConditionStatement(body, keywordToken: node.forKeyword) { + return + } if let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) @@ -101,6 +113,9 @@ private extension OpeningBraceRule { override func visitPost(_ node: GuardStmtSyntax) { let body = node.body + if isIgnoredMultilineConditionStatement(body, keywordToken: node.guardKeyword) { + return + } if let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) @@ -109,7 +124,8 @@ private extension OpeningBraceRule { override func visitPost(_ node: IfExprSyntax) { let body = node.body - if let correction = body.violationCorrection(locationConverter) { + if !isIgnoredMultilineConditionStatement(body, keywordToken: node.ifKeyword), + let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) } @@ -121,6 +137,9 @@ private extension OpeningBraceRule { override func visitPost(_ node: RepeatStmtSyntax) { let body = node.body + if isIgnoredMultilineConditionStatement(body, keywordToken: node.repeatKeyword) { + return + } if let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) @@ -129,6 +148,9 @@ private extension OpeningBraceRule { override func visitPost(_ node: WhileStmtSyntax) { let body = node.body + if isIgnoredMultilineConditionStatement(body, keywordToken: node.whileKeyword) { + return + } if let correction = body.violationCorrection(locationConverter) { violations.append(body.openingPosition) violationCorrections.append(correction) @@ -184,7 +206,7 @@ private extension OpeningBraceRule { guard let body = node.body else { return } - if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.funcKeyword) { + if isIgnoredMultilineFunc(body, keywordToken: node.funcKeyword) { return } if let correction = body.violationCorrection(locationConverter) { @@ -197,7 +219,7 @@ private extension OpeningBraceRule { guard let body = node.body else { return } - if configuration.allowMultilineFunc, refersToMultilineFunction(body, functionIndicator: node.initKeyword) { + if isIgnoredMultilineFunc(body, keywordToken: node.initKeyword) { return } if let correction = body.violationCorrection(locationConverter) { @@ -206,14 +228,29 @@ private extension OpeningBraceRule { } } - private func refersToMultilineFunction(_ body: CodeBlockSyntax, functionIndicator: TokenSyntax) -> Bool { + private func isIgnoredMultilineFunc(_ body: CodeBlockSyntax, keywordToken: TokenSyntax) -> Bool { + guard configuration.allowMultilineFunc else { + return false + } + + return isBodyPredecessorMultiline(body, keywordToken: keywordToken) + } + + private func isIgnoredMultilineConditionStatement(_ body: CodeBlockSyntax, keywordToken: TokenSyntax) -> Bool { + guard configuration.ignoreMultilineConditionStatement else { + return false + } + + return isBodyPredecessorMultiline(body, keywordToken: keywordToken) + } + + private func isBodyPredecessorMultiline(_ body: CodeBlockSyntax, keywordToken: TokenSyntax) -> Bool { guard let endToken = body.previousToken(viewMode: .sourceAccurate) else { return false } - let startLocation = functionIndicator.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 + let keywordEndLocation = keywordToken.endLocation(converter: locationConverter) + let bodyPredecessorEndLocation = endToken.endLocation(converter: locationConverter) + return keywordEndLocation.line != bodyPredecessorEndLocation.line } } } diff --git a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift index bdc0a0b9430..e825217cdf5 100644 --- a/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift +++ b/Tests/SwiftLintFrameworkTests/OpeningBraceRuleTests.swift @@ -1,7 +1,7 @@ @testable import SwiftLintBuiltInRules class OpeningBraceRuleTests: SwiftLintTestCase { - func testDefaultExamplesRunInMultilineMode() { + func testDefaultExamplesRunInMultilineFuncMode() { let description = OpeningBraceRule.description .with(triggeringExamples: OpeningBraceRule.description.triggeringExamples.removing([ Example("func abc(a: A,\n\tb: B)\n↓{"), @@ -19,7 +19,7 @@ class OpeningBraceRuleTests: SwiftLintTestCase { } // swiftlint:disable:next function_body_length - func testWithAllowMultilineTrue() { + func testWithAllowMultilineFuncTrue() { let nonTriggeringExamples = [ Example(""" func abc( @@ -89,6 +89,59 @@ class OpeningBraceRuleTests: SwiftLintTestCase { verifyRule(description, ruleConfiguration: ["allow_multiline_func": true]) } + + func testWithIgnoreMultilineConditionStatementsTrue() { + let nonTriggeringExamples = OpeningBraceRule.description.nonTriggeringExamples + [ + Example(""" + if x, + y + { + + } else if z, + w + { + + } + """), + Example(""" + while + x, + y + {} + """) + ] + + let triggeringExamples = [ + Example(""" + if x, y + { + + } + """), + Example(""" + if + x, + y + { + + } else if z + { + + } + """), + Example(""" + while x, y + {} + """) + ] + + let description = OpeningBraceRule.description + .with(nonTriggeringExamples: nonTriggeringExamples) + .with(triggeringExamples: triggeringExamples) + .with(corrections: [:]) + + verifyRule(description, ruleConfiguration: ["ignore_multiline_condition_statements": true]) + } } private extension Array where Element == Example {