diff --git a/CHANGELOG.md b/CHANGELOG.md index a081969dde..772043ff7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ [Jeehut](https://github.com/Jeehut) [#3312](https://github.com/realm/SwiftLint/issues/3312) +* Removed the `unneeded_notification_center_removal` rule because it was + based on an incorrect premise. + [JP Simard](https://github.com/jpsim) + [#3338](https://github.com/realm/SwiftLint/issues/3338) + #### Experimental * None. diff --git a/Source/SwiftLintFramework/Models/MasterRuleList.swift b/Source/SwiftLintFramework/Models/MasterRuleList.swift index 059c091daa..aa7dbb4be5 100644 --- a/Source/SwiftLintFramework/Models/MasterRuleList.swift +++ b/Source/SwiftLintFramework/Models/MasterRuleList.swift @@ -175,7 +175,6 @@ public let masterRuleList = RuleList(rules: [ TypeNameRule.self, UnavailableFunctionRule.self, UnneededBreakInSwitchRule.self, - UnneededNotificationCenterRemovalRule.self, UnneededParenthesesInClosureArgumentRule.self, UnownedVariableCaptureRule.self, UntypedErrorInCatchRule.self, diff --git a/Source/SwiftLintFramework/Rules/Lint/UnneededNotificationCenterRemovalRule.swift b/Source/SwiftLintFramework/Rules/Lint/UnneededNotificationCenterRemovalRule.swift deleted file mode 100644 index 6f9504d44f..0000000000 --- a/Source/SwiftLintFramework/Rules/Lint/UnneededNotificationCenterRemovalRule.swift +++ /dev/null @@ -1,108 +0,0 @@ -import SourceKittenFramework - -public struct UnneededNotificationCenterRemovalRule: ASTRule, ConfigurationProviderRule, AutomaticTestableRule { - public var configuration = SeverityConfiguration(.warning) - - public init() {} - - public static let description = RuleDescription( - identifier: "unneeded_notification_center_removal", - name: "Unneeded NotificationCenter Removal", - description: "Observers are automatically unregistered on dealloc (iOS 9 / macOS 10.11) so you should't call " + - "`removeObserver(self)` in the deinit.", - kind: .lint, - nonTriggeringExamples: [ - Example(""" - class Example { - deinit { - NotificationCenter.default.removeObserver(someOtherObserver) - } - } - """), - Example(""" - class Example { - func removeObservers() { - NotificationCenter.default.removeObserver(self) - } - } - """), - Example(""" - class Example { - deinit { - cleanup() - } - } - """) - ], - triggeringExamples: [ - Example(""" - class Foo { - deinit { - NotificationCenter.default.removeObserver(↓self) - } - } - """) - , - Example(""" - class Foo { - deinit { - NotificationCenter.default.removeObserver(↓self, - name: UITextView.textDidChangeNotification, object: nil) - } - } - """) - ] - ) - - public func validate(file: SwiftLintFile, - kind: SwiftDeclarationKind, - dictionary: SourceKittenDictionary) -> [StyleViolation] { - guard kind == .class else { return [] } - - let methodCollector = NamespaceCollector(dictionary: dictionary) - let methods = methodCollector.findAllElements(of: [.functionMethodInstance]) - let deinitMethod = methods.first(where: { $0.name == "deinit" }) - - return deinitMethod?.dictionary.substructure.compactMap { subDict -> StyleViolation? in - guard subDict.expressionKind == .call else { return nil } - - return violationRange(in: file, dictionary: subDict).map { - StyleViolation(ruleDescription: Self.description, - severity: configuration.severity, - location: Location(file: file, byteOffset: $0.location)) - } - } ?? [] - } - - private func violationRange(in file: SwiftLintFile, dictionary: SourceKittenDictionary) -> ByteRange? { - guard - dictionary.name == "NotificationCenter.default.removeObserver", - let observerRange = firstArgumentBody(in: dictionary), - let observerName = file.stringView.substringWithByteRange(observerRange), - observerName == "self" - else { return nil } - - return observerRange - } - - /// observer parameter range - private func firstArgumentBody(in dictionary: SourceKittenDictionary) -> ByteRange? { - if dictionary.enclosedArguments.names == [nil, "name", "object"], - let bodyOffset = dictionary.enclosedArguments.first?.bodyOffset, - let bodyLength = dictionary.enclosedArguments.first?.bodyLength { - return ByteRange(location: bodyOffset, length: bodyLength) - } else if dictionary.enclosedArguments.isEmpty, - let bodyOffset = dictionary.bodyOffset, - let bodyLength = dictionary.bodyLength { - return ByteRange(location: bodyOffset, length: bodyLength) - } else { - return nil - } - } -} - -private extension Array where Element == SourceKittenDictionary { - var names: [String?] { - return map { $0.name } - } -} diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj index 2996c39f26..00df0d14df 100644 --- a/SwiftLint.xcodeproj/project.pbxproj +++ b/SwiftLint.xcodeproj/project.pbxproj @@ -141,9 +141,9 @@ 67EB4DFA1E4CC111004E9ACD /* CyclomaticComplexityConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB4DF81E4CC101004E9ACD /* CyclomaticComplexityConfiguration.swift */; }; 67EB4DFC1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB4DFB1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift */; }; 69F88BF71BDA38A6005E7CAE /* OpeningBraceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692B1EB11BD7E00F00EAABFF /* OpeningBraceRule.swift */; }; + 6A14DB9323E7296700C17847 /* OpeningBraceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A14DB9123E7292000C17847 /* OpeningBraceConfiguration.swift */; }; 6A804EF323D8F6CF00976471 /* EmptyCountConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A804EF023D8F6A200976471 /* EmptyCountConfiguration.swift */; }; 6A804EF623D8FB0D00976471 /* EmptyCountRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A804EF423D8FA7900976471 /* EmptyCountRuleTests.swift */; }; - 6A14DB9323E7296700C17847 /* OpeningBraceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A14DB9123E7292000C17847 /* OpeningBraceConfiguration.swift */; }; 6A84A3ED23E79420004ECB7F /* OpeningBraceRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A14DB9423E75ACF00C17847 /* OpeningBraceRuleTests.swift */; }; 6BE79EB12204EC0700B5A2FE /* RequiredDeinitRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE79EB02204EC0700B5A2FE /* RequiredDeinitRule.swift */; }; 6C15818D237026AC00F582A2 /* GitHubActionsLoggingReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C15818C237026AC00F582A2 /* GitHubActionsLoggingReporter.swift */; }; @@ -334,7 +334,6 @@ D47079AB1DFDCF7A00027086 /* SwiftExpressionKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47079AA1DFDCF7A00027086 /* SwiftExpressionKind.swift */; }; D47079AD1DFE2FA700027086 /* EmptyParametersRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47079AC1DFE2FA700027086 /* EmptyParametersRule.swift */; }; D47079AF1DFE520000027086 /* VoidReturnRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47079AE1DFE520000027086 /* VoidReturnRule.swift */; }; - D47421F424E14760009AE788 /* UnneededNotificationCenterRemovalRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47421F324E14760009AE788 /* UnneededNotificationCenterRemovalRule.swift */; }; D47A510E1DB29EEB00A4CC21 /* SwitchCaseOnNewlineRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47A510D1DB29EEB00A4CC21 /* SwitchCaseOnNewlineRule.swift */; }; D47A51101DB2DD4800A4CC21 /* AttributesRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47A510F1DB2DD4800A4CC21 /* AttributesRule.swift */; }; D47EF4801F69E3100012C4CA /* ColonRule+FunctionCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47EF47F1F69E3100012C4CA /* ColonRule+FunctionCall.swift */; }; @@ -676,10 +675,10 @@ 692B1EB11BD7E00F00EAABFF /* OpeningBraceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpeningBraceRule.swift; sourceTree = ""; }; 692B60AB1BD8F2E700C7AA22 /* StatementPositionRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatementPositionRule.swift; sourceTree = ""; }; 695BE9CE1BDFD92B0071E985 /* CommaRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommaRule.swift; sourceTree = ""; }; - 6A804EF023D8F6A200976471 /* EmptyCountConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyCountConfiguration.swift; sourceTree = ""; }; - 6A804EF423D8FA7900976471 /* EmptyCountRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyCountRuleTests.swift; sourceTree = ""; }; 6A14DB9123E7292000C17847 /* OpeningBraceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpeningBraceConfiguration.swift; sourceTree = ""; }; 6A14DB9423E75ACF00C17847 /* OpeningBraceRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpeningBraceRuleTests.swift; sourceTree = ""; }; + 6A804EF023D8F6A200976471 /* EmptyCountConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyCountConfiguration.swift; sourceTree = ""; }; + 6A804EF423D8FA7900976471 /* EmptyCountRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyCountRuleTests.swift; sourceTree = ""; }; 6BE79EB02204EC0700B5A2FE /* RequiredDeinitRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredDeinitRule.swift; sourceTree = ""; }; 6C15818C237026AC00F582A2 /* GitHubActionsLoggingReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GitHubActionsLoggingReporter.swift; sourceTree = ""; }; 6C15818E23702DCE00F582A2 /* CannedGitHubActionsLoggingReporterOutput.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CannedGitHubActionsLoggingReporterOutput.txt; sourceTree = ""; }; @@ -884,7 +883,6 @@ D47079AA1DFDCF7A00027086 /* SwiftExpressionKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftExpressionKind.swift; sourceTree = ""; }; D47079AC1DFE2FA700027086 /* EmptyParametersRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyParametersRule.swift; sourceTree = ""; }; D47079AE1DFE520000027086 /* VoidReturnRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VoidReturnRule.swift; sourceTree = ""; }; - D47421F324E14760009AE788 /* UnneededNotificationCenterRemovalRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnneededNotificationCenterRemovalRule.swift; sourceTree = ""; }; D47A510D1DB29EEB00A4CC21 /* SwitchCaseOnNewlineRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchCaseOnNewlineRule.swift; sourceTree = ""; }; D47A510F1DB2DD4800A4CC21 /* AttributesRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributesRule.swift; sourceTree = ""; }; D47EF47F1F69E3100012C4CA /* ColonRule+FunctionCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ColonRule+FunctionCall.swift"; sourceTree = ""; }; @@ -1261,7 +1259,6 @@ C225E844252E8B1B00EDE3E7 /* TestCaseAccessibilityRule.swift */, C225E845252E8B1E00EDE3E7 /* TestCaseAccessibilityRuleExamples.swift */, E88DEA811B0990A700A66CB0 /* TodoRule.swift */, - D47421F324E14760009AE788 /* UnneededNotificationCenterRemovalRule.swift */, 7565E5F02262BA0900B0597C /* UnusedCaptureListRule.swift */, D40AD0891E032F9700F48C30 /* UnusedClosureParameterRule.swift */, D4D7320C21E15ED4001C07D9 /* UnusedControlFlowLabelRule.swift */, @@ -2223,7 +2220,6 @@ D4B022981E102EE8007E5297 /* ObjectLiteralRule.swift in Sources */, 2E336D1B1DF08BFB00CCFE77 /* EmojiReporter.swift in Sources */, E8EA41171C2D1DBE004F9930 /* CheckstyleReporter.swift in Sources */, - D47421F424E14760009AE788 /* UnneededNotificationCenterRemovalRule.swift in Sources */, 006ECFC41C44E99E00EF6364 /* LegacyConstantRule.swift in Sources */, 82FE254120F604CB00295958 /* VerticalWhitespaceClosingBracesRule.swift in Sources */, 429644B61FB0A9B400D75128 /* SortedFirstLastRule.swift in Sources */, diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index d6b3b5c691..c109cd8ad2 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -191,12 +191,6 @@ extension ConfigurationTests { ("testForceExcludesDirectoryThatIsNotInExcludedButHasChildrenThatAre", testForceExcludesDirectoryThatIsNotInExcludedButHasChildrenThatAre), ("testLintablePaths", testLintablePaths), ("testGlobExcludePaths", testGlobExcludePaths), - ("testExcludeByPrefixExcludedPaths", testExcludeByPrefixExcludedPaths), - ("testExcludeByPrefixForceExcludesFile", testExcludeByPrefixForceExcludesFile), - ("testExcludeByPrefixForceExcludesFileNotPresentInExcluded", testExcludeByPrefixForceExcludesFileNotPresentInExcluded), - ("testExcludeByPrefixForceExcludesDirectory", testExcludeByPrefixForceExcludesDirectory), - ("testExcludeByPrefixForceExcludesDirectoryThatIsNotInExcludedButHasChildrenThatAre", testExcludeByPrefixForceExcludesDirectoryThatIsNotInExcludedButHasChildrenThatAre), - ("testExcludeByPrefixGlobExcludePaths", testExcludeByPrefixGlobExcludePaths), ("testIsEqualTo", testIsEqualTo), ("testIsNotEqualTo", testIsNotEqualTo), ("testCustomConfiguration", testCustomConfiguration), @@ -208,6 +202,12 @@ extension ConfigurationTests { ("testConfiguresCorrectlyFromDict", testConfiguresCorrectlyFromDict), ("testConfigureFallsBackCorrectly", testConfigureFallsBackCorrectly), ("testAllowZeroLintableFiles", testAllowZeroLintableFiles), + ("testExcludeByPrefixExcludedPaths", testExcludeByPrefixExcludedPaths), + ("testExcludeByPrefixForceExcludesFile", testExcludeByPrefixForceExcludesFile), + ("testExcludeByPrefixForceExcludesFileNotPresentInExcluded", testExcludeByPrefixForceExcludesFileNotPresentInExcluded), + ("testExcludeByPrefixForceExcludesDirectory", testExcludeByPrefixForceExcludesDirectory), + ("testExcludeByPrefixForceExcludesDirectoryThatIsNotInExcludedButHasChildrenThatAre", testExcludeByPrefixForceExcludesDirectoryThatIsNotInExcludedButHasChildrenThatAre), + ("testExcludeByPrefixGlobExcludePaths", testExcludeByPrefixGlobExcludePaths), ("testMerge", testMerge), ("testLevel0", testLevel0), ("testLevel1", testLevel1), @@ -1547,12 +1547,6 @@ extension UnneededBreakInSwitchRuleTests { ] } -extension UnneededNotificationCenterRemovalRuleTests { - static var allTests: [(String, (UnneededNotificationCenterRemovalRuleTests) -> () throws -> Void)] = [ - ("testWithDefaultConfiguration", testWithDefaultConfiguration) - ] -} - extension UnneededParenthesesInClosureArgumentRuleTests { static var allTests: [(String, (UnneededParenthesesInClosureArgumentRuleTests) -> () throws -> Void)] = [ ("testWithDefaultConfiguration", testWithDefaultConfiguration) @@ -1926,7 +1920,6 @@ XCTMain([ testCase(TypeNameRuleTests.allTests), testCase(UnavailableFunctionRuleTests.allTests), testCase(UnneededBreakInSwitchRuleTests.allTests), - testCase(UnneededNotificationCenterRemovalRuleTests.allTests), testCase(UnneededParenthesesInClosureArgumentRuleTests.allTests), testCase(UnownedVariableCaptureRuleTests.allTests), testCase(UntypedErrorInCatchRuleTests.allTests), diff --git a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift index af41a21d2c..e910d05443 100644 --- a/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift +++ b/Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift @@ -738,12 +738,6 @@ class UnneededBreakInSwitchRuleTests: XCTestCase { } } -class UnneededNotificationCenterRemovalRuleTests: XCTestCase { - func testWithDefaultConfiguration() { - verifyRule(UnneededNotificationCenterRemovalRule.description) - } -} - class UnneededParenthesesInClosureArgumentRuleTests: XCTestCase { func testWithDefaultConfiguration() { verifyRule(UnneededParenthesesInClosureArgumentRule.description)