Files
SwiftLint/Source/SwiftLintFramework/Rules/ModifiersOrderRule.swift
T
Daniel Metzing cf64c0873b Merge branch 'attibute_and_modifier_order' into upstream_master
# Conflicts:
#	Cartfile
#	Cartfile.private
#	Cartfile.resolved
#	Carthage/Checkouts/SourceKitten
#	Package.resolved
#	Package.swift
#	Rules.md
#	Source/SwiftLintFramework/Extensions/Configuration+LintableFiles.swift
#	Source/SwiftLintFramework/Extensions/Dictionary+SwiftLint.swift
#	Source/SwiftLintFramework/Models/SwiftVersion.swift
#	Source/SwiftLintFramework/Rules/ModifiersOrderRule.swift
#	Source/SwiftLintFramework/Rules/RuleConfigurations/ModifiersOrderConfiguration.swift
#	SwiftLint.xcodeproj/project.pbxproj
#	Tests/SwiftLintFrameworkTests/LinterCacheTests.swift
#	Tests/SwiftLintFrameworkTests/ModifiersOrderTests.swift
#	circle.yml
2018-04-10 23:04:11 +02:00

124 lines
5.1 KiB
Swift

//
// ModifiersOrderRule.swift
// SwiftLint
//
// Created by Jose Cheyo Jimenez on 05/06/17.
// Copyright © 2017 Realm. All rights reserved.
//
import SourceKittenFramework
public struct ModifiersOrderRule: ASTRule, OptInRule, ConfigurationProviderRule {
public var configuration = ModifiersOrderConfiguration(preferedModifiersOrder: [.override, .acl])
public init() {}
public static let description = RuleDescription(
identifier: "modifiers_order",
name: "Modifiers Order",
description: "Modifiers order should be consistent.",
kind: .style,
nonTriggeringExamples: [
"public static let nnumber = 3 \n",
"@objc \npublic final class MyClass: NSObject {\n }",
"@objc \n override public private(set) weak var foo: Bar?\n",
"@objc \npublic final class MyClass: NSObject {\n }",
"@objc \npublic final class MyClass: NSObject {\n" +
"private final func myFinal() {}\n" +
"weak var myWeak: NSString? = nil\n" +
"public static let nnumber = 3 \n }",
"public final class MyClass {}",
"class RootClass { func myFinal() {}}\n" +
"internal class MyClass: RootClass {" +
"override internal func myFinal() {}}"
],
triggeringExamples: [
"class Foo { \n static public let bar = 3 {} \n }",
"class Foo { \n class override public let bar = 3 {} \n }",
"class Foo { \n overide static final public var foo: String {} \n }",
"@objc \npublic final class MyClass: NSObject {\n" +
"final private func myFinal() {}\n}",
"@objc \nfinal public class MyClass: NSObject {}\n",
"final public class MyClass {}\n",
"class MyClass {" +
"weak internal var myWeak: NSString? = nil\n}",
"class MyClass {" +
"static public let nnumber = 3 \n }"
]
)
public func validate(file: File,
kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
guard let offset = dictionary.offset else {
return []
}
let preferedOrderOfModifiers = [.objcInteroperability, .interfaceBuilder] + configuration.preferedModifiersOrder
print(preferedOrderOfModifiers)
let modifierGroupsInDeclaration = findModifierGroups(in: dictionary)
let filteredPreferedOrderOfModifiers = preferedOrderOfModifiers.filter {
return modifierGroupsInDeclaration.contains($0)
}
print(filteredPreferedOrderOfModifiers)
for (index, preferedGroup) in filteredPreferedOrderOfModifiers.enumerated()
where preferedGroup != modifierGroupsInDeclaration[index] {
return [StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severityConfiguration.severity,
location: Location(file: file, byteOffset: offset))]
}
return []
}
// swiftlint:disable line_length
private func findModifierGroups(in dictionary: [String: SourceKitRepresentable]) -> [SwiftDeclarationAttributeKind.ModifierGroup] {
var declarationAttributes = dictionary.enclosedSwiftAttributesWithMetaData
if let delcarationKinds = contains(in: dictionary,
declarationKinds: .functionMethodClass, .functionMethodStatic, .varClass, .varStatic) {
declarationAttributes.append(delcarationKinds)
}
return declarationAttributes
.sorted {
guard let rhsOffset = $0["key.offset"] as? Int64,
let lhsOffset = $1["key.offset"] as? Int64 else {
return false
}
return rhsOffset < lhsOffset
}
.compactMap {
if let attribute = $0["key.attribute"] as? String { return group(of: attribute) }
if $0["key.kind"] != nil { return .typeMethods }
return nil
}
}
private func group(of rawAttribute: String) -> SwiftDeclarationAttributeKind.ModifierGroup? {
for value in SwiftDeclarationAttributeKind.ModifierGroup.allValues {
for attributeKind in value.swiftDeclarationAttributeKinds
where attributeKind.rawValue.hasSuffix(rawAttribute) {
return value
}
}
if rawAttribute == "static" || rawAttribute == "class" {
return .typeMethods
}
return nil
}
private func contains(in dictionary: [String: SourceKitRepresentable],
declarationKinds: SwiftDeclarationKind...) -> [String: SourceKitRepresentable]? {
guard let rawKind = dictionary.kind,
let kind = SwiftDeclarationKind(rawValue: rawKind),
let offset = dictionary.offset else { return nil }
if declarationKinds.contains(kind) { return ["key.kind": rawKind, "key.offset": Int64(offset)] }
return nil
}
}