Merge pull request #1581 from marcelofabri/fix-1525

Don't trigger `discarded_notification_center_observer` when the observer is returned
This commit is contained in:
Marcelo Fabri
2017-06-02 21:06:37 +02:00
committed by GitHub
2 changed files with 43 additions and 2 deletions
+6
View File
@@ -27,6 +27,12 @@
[Marcelo Fabri](https://github.com/marcelofabri)
[#1532](https://github.com/realm/SwiftLint/issues/1532)
* Don't trigger violations from `discarded_notification_center_observer` rule
when the observer is being returned from a function that is not marked
as `@discardableResult`.
[Marcelo Fabri](https://github.com/marcelofabri)
[#1525](https://github.com/realm/SwiftLint/issues/1525)
##### Bug Fixes
* None.
@@ -21,11 +21,17 @@ public struct DiscardedNotificationCenterObserverRule: ASTRule, ConfigurationPro
"returned should be stored so it can be removed later.",
nonTriggeringExamples: [
"let foo = nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil) { }\n",
"let foo = nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })\n"
"let foo = nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })\n",
"func foo() -> Any {\n" +
" return nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })\n" +
"}\n"
],
triggeringExamples: [
"↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil) { }\n",
"↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })\n"
"↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })\n",
"@discardableResult func foo() -> Any {\n" +
" return ↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })\n" +
"}\n"
]
)
@@ -57,6 +63,35 @@ public struct DiscardedNotificationCenterObserverRule: ASTRule, ConfigurationPro
return []
}
if let lastMatch = file.match(pattern: "\\breturn\\s+", with: [.keyword], range: range).last,
lastMatch.location == range.length - lastMatch.length,
let lastFunction = file.structure.functions(forByteOffset: offset).last,
!lastFunction.enclosedSwiftAttributes.contains("source.decl.attribute.discardableResult") {
return []
}
return [offset]
}
}
private extension Structure {
func functions(forByteOffset byteOffset: Int) -> [[String: SourceKitRepresentable]] {
var results = [[String: SourceKitRepresentable]]()
func parse(_ dictionary: [String: SourceKitRepresentable]) {
guard let offset = dictionary.offset,
let byteRange = dictionary.length.map({ NSRange(location: offset, length: $0) }),
NSLocationInRange(byteOffset, byteRange) else {
return
}
if let kind = dictionary.kind.flatMap(SwiftDeclarationKind.init),
SwiftDeclarationKind.functionKinds().contains(kind) {
results.append(dictionary)
}
dictionary.substructure.forEach(parse)
}
parse(dictionary)
return results
}
}