mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
c891efc8d6
Fixes #1062
63 lines
2.7 KiB
Swift
63 lines
2.7 KiB
Swift
//
|
|
// DiscardedNotificationCenterObserverRule.swift
|
|
// SwiftLint
|
|
//
|
|
// Created by Marcelo Fabri on 01/13/17.
|
|
// Copyright © 2017 Realm. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import SourceKittenFramework
|
|
|
|
public struct DiscardedNotificationCenterObserverRule: ASTRule, ConfigurationProviderRule {
|
|
public var configuration = SeverityConfiguration(.warning)
|
|
|
|
public init() {}
|
|
|
|
public static let description = RuleDescription(
|
|
identifier: "discarded_notification_center_observer",
|
|
name: "Discarded Notification Center Observer",
|
|
description: "When registing for a notification using a block, the opaque observer that is " +
|
|
"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"
|
|
],
|
|
triggeringExamples: [
|
|
"↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil) { }\n",
|
|
"↓nc.addObserver(forName: .NSSystemTimeZoneDidChange, object: nil, queue: nil, using: { })\n"
|
|
]
|
|
)
|
|
|
|
public func validate(file: File, kind: SwiftExpressionKind,
|
|
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
|
|
return violationOffsets(in: file, dictionary: dictionary, kind: kind).map { location in
|
|
StyleViolation(ruleDescription: type(of: self).description,
|
|
severity: configuration.severity,
|
|
location: Location(file: file, byteOffset: location))
|
|
}
|
|
}
|
|
|
|
private func violationOffsets(in file: File, dictionary: [String: SourceKitRepresentable],
|
|
kind: SwiftExpressionKind) -> [Int] {
|
|
guard kind == .call,
|
|
let name = dictionary.name,
|
|
name.hasSuffix(".addObserver"),
|
|
case let arguments = dictionary.enclosedArguments,
|
|
case let argumentsNames = arguments.flatMap({ $0.name }),
|
|
argumentsNames == ["forName", "object", "queue"] ||
|
|
argumentsNames == ["forName", "object", "queue", "using"],
|
|
let offset = dictionary.offset,
|
|
let range = file.contents.bridge().byteRangeToNSRange(start: 0, length: offset) else {
|
|
return []
|
|
}
|
|
|
|
if let lastMatch = regex("\\s?=\\s*").matches(in: file.contents, options: [], range: range).last?.range,
|
|
lastMatch.location == range.length - lastMatch.length {
|
|
return []
|
|
}
|
|
|
|
return [offset]
|
|
}
|
|
}
|