diff --git a/CHANGELOG.md b/CHANGELOG.md index cd7bc839d8..ec3b6b4019 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ [Marcelo Fabri](https://github.com/marcelofabri) [#1156](https://github.com/realm/SwiftLint/issues/1156) +* Fix false positive on `redundant_optional_initialization` rule. + [Marcelo Fabri](https://github.com/marcelofabri) + [#1159](https://github.com/realm/SwiftLint/issues/1159) + ## 0.16.0: Maximum Energy Efficiency Setting ##### Breaking diff --git a/Source/SwiftLintFramework/Rules/RedundantOptionalInitializationRule.swift b/Source/SwiftLintFramework/Rules/RedundantOptionalInitializationRule.swift index 6f8ee3487f..336e12b46e 100644 --- a/Source/SwiftLintFramework/Rules/RedundantOptionalInitializationRule.swift +++ b/Source/SwiftLintFramework/Rules/RedundantOptionalInitializationRule.swift @@ -26,7 +26,17 @@ public struct RedundantOptionalInitializationRule: ASTRule, CorrectableRule, Con "func foo(bar: Int? = 0) { }\n", "var myVar: Optional\n", "let myVar: Optional = nil\n", - "var myVar: Optional = 0\n" + "var myVar: Optional = 0\n", + // properties with body should be ignored + "var foo: Int? {\n" + + " if bar != nil { }\n" + + " return 0\n" + + "}\n", + // properties with a closure call + "var foo: Int? = {\n" + + " if bar != nil { }\n" + + " return 0\n" + + "}()\n" ], triggeringExamples: [ "var myVar: Int?↓ = nil\n", @@ -59,17 +69,29 @@ public struct RedundantOptionalInitializationRule: ASTRule, CorrectableRule, Con dictionary["key.setter_accessibility"] != nil, let type = dictionary["key.typename"] as? String, typeIsOptional(type), - case let contents = file.contents.bridge(), - let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }), - let length = (dictionary["key.length"] as? Int64).flatMap({ Int($0) }), - let range = contents.byteRangeToNSRange(start: offset, length: length), - let match = file.match(pattern: pattern, with: [.keyword], range: range).first else { + let range = range(for: dictionary, file: file), + let match = file.match(pattern: pattern, with: [.keyword], range: range).first, + match.location == range.location + range.length - match.length else { return [] } return [match] } + private func range(for dictionary: [String: SourceKitRepresentable], file: File) -> NSRange? { + guard let offset = (dictionary["key.offset"] as? Int64).flatMap({ Int($0) }), + let length = (dictionary["key.length"] as? Int64).flatMap({ Int($0) }) else { + return nil + } + + let contents = file.contents.bridge() + if let bodyOffset = (dictionary["key.bodyoffset"] as? Int64).flatMap({ Int($0) }) { + return contents.byteRangeToNSRange(start: offset, length: bodyOffset - offset) + } else { + return contents.byteRangeToNSRange(start: offset, length: length) + } + } + private func violationRanges(in file: File, dictionary: [String: SourceKitRepresentable]) -> [NSRange] { return dictionary.substructure.flatMap { subDict -> [NSRange] in guard let kindString = subDict["key.kind"] as? String,