TypeNameRule

This commit is contained in:
JP Simard
2015-05-18 06:03:03 +02:00
parent e4c05d592a
commit 4f4afbef32
4 changed files with 81 additions and 35 deletions
+1 -35
View File
@@ -47,7 +47,7 @@ extension File {
let kindString = subDict["key.kind"] as? String,
let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) {
violations.extend(self.astViolationsInDictionary(subDict))
violations.extend(self.validateTypeName(kind, dict: subDict))
violations.extend(TypeNameRule.validateFile(self, kind: kind, dictionary: subDict))
violations.extend(self.validateVariableName(kind, dict: subDict))
violations.extend(TypeBodyLengthRule.validateFile(self, kind: kind, dictionary: subDict))
violations.extend(FunctionBodyLengthRule.validateFile(self, kind: kind, dictionary: subDict))
@@ -57,40 +57,6 @@ extension File {
}
}
func validateTypeName(kind: SwiftDeclarationKind, dict: XPCDictionary) -> [StyleViolation] {
let typeKinds: [SwiftDeclarationKind] = [
.Class,
.Struct,
.Typealias,
.Enum,
.Enumelement
]
if !contains(typeKinds, kind) {
return []
}
var violations = [StyleViolation]()
if let name = dict["key.name"] as? String,
let offset = flatMap(dict["key.offset"] as? Int64, { Int($0) }) {
let location = Location(file: self, offset: offset)
let nameCharacterSet = NSCharacterSet(charactersInString: name)
if !NSCharacterSet.alphanumericCharacterSet().isSupersetOfSet(nameCharacterSet) {
violations.append(StyleViolation(type: .NameFormat,
location: location,
reason: "Type name should only contain alphanumeric characters: '\(name)'"))
} else if !name.substringToIndex(name.startIndex.successor()).isUppercase() {
violations.append(StyleViolation(type: .NameFormat,
location: location,
reason: "Type name should start with an uppercase character: '\(name)'"))
} else if count(name) < 3 || count(name) > 40 {
violations.append(StyleViolation(type: .NameFormat,
location: location,
reason: "Type name should be between 3 and 40 characters in length: " +
"'\(name)'"))
}
}
return violations
}
func validateVariableName(kind: SwiftDeclarationKind, dict: XPCDictionary) -> [StyleViolation] {
let variableKinds: [SwiftDeclarationKind] = [
.VarClass,
@@ -0,0 +1,71 @@
//
// TypeNameRule.swift
// SwiftLint
//
// Created by JP Simard on 5/18/15.
// Copyright (c) 2015 Realm. All rights reserved.
//
import SourceKittenFramework
import SwiftXPC
struct TypeNameRule: Rule {
static let identifier = "type_name"
static let parameters = [RuleParameter<Void>]()
static func validateFile(file: File) -> [StyleViolation] {
return self.validateFile(file, dictionary: Structure(file: file).dictionary)
}
static func validateFile(file: File, dictionary: XPCDictionary) -> [StyleViolation] {
return (dictionary["key.substructure"] as? XPCArray ?? []).flatMap { subItem in
var violations = [StyleViolation]()
if let subDict = subItem as? XPCDictionary,
let kindString = subDict["key.kind"] as? String,
let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) {
violations.extend(self.validateFile(file, dictionary: subDict))
violations.extend(self.validateFile(file, kind: kind, dictionary: subDict))
}
return violations
}
}
static func validateFile(file: File,
kind: SwiftDeclarationKind,
dictionary: XPCDictionary) -> [StyleViolation] {
let typeKinds: [SwiftDeclarationKind] = [
.Class,
.Struct,
.Typealias,
.Enum,
.Enumelement
]
if !contains(typeKinds, kind) {
return []
}
var violations = [StyleViolation]()
if let name = dictionary["key.name"] as? String,
let offset = flatMap(dictionary["key.offset"] as? Int64, { Int($0) }) {
let location = Location(file: file, offset: offset)
let nameCharacterSet = NSCharacterSet(charactersInString: name)
if !NSCharacterSet.alphanumericCharacterSet().isSupersetOfSet(nameCharacterSet) {
violations.append(StyleViolation(type: .NameFormat,
location: location,
severity: .Medium,
reason: "Type name should only contain alphanumeric characters: '\(name)'"))
} else if !name.substringToIndex(name.startIndex.successor()).isUppercase() {
violations.append(StyleViolation(type: .NameFormat,
location: location,
severity: .High,
reason: "Type name should start with an uppercase character: '\(name)'"))
} else if count(name) < 3 || count(name) > 40 {
violations.append(StyleViolation(type: .NameFormat,
location: location,
severity: .Medium,
reason: "Type name should be between 3 and 40 characters in length: " +
"'\(name)'"))
}
}
return violations
}
}
@@ -25,14 +25,17 @@ class LinterTests: XCTestCase {
XCTAssertEqual(violations("\(kind) Ab_ {}\n"), [StyleViolation(type: .NameFormat,
location: Location(file: nil, line: 1),
severity: .Medium,
reason: "Type name should only contain alphanumeric characters: 'Ab_'")])
XCTAssertEqual(violations("\(kind) abc {}\n"), [StyleViolation(type: .NameFormat,
location: Location(file: nil, line: 1),
severity: .High,
reason: "Type name should start with an uppercase character: 'abc'")])
XCTAssertEqual(violations("\(kind) Ab {}\n"), [StyleViolation(type: .NameFormat,
location: Location(file: nil, line: 1),
severity: .Medium,
reason: "Type name should be between 3 and 40 characters in length: 'Ab'")])
let longName = join("", Array(count: 40, repeatedValue: "A"))
@@ -41,6 +44,7 @@ class LinterTests: XCTestCase {
XCTAssertEqual(violations("\(kind) \(longerName) {}\n"), [
StyleViolation(type: .NameFormat,
location: Location(file: nil, line: 1),
severity: .Medium,
reason: "Type name should be between 3 and 40 characters in length: " +
"'\(longerName)'")
])
@@ -66,6 +70,7 @@ class LinterTests: XCTestCase {
[
StyleViolation(type: .NameFormat,
location: Location(file: nil, line: 2),
severity: .High,
reason: "Type name should start with an uppercase character: 'def'")
])
+4
View File
@@ -39,6 +39,7 @@
E88DEA8C1B0999A000A66CB0 /* ASTRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA8B1B0999A000A66CB0 /* ASTRule.swift */; };
E88DEA8E1B0999CD00A66CB0 /* TypeBodyLengthRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA8D1B0999CD00A66CB0 /* TypeBodyLengthRule.swift */; };
E88DEA901B099A3100A66CB0 /* FunctionBodyLengthRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA8F1B099A3100A66CB0 /* FunctionBodyLengthRule.swift */; };
E88DEA921B099B1F00A66CB0 /* TypeNameRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA911B099B1F00A66CB0 /* TypeNameRule.swift */; };
E8AB1A2E1A649F2100452012 /* libclang.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E8AB1A2D1A649F2100452012 /* libclang.dylib */; };
E8BA7E111B07A3EC003E02D0 /* Commandant.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E101B07A3EC003E02D0 /* Commandant.framework */; };
E8BA7E131B07A3F3003E02D0 /* LlamaKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8BA7E121B07A3F3003E02D0 /* LlamaKit.framework */; };
@@ -148,6 +149,7 @@
E88DEA8B1B0999A000A66CB0 /* ASTRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASTRule.swift; sourceTree = "<group>"; };
E88DEA8D1B0999CD00A66CB0 /* TypeBodyLengthRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeBodyLengthRule.swift; sourceTree = "<group>"; };
E88DEA8F1B099A3100A66CB0 /* FunctionBodyLengthRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionBodyLengthRule.swift; sourceTree = "<group>"; };
E88DEA911B099B1F00A66CB0 /* TypeNameRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeNameRule.swift; sourceTree = "<group>"; };
E8AB1A2D1A649F2100452012 /* libclang.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libclang.dylib; path = Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib; sourceTree = DEVELOPER_DIR; };
E8BA7E101B07A3EC003E02D0 /* Commandant.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Commandant.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E8BA7E121B07A3F3003E02D0 /* LlamaKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = LlamaKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -364,6 +366,7 @@
E88DEA891B0992B300A66CB0 /* FileLengthRule.swift */,
E88DEA8D1B0999CD00A66CB0 /* TypeBodyLengthRule.swift */,
E88DEA8F1B099A3100A66CB0 /* FunctionBodyLengthRule.swift */,
E88DEA911B099B1F00A66CB0 /* TypeNameRule.swift */,
);
path = Rules;
sourceTree = "<group>";
@@ -528,6 +531,7 @@
E88DEA771B098D0C00A66CB0 /* Rule.swift in Sources */,
E88DEA7C1B098D7D00A66CB0 /* LineLengthRule.swift in Sources */,
E88DEA801B09903300A66CB0 /* ForceCastRule.swift in Sources */,
E88DEA921B099B1F00A66CB0 /* TypeNameRule.swift in Sources */,
E88DEA711B09847500A66CB0 /* ViolationSeverity.swift in Sources */,
E88DEA8C1B0999A000A66CB0 /* ASTRule.swift in Sources */,
E88DEA821B0990A700A66CB0 /* TodoRule.swift in Sources */,