diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f08b598557..960fddb7f3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,10 @@ [Artem Garmash](https://github.com/agarmash) [#3651](https://github.com/realm/SwiftLint/issues/3651) +* Handle `get async` and `get throws` in the `implicit_getter` rule. + [Marcelo Fabri](https://github.com/marcelofabri) + [#3684](https://github.com/realm/SwiftLint/issues/3684) + #### Bug Fixes * Fixes a bug with the `missing_docs` rule where `excludes_inherited_types` would not be set. diff --git a/Source/SwiftLintFramework/Models/SwiftVersion.swift b/Source/SwiftLintFramework/Models/SwiftVersion.swift index cce7b0a027e..f4cadf31af8 100644 --- a/Source/SwiftLintFramework/Models/SwiftVersion.swift +++ b/Source/SwiftLintFramework/Models/SwiftVersion.swift @@ -35,6 +35,8 @@ public extension SwiftVersion { static let fiveDotThree = SwiftVersion(rawValue: "5.3.0") /// Swift 5.4.x - https://swift.org/download/#swift-54 static let fiveDotFour = SwiftVersion(rawValue: "5.4.0") + /// Swift 5.5.x - https://swift.org/download/#swift-55 + static let fiveDotFive = SwiftVersion(rawValue: "5.5.0") /// The current detected Swift compiler version, based on the currently accessible SourceKit version. /// diff --git a/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift b/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift index 16097fb971a..11f0815de28 100644 --- a/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRule.swift @@ -31,7 +31,7 @@ public struct ImplicitGetterRule: ConfigurationProviderRule, AutomaticTestableRu return nil } } else { - guard let range = dict.byteRange.map(file.stringView.byteRangeToNSRange) else { + guard let range = dict.byteRange.flatMap(file.stringView.byteRangeToNSRange) else { return nil } @@ -51,6 +51,22 @@ public struct ImplicitGetterRule: ConfigurationProviderRule, AutomaticTestableRu } } + // If there's another keyword after `get`, it's allowed (e.g. `get async`) + if SwiftVersion.current >= .fiveDotFive { + guard let byteRange = dict.byteRange else { + return nil + } + + let nextToken = file.syntaxMap.tokens(inByteRange: byteRange) + .first { $0.offset > token.offset } + + let allowedKeywords: Set = ["throws", "async"] + if let nextToken = nextToken, + allowedKeywords.contains(file.contents(for: nextToken) ?? "") { + return nil + } + } + let kind = dict.declarationKind return (token.offset, kind) } diff --git a/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRuleExamples.swift b/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRuleExamples.swift index 7bfd31e4a86..a41f3cd5bf4 100644 --- a/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRuleExamples.swift +++ b/Source/SwiftLintFramework/Rules/Style/ImplicitGetterRuleExamples.swift @@ -138,14 +138,7 @@ struct ImplicitGetterRuleExamples { } } } - """) - ] - - guard SwiftVersion.current >= .fourDotOne else { - return commonExamples - } - - return commonExamples + [ + """), Example(""" class Foo { subscript(i: Int) -> Int { @@ -172,6 +165,36 @@ struct ImplicitGetterRuleExamples { } """) ] + + guard SwiftVersion.current >= .fiveDotFive else { + return commonExamples + } + + return commonExamples + [ + Example(""" + class DatabaseEntity { + var isSynced: Bool { + get async { + await database.isEntitySynced(self) + } + } + } + """), + Example(""" + struct Test { + subscript(value: Int) -> Int { + get throws { + if value == 0 { + throw NSError() + } else { + return value + } + } + } + } + """) + ] + } static var triggeringExamples: [Example] {