diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d5f32c0f..c5daf95dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ [imsonalbajaj](https://github.com/imsonalbajaj) [#6054](https://github.com/realm/SwiftLint/issues/6054) +* Ignore various assignment operators like `=`, `+=`, `&=`, etc. with right-hand side + ternary expressions otherwise violating the `void_function_in_ternary` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5611](https://github.com/realm/SwiftLint/issues/5611) + * Rewrite the following rules with SwiftSyntax: * `accessibility_label_for_image` * `accessibility_trait_for_button` diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift index 8d6cc648c..25f5dd157 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/VoidFunctionInTernaryConditionRule.swift @@ -11,7 +11,6 @@ struct VoidFunctionInTernaryConditionRule: Rule { kind: .idiomatic, minSwiftVersion: .fiveDotOne, nonTriggeringExamples: [ - Example("let result = success ? foo() : bar()"), Example(""" if success { askQuestion() @@ -60,6 +59,14 @@ struct VoidFunctionInTernaryConditionRule: Rule { subscript(index: Int) -> Int { index == 0 ? defaultValue() : compute(index) """), + Example(""" + var a = b ? c() : d() + a += b ? c() : d() + a -= b ? c() : d() + a *= b ? c() : d() + a &<<= b ? c() : d() + a &-= b ? c() : d() + """), ], triggeringExamples: [ Example("success ↓? askQuestion() : exit()"), @@ -144,18 +151,43 @@ private extension VoidFunctionInTernaryConditionRule { private extension ExprListSyntax { var containsAssignment: Bool { - children(viewMode: .sourceAccurate).contains(where: { $0.is(AssignmentExprSyntax.self) }) + children(viewMode: .sourceAccurate).contains { + if let binOp = $0.as(BinaryOperatorExprSyntax.self) { + // https://developer.apple.com/documentation/swift/operator-declarations + return [ + "*=", + "/=", + "%=", + "+=", + "-=", + "<<=", + ">>=", + "&=", + "|=", + "^=", + "&*=", + "&+=", + "&-=", + "&<<=", + "&>>=", + ".&=", + ".|=", + ".^=", + ].contains(binOp.operator.text) + } + return $0.is(AssignmentExprSyntax.self) + } } } private extension CodeBlockItemSyntax { var isImplicitReturn: Bool { - isClosureImplictReturn || isFunctionImplicitReturn || + isClosureImplicitReturn || isFunctionImplicitReturn || isVariableImplicitReturn || isSubscriptImplicitReturn || - isAcessorImplicitReturn + isAccessorImplicitReturn } - var isClosureImplictReturn: Bool { + var isClosureImplicitReturn: Bool { guard let parent = parent?.as(CodeBlockItemListSyntax.self), let grandparent = parent.parent else { return false @@ -191,7 +223,7 @@ private extension CodeBlockItemSyntax { return parent.children(viewMode: .sourceAccurate).count == 1 && subscriptDecl.allowsImplicitReturns } - var isAcessorImplicitReturn: Bool { + var isAccessorImplicitReturn: Bool { guard let parent = parent?.as(CodeBlockItemListSyntax.self), parent.parent?.parent?.as(AccessorDeclSyntax.self) != nil else { return false