diff --git a/CHANGELOG.md b/CHANGELOG.md index 15ff3eccb3..0d94aa14bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ #### Breaking -* None. +* Remove the `weak_computed_property` rule. Please see linked issue for + discussion and rationale. + [JP Simard](https://github.com/jpsim) + [#2712](https://github.com/realm/SwiftLint/issues/2712) #### Experimental @@ -10,9 +13,8 @@ #### Enhancements - * Add `" - "` delimiter to allow commenting SwiftLint commands without triggering -`superfluous_disable_command`. + `superfluous_disable_command`. [Kevin Randrup](https://github.com/kevinrandrup) * Make `testSimulateHomebrewTest()` test opt-in because it may fail on unknown diff --git a/Rules.md b/Rules.md index 763e5ab4c4..89da53ffd8 100644 --- a/Rules.md +++ b/Rules.md @@ -172,7 +172,6 @@ * [Vertical Whitespace before Closing Braces](#vertical-whitespace-before-closing-braces) * [Vertical Whitespace after Opening Braces](#vertical-whitespace-after-opening-braces) * [Void Return](#void-return) -* [Weak Computed Property](#weak-computed-property) * [Weak Delegate](#weak-delegate) * [XCTest Specific Matcher](#xctest-specific-matcher) * [XCTFail Message](#xctfail-message) @@ -24890,76 +24889,6 @@ let foo: (ConfigurationTests) -> () throws -> ↓()) -## Weak Computed Property - -Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version ---- | --- | --- | --- | --- | --- -`weak_computed_property` | Enabled | Yes | lint | No | 4.1.0 - -Adding weak to a computed property has no effect. - -### Examples - -
-Non Triggering Examples - -```swift -class Foo { - weak var delegate: SomeProtocol? -} -``` - -```swift -class Foo { - var delegate: SomeProtocol? -} -``` - -```swift -class Foo { - weak var delegate: SomeProtocol? { - didSet { - update(with: delegate) - } - } -} -``` - -```swift -class Foo { - weak var delegate: SomeProtocol? { - willSet { - update(with: delegate) - } - } -} -``` - -
-
-Triggering Examples - -```swift -class Foo { - weak var delegate: SomeProtocol? { return bar() } -} -``` - -```swift -class Foo { - private weak var _delegate: SomeProtocol? - - ↓weak var delegate: SomeProtocol? { - get { return _delegate } - set { _delegate = newValue } - } -} -``` - -
- - - ## Weak Delegate Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version diff --git a/Source/SwiftLintFramework/Models/MasterRuleList.swift b/Source/SwiftLintFramework/Models/MasterRuleList.swift index 102cce0ecb..599018746a 100644 --- a/Source/SwiftLintFramework/Models/MasterRuleList.swift +++ b/Source/SwiftLintFramework/Models/MasterRuleList.swift @@ -173,7 +173,6 @@ public let masterRuleList = RuleList(rules: [ VerticalWhitespaceOpeningBracesRule.self, VerticalWhitespaceRule.self, VoidReturnRule.self, - WeakComputedProperyRule.self, WeakDelegateRule.self, XCTFailMessageRule.self, XCTSpecificMatcherRule.self, diff --git a/Source/SwiftLintFramework/Rules/Lint/WeakComputedProperyRule.swift b/Source/SwiftLintFramework/Rules/Lint/WeakComputedProperyRule.swift deleted file mode 100644 index 0690364df7..0000000000 --- a/Source/SwiftLintFramework/Rules/Lint/WeakComputedProperyRule.swift +++ /dev/null @@ -1,189 +0,0 @@ -import Foundation -import SourceKittenFramework - -public struct WeakComputedProperyRule: SubstitutionCorrectableASTRule, ConfigurationProviderRule, - AutomaticTestableRule { - public var configuration = SeverityConfiguration(.warning) - - public init() {} - - public static let description = RuleDescription( - identifier: "weak_computed_property", - name: "Weak Computed Property", - description: "Adding weak to a computed property has no effect.", - kind: .lint, - minSwiftVersion: .fourDotOne, - nonTriggeringExamples: [ - " weak var delegate: SomeProtocol?", - " var delegate: SomeProtocol?", - """ - weak var delegate: SomeProtocol? { - didSet { - update(with: delegate) - } - } - """, - """ - weak var delegate: SomeProtocol? { - willSet { - update(with: delegate) - } - } - """ - ].map(wrapExample), - triggeringExamples: [ - " weak var delegate: SomeProtocol? { return bar() }", - """ - private weak var _delegate: SomeProtocol? - - ↓weak var delegate: SomeProtocol? { - get { return _delegate } - set { _delegate = newValue } - } - """ - ].map(wrapExample), - corrections: [ - wrapExample(" ↓weak var delegate: SomeProtocol? { return bar() }"): - wrapExample(" var delegate: SomeProtocol? { return bar() }"), - wrapExample(""" - private weak var _delegate: SomeProtocol? - - ↓weak var delegate: SomeProtocol? { - get { return _delegate } - set { _delegate = newValue } - } - """): - wrapExample(""" - private weak var _delegate: SomeProtocol? - - var delegate: SomeProtocol? { - get { return _delegate } - set { _delegate = newValue } - } - """) - ] - ) - - // MARK: - ASTRule - - public func validate(file: File, - kind: SwiftDeclarationKind, - dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] { - return violationRanges(in: file, kind: kind, dictionary: dictionary).map { - StyleViolation(ruleDescription: type(of: self).description, - severity: configuration.severity, - location: Location(file: file, characterOffset: $0.location)) - } - } - - // MARK: - SubstitutionCorrectableASTRule - - public func substitution(for violationRange: NSRange, in file: File) -> (NSRange, String) { - var rangeToRemove = violationRange - let contentsNSString = file.contents.bridge() - if let byteRange = contentsNSString.NSRangeToByteRange(start: violationRange.location, - length: violationRange.length), - let nextToken = file.syntaxMap.tokens.first(where: { $0.offset > byteRange.location }), - let nextTokenLocation = contentsNSString.byteRangeToNSRange(start: nextToken.offset, length: 0) { - rangeToRemove.length = nextTokenLocation.location - violationRange.location - } - - return (rangeToRemove, "") - } - - public func violationRanges(in file: File, - kind: SwiftDeclarationKind, - dictionary: [String: SourceKitRepresentable]) -> [NSRange] { - guard allowedKinds.contains(kind), - let bodyOffset = dictionary.bodyOffset, - let bodyLength = dictionary.bodyLength, bodyLength > 0, - let weakAttribute = dictionary.swiftAttributes.first(where: { $0.isWeakAttribute }), - let attributeOffset = weakAttribute.offset, - let attributeLength = weakAttribute.length, attributeLength > 0, - case let contents = file.contents.bridge(), - let attributeRange = contents.byteRangeToNSRange(start: attributeOffset, length: attributeLength), - let bodyRange = contents.byteRangeToNSRange(start: bodyOffset, length: bodyLength), - !containsObserverToken(in: bodyRange, file: file, propertyStructure: dictionary) else { - return [] - } - - return [attributeRange] - } - - // MARK: - Private - - private let allowedKinds = SwiftDeclarationKind.variableKinds.subtracting([.varParameter]) - - private func containsObserverToken(in range: NSRange, file: File, - propertyStructure: [String: SourceKitRepresentable]) -> Bool { - let tokens = file.rangesAndTokens(matching: "\\b(?:didSet|willSet)\\b", range: range).keywordTokens() - return tokens.contains(where: { token -> Bool in - // the last element is the deepest structure - guard let dict = declarations(forByteOffset: token.offset, structure: file.structure).last, - propertyStructure.isEqualTo(dict) else { - return false - } - - return true - }) - } - - private func declarations(forByteOffset byteOffset: Int, - structure: Structure) -> [[String: SourceKitRepresentable]] { - var results = [[String: SourceKitRepresentable]]() - - func parse(dictionary: [String: SourceKitRepresentable], parentKind: SwiftDeclarationKind?) { - // Only accepts declarations which contains a body and contains the - // searched byteOffset - guard let kindString = dictionary.kind, - let kind = SwiftDeclarationKind(rawValue: kindString), - let bodyOffset = dictionary.bodyOffset, - let bodyLength = dictionary.bodyLength, - case let byteRange = NSRange(location: bodyOffset, length: bodyLength), - NSLocationInRange(byteOffset, byteRange) else { - return - } - - if parentKind != .protocol && allowedKinds.contains(kind) { - results.append(dictionary) - } - - for dictionary in dictionary.substructure { - parse(dictionary: dictionary, parentKind: kind) - } - } - - for dictionary in structure.dictionary.substructure { - parse(dictionary: dictionary, parentKind: nil) - } - - return results - } -} - -private extension Dictionary where Key == String, Value == SourceKitRepresentable { - var isWeakAttribute: Bool { - return attribute.flatMap(SwiftDeclarationAttributeKind.init) == .weak - } -} - -private extension Array where Element == (NSRange, [SyntaxToken]) { - func keywordTokens() -> [SyntaxToken] { - return compactMap { _, tokens in - guard let token = tokens.last, - SyntaxKind(rawValue: token.type) == .keyword else { - return nil - } - - return token - } - } -} - -private func wrapExample(_ text: String) -> String { - return """ - class Foo { - \(text) - } - """ -} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index f62957d6ef..808f0d024e 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -248,7 +248,6 @@ D41985EB21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985EA21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift */; }; D41985ED21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985EC21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift */; }; D41985EF21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985EE21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift */; }; - D41985F121FC5AF7003BE2B7 /* WeakComputedProperyRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985F021FC5AF7003BE2B7 /* WeakComputedProperyRule.swift */; }; D41B57781ED8CEE0007B0470 /* ExtensionAccessModifierRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41B57771ED8CEE0007B0470 /* ExtensionAccessModifierRule.swift */; }; D41E7E0B1DF9DABB0065259A /* RedundantStringEnumValueRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41E7E0A1DF9DABB0065259A /* RedundantStringEnumValueRule.swift */; }; D4246D6D1F30D8620097E658 /* PrivateOverFilePrivateRuleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4246D6C1F30D8620097E658 /* PrivateOverFilePrivateRuleConfiguration.swift */; }; @@ -734,7 +733,6 @@ D41985EA21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeploymentTargetConfiguration.swift; sourceTree = ""; }; D41985EC21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeploymentTargetConfigurationTests.swift; sourceTree = ""; }; D41985EE21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeploymentTargetRuleTests.swift; sourceTree = ""; }; - D41985F021FC5AF7003BE2B7 /* WeakComputedProperyRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakComputedProperyRule.swift; sourceTree = ""; }; D41B57771ED8CEE0007B0470 /* ExtensionAccessModifierRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionAccessModifierRule.swift; sourceTree = ""; }; D41E7E0A1DF9DABB0065259A /* RedundantStringEnumValueRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedundantStringEnumValueRule.swift; sourceTree = ""; }; D4246D6C1F30D8620097E658 /* PrivateOverFilePrivateRuleConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateOverFilePrivateRuleConfiguration.swift; sourceTree = ""; }; @@ -1119,7 +1117,6 @@ 8F6B3153213CDCD100858E44 /* UnusedPrivateDeclarationRule.swift */, D4B3409C21F16B110038C79A /* UnusedSetterValueRule.swift */, D442541E1DB87C3D00492EA4 /* ValidIBInspectableRule.swift */, - D41985F021FC5AF7003BE2B7 /* WeakComputedProperyRule.swift */, 094384FF1D5D2382009168CF /* WeakDelegateRule.swift */, 1872906F1FC37A9B0016BEA2 /* YodaConditionRule.swift */, ); @@ -2106,7 +2103,6 @@ D4130D971E16183F00242361 /* IdentifierNameRuleExamples.swift in Sources */, 7250948A1D0859260039B353 /* StatementModeConfiguration.swift in Sources */, E81619531BFC162C00946723 /* QueuedPrint.swift in Sources */, - D41985F121FC5AF7003BE2B7 /* WeakComputedProperyRule.swift in Sources */, E87E4A051BFB927C00FCFE46 /* TrailingSemicolonRule.swift in Sources */, D4B472411F66486300BD6EF1 /* FallthroughRule.swift in Sources */, B25DCD0B1F7E9F9E0028A199 /* MultilineArgumentsRuleExamples.swift in Sources */, diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 29c77911ca..31d263d4bd 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -103,6 +103,7 @@ extension CommandTests { ("testEnablePrevious", testEnablePrevious), ("testEnableThis", testEnableThis), ("testEnableNext", testEnableNext), + ("testTrailingCOmment", testTrailingCOmment), ("testActionInverse", testActionInverse), ("testNoModifierCommandExpandsToItself", testNoModifierCommandExpandsToItself), ("testExpandPreviousCommand", testExpandPreviousCommand), @@ -110,6 +111,7 @@ extension CommandTests { ("testExpandNextCommand", testExpandNextCommand), ("testSuperfluousDisableCommands", testSuperfluousDisableCommands), ("testDisableAllOverridesSuperfluousDisableCommand", testDisableAllOverridesSuperfluousDisableCommand), + ("testSuperfluousDisableCommandsIgnoreDelimiter", testSuperfluousDisableCommandsIgnoreDelimiter), ("testInvalidDisableCommands", testInvalidDisableCommands), ("testSuperfluousDisableCommandsDisabled", testSuperfluousDisableCommandsDisabled), ("testSuperfluousDisableCommandsDisabledOnConfiguration", testSuperfluousDisableCommandsDisabledOnConfiguration) @@ -1454,12 +1456,6 @@ extension VoidReturnRuleTests { ] } -extension WeakComputedProperyRuleTests { - static var allTests: [(String, (WeakComputedProperyRuleTests) -> () throws -> Void)] = [ - ("testWithDefaultConfiguration", testWithDefaultConfiguration) - ] -} - extension WeakDelegateRuleTests { static var allTests: [(String, (WeakDelegateRuleTests) -> () throws -> Void)] = [ ("testWithDefaultConfiguration", testWithDefaultConfiguration) @@ -1707,7 +1703,6 @@ XCTMain([ testCase(VerticalWhitespaceOpeningBracesRuleTests.allTests), testCase(VerticalWhitespaceRuleTests.allTests), testCase(VoidReturnRuleTests.allTests), - testCase(WeakComputedProperyRuleTests.allTests), testCase(WeakDelegateRuleTests.allTests), testCase(XCTFailMessageRuleTests.allTests), testCase(XCTSpecificMatcherRuleTests.allTests), diff --git a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift index adb224e013..d7dfa476e3 100644 --- a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift +++ b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift @@ -768,12 +768,6 @@ class VoidReturnRuleTests: XCTestCase { } } -class WeakComputedProperyRuleTests: XCTestCase { - func testWithDefaultConfiguration() { - verifyRule(WeakComputedProperyRule.description) - } -} - class WeakDelegateRuleTests: XCTestCase { func testWithDefaultConfiguration() { verifyRule(WeakDelegateRule.description)