From d99be668c56ea8a0c8abcb55ff32f577e22c78f2 Mon Sep 17 00:00:00 2001 From: Danny Moesch Date: Fri, 21 Jan 2022 21:43:12 +0100 Subject: [PATCH] Ignore more locations of static references not using 'Self' in classes (#3771) Static references with `Self` are not allowed to define * default values of properties, * annotation parameter values and * default method parameter values in classes. --- CHANGELOG.md | 4 ++ .../PreferSelfInStaticReferencesRule.swift | 62 ++++++++++++++----- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23582418d..100bba340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ [JP Simard](https://github.com/jpsim) [#3770](https://github.com/realm/SwiftLint/issues/3770) +* Fix false positives in the `prefer_self_in_static_references` rule. + [SimplyDanny](https://github.com/simplydanny) + [#3768](https://github.com/realm/SwiftLint/issues/3768) + * Fix the regex for expiring TODO comments. [Sergei Shirokov](https://github.com/serges147) [#3767](https://github.com/realm/SwiftLint/issues/3767) diff --git a/Source/SwiftLintFramework/Rules/Style/PreferSelfInStaticReferencesRule.swift b/Source/SwiftLintFramework/Rules/Style/PreferSelfInStaticReferencesRule.swift index 3fa09850d..e0554607a 100644 --- a/Source/SwiftLintFramework/Rules/Style/PreferSelfInStaticReferencesRule.swift +++ b/Source/SwiftLintFramework/Rules/Style/PreferSelfInStaticReferencesRule.swift @@ -10,8 +10,9 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule, nonTriggeringExamples: [ Example(""" class C { - static let i = 0, j = C.i + static private(set) var i = 0, j = C.i let h = C.i + @GreaterThan(C.j) var k: Int } """), Example(""" @@ -50,6 +51,15 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule, static let j = Self.T.R.i + Self.R.j let h = Self.T.R.i + Self.R.j } + """), + Example(""" + class C { + static let s = 2 + func f(i: Int = C.s) -> Int { + func g(@GreaterEqualThan(C.s) j: Int = C.s) -> Int { j } + return i + Self.s + } + } """) ], triggeringExamples: [ @@ -66,9 +76,13 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule, } """), Example(""" - struct S { - static func f() { ↓S.g(↓S.f) } - static func g(f: () -> Void) { f() } + class C { + struct S { + static let i = 2 + let h = ↓S.i + } + static let i = 1 + let h = C.i } """), Example(""" @@ -114,14 +128,15 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule, ) private static let nestedKindsToIgnore: Set = [ - SwiftDeclarationKind.class.rawValue, - SwiftDeclarationKind.enum.rawValue, - SwiftDeclarationKind.struct.rawValue + SwiftDeclarationKind.class, + SwiftDeclarationKind.enum, + SwiftDeclarationKind.struct ] private static let nestedKindsToIgnoreIfClass: Set = [ - SwiftDeclarationKind.varInstance.rawValue, - SwiftDeclarationKind.varStatic.rawValue + SwiftDeclarationKind.varInstance, + SwiftDeclarationKind.varStatic, + SwiftDeclarationKind.varParameter ] public var configuration = SeverityConfiguration(.warning) @@ -159,7 +174,7 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule, } var rangesToIgnore = dictionary.substructure - .filter { shallIgnore(kind: $0.kind, in: kind) } + .flatMap { getSubstructuresToIgnore(in: $0, containedIn: kind) } .compactMap(\.byteRange) .unique .sorted { $0.location < $1.location } @@ -168,6 +183,10 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule, var location = bodyRange.location return rangesToIgnore .flatMap { (range: ByteRange) -> [NSRange] in + if range.location < location { + location = max(range.upperBound, location) + return [] + } let searchRange = ByteRange(location: location, length: range.lowerBound - location) location = range.upperBound return file.match( @@ -181,14 +200,23 @@ public struct PreferSelfInStaticReferencesRule: SubstitutionCorrectableASTRule, kind == .class || kind == .struct || kind == .enum || SwiftDeclarationKind.extensionKinds.contains(kind) } - private func shallIgnore(kind: String?, in containingKind: SwiftDeclarationKind) -> Bool { - guard let kind = kind else { - return false + private func getSubstructuresToIgnore(in structure: SourceKittenDictionary, + containedIn parentKind: SwiftDeclarationKind) -> [SourceKittenDictionary] { + guard let kind = structure.kind, let declarationKind = SwiftDeclarationKind(rawValue: kind) else { + return [] } - let shallIgnore = Self.nestedKindsToIgnore.contains(kind) - if containingKind == .class || containingKind == .extensionClass { - return shallIgnore || Self.nestedKindsToIgnoreIfClass.contains(kind) + if Self.nestedKindsToIgnore.contains(declarationKind) { + return [structure] } - return shallIgnore + if parentKind != .class && parentKind != .extensionClass { + return [] + } + var structures = structure.swiftAttributes + if Self.nestedKindsToIgnoreIfClass.contains(declarationKind) { + structures.append(structure) + return structures + } + return structures + structure.substructure + .flatMap { getSubstructuresToIgnore(in: $0, containedIn: parentKind) } } }