mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
244 lines
12 KiB
Swift
244 lines
12 KiB
Swift
import SourceKittenFramework
|
|
|
|
public struct ModifierOrderRule: ASTRule, OptInRule, ConfigurationProviderRule {
|
|
public var configuration = ModifierOrderConfiguration(preferredModifierOrder: [.override, .acl])
|
|
|
|
public init() {}
|
|
|
|
public static let description = RuleDescription(
|
|
identifier: "modifier_order",
|
|
name: "Modifier Order",
|
|
description: "Modifier order should be consistent.",
|
|
kind: .style,
|
|
minSwiftVersion: .fourDotOne ,
|
|
nonTriggeringExamples: [
|
|
"public class Foo { \n" +
|
|
" public convenience required init() {} \n" +
|
|
"}",
|
|
"public class Foo { \n" +
|
|
" public static let bar = 42 \n" +
|
|
"}",
|
|
"public class Foo { \n" +
|
|
" public static var bar: Int { \n" +
|
|
" return 42" +
|
|
" }" +
|
|
"}",
|
|
"public class Foo { \n" +
|
|
" public class var bar: Int { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"}",
|
|
"public class Bar { \n" +
|
|
" public class var foo: String { \n" +
|
|
" return \"foo\" \n" +
|
|
" } \n" +
|
|
"} \n" +
|
|
"public class Foo: Bar { \n" +
|
|
" override public final class var foo: String { \n" +
|
|
" return \"bar\" \n" +
|
|
" } \n" +
|
|
"}",
|
|
"open class Bar { \n" +
|
|
" public var foo: Int? { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"} \n" +
|
|
"open class Foo: Bar { \n" +
|
|
" override public var foo: Int? { \n" +
|
|
" return 43 \n" +
|
|
" } \n" +
|
|
"}",
|
|
"open class Bar { \n" +
|
|
" open class func foo() -> Int { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"} \n" +
|
|
"class Foo: Bar { \n" +
|
|
" override open class func foo() -> Int { \n" +
|
|
" return 43 \n" +
|
|
" } \n" +
|
|
"}",
|
|
"protocol Foo: class {} \n" +
|
|
"class Bar { \n" +
|
|
" public private(set) weak var foo: Foo? \n" +
|
|
"} \n",
|
|
"@objc \n" +
|
|
"public final class Foo: NSObject {} \n",
|
|
"@objcMembers \n" +
|
|
"public final class Foo: NSObject {} \n",
|
|
"@objc \n" +
|
|
"override public private(set) weak var foo: Bar? \n",
|
|
"@objc \n" +
|
|
"public final class Foo: NSObject {} \n",
|
|
"@objc \n" +
|
|
"open final class Foo: NSObject { \n" +
|
|
" open weak var weakBar: NSString? = nil \n" +
|
|
"}",
|
|
"public final class Foo {}",
|
|
"class Bar { \n" +
|
|
" func bar() {} \n" +
|
|
"}",
|
|
"internal class Foo: Bar { \n" +
|
|
" override internal func bar() {} \n" +
|
|
"}",
|
|
"public struct Foo { \n" +
|
|
" internal weak var weakBar: NSObject? = nil \n" +
|
|
"}",
|
|
"class Foo { \n" +
|
|
" internal lazy var bar: String = \"foo\" \n" +
|
|
"}"
|
|
],
|
|
triggeringExamples: [
|
|
"class Foo { \n" +
|
|
" convenience required public init() {} \n" +
|
|
"}",
|
|
"public class Foo { \n" +
|
|
" static public let bar = 42 \n" +
|
|
"}",
|
|
"public class Foo { \n" +
|
|
" static public var bar: Int { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"} \n",
|
|
"public class Foo { \n" +
|
|
" class public var bar: Int { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"}",
|
|
"public class RootFoo { \n" +
|
|
" class public var foo: String { \n" +
|
|
" return \"foo\" \n" +
|
|
" } \n" +
|
|
"} \n" +
|
|
"public class Foo: RootFoo { \n" +
|
|
" override final class public var foo: String { \n" +
|
|
" return \"bar\" \n" +
|
|
" } \n" +
|
|
"}",
|
|
"open class Bar { \n" +
|
|
" public var foo: Int? { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"} \n" +
|
|
"open class Foo: Bar { \n" +
|
|
" public override var foo: Int? { \n" +
|
|
" return 43 \n" +
|
|
" } \n" +
|
|
"}",
|
|
"protocol Foo: class {} \n" +
|
|
"class Bar { \n" +
|
|
" private(set) public weak var foo: Foo? \n" +
|
|
"} \n",
|
|
"open class Bar { \n" +
|
|
" open class func foo() -> Int { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"} \n" +
|
|
"class Foo: Bar { \n" +
|
|
" class open override func foo() -> Int { \n" +
|
|
" return 43 \n" +
|
|
" } \n" +
|
|
"}",
|
|
"open class Bar { \n" +
|
|
" open class func foo() -> Int { \n" +
|
|
" return 42 \n" +
|
|
" } \n" +
|
|
"} \n" +
|
|
"class Foo: Bar { \n" +
|
|
" open override class func foo() -> Int { \n" +
|
|
" return 43 \n" +
|
|
" } \n" +
|
|
"}",
|
|
"@objc \n" +
|
|
"final public class Foo: NSObject {}",
|
|
"@objcMembers \n" +
|
|
"final public class Foo: NSObject {}",
|
|
"@objc \n" +
|
|
"final open class Foo: NSObject { \n" +
|
|
" weak open var weakBar: NSString? = nil \n" +
|
|
"}",
|
|
"final public class Foo {} \n",
|
|
"internal class Foo: Bar { \n" +
|
|
" internal override func bar() {} \n" +
|
|
"}",
|
|
"public struct Foo { \n" +
|
|
" weak internal var weakBar: NSObjetc? = nil \n" +
|
|
"}",
|
|
"class Foo { \n" +
|
|
" lazy internal var bar: String = \"foo\" \n" +
|
|
"}"
|
|
]
|
|
)
|
|
|
|
public func validate(file: File,
|
|
kind: SwiftDeclarationKind,
|
|
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
|
|
|
|
guard let offset = dictionary.offset else {
|
|
return []
|
|
}
|
|
|
|
let preferredOrderOfModifiers = [.atPrefixed] + configuration.preferredModifierOrder
|
|
let modifierGroupsInDeclaration = dictionary.modifierGroups
|
|
let filteredPreferedOrderOfModifiers = preferredOrderOfModifiers.filter(modifierGroupsInDeclaration.contains)
|
|
for (index, preferredGroup) in filteredPreferedOrderOfModifiers.enumerated()
|
|
where preferredGroup != modifierGroupsInDeclaration[index] {
|
|
return [StyleViolation(ruleDescription: type(of: self).description,
|
|
severity: configuration.severityConfiguration.severity,
|
|
location: Location(file: file, byteOffset: offset))]
|
|
}
|
|
|
|
return []
|
|
}
|
|
}
|
|
|
|
private extension Dictionary where Key == String, Value == SourceKitRepresentable {
|
|
var modifierGroups: [SwiftDeclarationAttributeKind.ModifierGroup] {
|
|
let staticKinds = [SwiftDeclarationKind.functionMethodClass, .functionMethodStatic, .varClass, .varStatic]
|
|
let staticKindsAndOffsets = kindsAndOffsets(in: staticKinds).map { [$0] } ?? []
|
|
return (swiftAttributes + staticKindsAndOffsets)
|
|
.sorted {
|
|
guard let rhsOffset = $0.offset, let lhsOffset = $1.offset else {
|
|
return false
|
|
}
|
|
return rhsOffset < lhsOffset
|
|
}
|
|
.compactMap {
|
|
if let attribute = $0.attribute {
|
|
return SwiftDeclarationAttributeKind.ModifierGroup(rawAttribute: attribute)
|
|
} else if $0.kind != nil {
|
|
return .typeMethods
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
private func kindsAndOffsets(in declarationKinds: [SwiftDeclarationKind]) -> [String: SourceKitRepresentable]? {
|
|
guard let kind = kind, let offset = offset,
|
|
let declarationKind = SwiftDeclarationKind(rawValue: kind),
|
|
declarationKinds.contains(declarationKind) else {
|
|
return nil
|
|
}
|
|
|
|
return ["key.kind": kind, "key.offset": Int64(offset)]
|
|
}
|
|
}
|
|
|
|
fileprivate extension SwiftDeclarationAttributeKind.ModifierGroup {
|
|
init?(rawAttribute: String) {
|
|
let allModifierGroups: Set<SwiftDeclarationAttributeKind.ModifierGroup> = [
|
|
.acl, .setterACL, .mutators, .override, .owned, .atPrefixed, .dynamic, .final, .typeMethods,
|
|
.required, .convenience, .lazy
|
|
]
|
|
let modifierGroup = allModifierGroups.first {
|
|
$0.swiftDeclarationAttributeKinds.contains(where: { $0.rawValue == rawAttribute })
|
|
}
|
|
|
|
if let modifierGroup = modifierGroup {
|
|
self = modifierGroup
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
}
|