From 73e6ba3067c831abde96a449385d0f0a610ef2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sun, 15 Oct 2023 12:43:43 +0200 Subject: [PATCH] Add parentheses to corrected opaque and existential optionals (#5278) --- CHANGELOG.md | 5 +++++ .../Rules/Idiomatic/SyntacticSugarRule.swift | 12 ++++++++++++ .../Rules/Idiomatic/SyntacticSugarRuleExamples.swift | 2 ++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd247e5450..f4db4eefe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ #### Bug Fixes +* Fix invalid corrections for opaque and existential optionals in + `syntactic_sugar` rule. + [SimplyDanny](https://github.com/SimplyDanny) + [#5277](https://github.com/realm/SwiftLint/issues/5277) + * Fix false positive in `unused_import` rule that triggered on `@_exported` imports which could break downstream modules if removed. [jszumski](https://github.com/jszumski) diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift index 9bcd2f7e52..b398598357 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRule.swift @@ -300,6 +300,10 @@ private struct CorrectingContext { correctViolations(violationsBeforeComma) replaceCharacters(in: leftRange, with: "[") + case .optional where typeIsOpaqueOrExistential(correction: correction): + replaceCharacters(in: rightRange, with: ")?") + correctViolations(violation.children) + replaceCharacters(in: leftRange, with: "(") case .optional: replaceCharacters(in: rightRange, with: "?") correctViolations(violation.children) @@ -310,6 +314,14 @@ private struct CorrectingContext { corrections.append(Correction(ruleDescription: type(of: rule).description, location: location)) } + private func typeIsOpaqueOrExistential(correction: SyntacticSugarRuleViolation.Correction) -> Bool { + if let innerTypeRange = file.stringView.NSRange(start: correction.leftEnd, end: correction.rightStart) { + let innerTypeString = file.stringView.substring(with: innerTypeRange) + return innerTypeString.contains("any ") || innerTypeString.contains("some ") + } + return false + } + private mutating func replaceCharacters(in range: NSRange, with replacement: String) { contents = contents.bridge().replacingCharacters(in: range, with: replacement) } diff --git a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift index 85f73eb2be..2da01b60ca 100644 --- a/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift +++ b/Source/SwiftLintBuiltInRules/Rules/Idiomatic/SyntacticSugarRuleExamples.swift @@ -71,6 +71,8 @@ internal enum SyntacticSugarRuleExamples { Example("let x: Dictionary"): Example("let x: [Int: String]"), Example("let x: Optional"): Example("let x: Int?"), Example("let x: Optional< Int >"): Example("let x: Int?"), + Example("func f() -> Optional {}"): Example("func f() -> (any Foo)? {}"), + Example("func f() -> Optional {}"): Example("func f() -> (some Foo)? {}"), Example("let x: Dictionary"): Example("let x: [Int: String]"), Example("let x: Swift.Optional"): Example("let x: String?"),