mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
113 lines
4.4 KiB
Swift
113 lines
4.4 KiB
Swift
//
|
|
// ObjectLiteralRule.swift
|
|
// SwiftLint
|
|
//
|
|
// Created by Marcelo Fabri on 12/25/16.
|
|
// Copyright © 2016 Realm. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import SourceKittenFramework
|
|
|
|
public struct ObjectLiteralRule: ASTRule, ConfigurationProviderRule, OptInRule {
|
|
|
|
public var configuration = SeverityConfiguration(.warning)
|
|
|
|
public init() {}
|
|
|
|
public static let description = RuleDescription(
|
|
identifier: "object_literal",
|
|
name: "Object Literal",
|
|
description: "Prefer object literals over image and color inits.",
|
|
nonTriggeringExamples: [
|
|
"let image = #imageLiteral(resourceName: \"image.jpg\")",
|
|
"let color = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)",
|
|
"let image = UIImage(named: aVariable)",
|
|
"let image = UIImage(named: \"interpolated \\(variable)\")",
|
|
"let color = UIColor(red: value, green: value, blue: value, alpha: 1)",
|
|
"let image = NSImage(named: aVariable)",
|
|
"let image = NSImage(named: \"interpolated \\(variable)\")",
|
|
"let color = NSColor(red: value, green: value, blue: value, alpha: 1)"
|
|
],
|
|
triggeringExamples: ["", ".init"].flatMap { (method: String) -> [String] in
|
|
["UI", "NS"].flatMap { (prefix: String) -> [String] in
|
|
[
|
|
"let image = ↓\(prefix)Image\(method)(named: \"foo\")",
|
|
"let color = ↓\(prefix)Color\(method)(red: 0.3, green: 0.3, blue: 0.3, alpha: 1)",
|
|
"let color = ↓\(prefix)Color\(method)(red: 100 / 255.0, green: 50 / 255.0, blue: 0, alpha: 1)",
|
|
"let color = ↓\(prefix)Color\(method)(white: 0.5, alpha: 1)"
|
|
]
|
|
}
|
|
}
|
|
)
|
|
|
|
public func validate(file: File, kind: SwiftExpressionKind,
|
|
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
|
|
guard kind == .call,
|
|
let offset = dictionary.offset,
|
|
isImageNamedInit(dictionary: dictionary, file: file) ||
|
|
isColorInit(dictionary: dictionary, file: file) else {
|
|
return []
|
|
}
|
|
|
|
return [
|
|
StyleViolation(ruleDescription: type(of: self).description,
|
|
severity: configuration.severity,
|
|
location: Location(file: file, byteOffset: offset))
|
|
]
|
|
}
|
|
|
|
private func isImageNamedInit(dictionary: [String: SourceKitRepresentable], file: File) -> Bool {
|
|
guard let name = dictionary.name,
|
|
inits(forClasses: ["UIImage", "NSImage"]).contains(name),
|
|
case let arguments = dictionary.enclosedArguments,
|
|
arguments.flatMap({ $0.name }) == ["named"],
|
|
let argument = arguments.first,
|
|
case let kinds = kinds(forArgument: argument, file: file),
|
|
kinds == [.string] else {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private func isColorInit(dictionary: [String: SourceKitRepresentable], file: File) -> Bool {
|
|
guard let name = dictionary.name,
|
|
inits(forClasses: ["UIColor", "NSColor"]).contains(name),
|
|
case let arguments = dictionary.enclosedArguments,
|
|
case let argumentsNames = arguments.flatMap({ $0.name }),
|
|
argumentsNames == ["red", "green", "blue", "alpha"] || argumentsNames == ["white", "alpha"],
|
|
validateColorKinds(arguments: arguments, file: file) else {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private func inits(forClasses names: [String]) -> [String] {
|
|
return names.flatMap { name in
|
|
[
|
|
name,
|
|
name + ".init"
|
|
]
|
|
}
|
|
}
|
|
|
|
private func validateColorKinds(arguments: [[String: SourceKitRepresentable]], file: File) -> Bool {
|
|
for dictionary in arguments where kinds(forArgument: dictionary, file: file) != [.number] {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private func kinds(forArgument argument: [String: SourceKitRepresentable], file: File) -> Set<SyntaxKind> {
|
|
guard let offset = argument.bodyOffset, let length = argument.bodyLength else {
|
|
return []
|
|
}
|
|
|
|
let range = NSRange(location: offset, length: length)
|
|
return Set(file.syntaxMap.tokens(inByteRange: range).flatMap({ SyntaxKind(rawValue: $0.type) }))
|
|
}
|
|
}
|