mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
added variable name validation
This commit is contained in:
@@ -234,30 +234,82 @@ extension File {
|
||||
// swiftlint:enable_rule:force_cast
|
||||
var violations = self.astViolationsInDictionary(subDict)
|
||||
if let kindString = subDict["key.kind"] as? String,
|
||||
let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) })
|
||||
where contains([.Class, .Struct, .Typealias, .Enum, .Enumelement], kind),
|
||||
let name = subDict["key.name"] as? String,
|
||||
let offset = flatMap(subDict["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)'"))
|
||||
}
|
||||
let kind = flatMap(kindString, { SwiftDeclarationKind(rawValue: $0) }) {
|
||||
violations.extend(self.validateTypeName(kind, dict: subDict))
|
||||
violations.extend(self.validateVariableName(kind, dict: subDict))
|
||||
}
|
||||
return violations
|
||||
}, [], +)
|
||||
}
|
||||
|
||||
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,
|
||||
.VarGlobal,
|
||||
.VarInstance,
|
||||
.VarLocal,
|
||||
.VarParameter,
|
||||
.VarStatic
|
||||
]
|
||||
if !contains(variableKinds, 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: "Variable name should only contain alphanumeric characters: '\(name)'"))
|
||||
} else if name.substringToIndex(name.startIndex.successor()).isUppercase() {
|
||||
violations.append(StyleViolation(type: .NameFormat,
|
||||
location: location,
|
||||
reason: "Variable name should start with a lowercase character: '\(name)'"))
|
||||
} else if count(name) < 3 || count(name) > 40 {
|
||||
violations.append(StyleViolation(type: .NameFormat,
|
||||
location: location,
|
||||
reason: "Variable name should be between 3 and 40 characters in length: " +
|
||||
"'\(name)'"))
|
||||
}
|
||||
}
|
||||
return violations
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
|
||||
@@ -40,7 +40,6 @@ class LinterTests: XCTestCase {
|
||||
XCTAssertEqual(violations("\(kind) Ab {}\n"), [StyleViolation(type: .NameFormat,
|
||||
location: Location(file: nil, line: 1),
|
||||
reason: "Type name should be between 3 and 40 characters in length: 'Ab'")])
|
||||
XCTAssertEqual(violations("\(kind) Abc {}\n"), [])
|
||||
|
||||
let longName = join("", Array(count: 40, repeatedValue: "A"))
|
||||
XCTAssertEqual(violations("\(kind) \(longName) {}\n"), [])
|
||||
@@ -80,7 +79,40 @@ class LinterTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testVariableNames() {
|
||||
// TODO: Variable names should contain between 3 and 20 characters.
|
||||
for kind in ["class", "struct"] {
|
||||
for varType in ["var", "let"] {
|
||||
XCTAssertEqual(violations("\(kind) Abc { \(varType) def: Void }\n"), [])
|
||||
|
||||
XCTAssertEqual(violations("\(kind) Abc { \(varType) de_: Void }\n"), [
|
||||
StyleViolation(type: .NameFormat,
|
||||
location: Location(file: nil, line: 1),
|
||||
reason: "Variable name should only contain alphanumeric characters: 'de_'")
|
||||
])
|
||||
|
||||
XCTAssertEqual(violations("\(kind) Abc { \(varType) Def: Void }\n"), [
|
||||
StyleViolation(type: .NameFormat,
|
||||
location: Location(file: nil, line: 1),
|
||||
reason: "Variable name should start with a lowercase character: 'Def'")
|
||||
])
|
||||
|
||||
XCTAssertEqual(violations("\(kind) Abc { \(varType) de: Void }\n"), [
|
||||
StyleViolation(type: .NameFormat,
|
||||
location: Location(file: nil, line: 1),
|
||||
reason: "Variable name should be between 3 and 40 characters in length: " +
|
||||
"'de'")
|
||||
])
|
||||
|
||||
let longName = join("", Array(count: 40, repeatedValue: "d"))
|
||||
XCTAssertEqual(violations("\(kind) Abc { \(varType) \(longName): Void }\n"), [])
|
||||
let longerName = longName + "d"
|
||||
XCTAssertEqual(violations("\(kind) Abc { \(varType) \(longerName): Void }\n"), [
|
||||
StyleViolation(type: .NameFormat,
|
||||
location: Location(file: nil, line: 1),
|
||||
reason: "Variable name should be between 3 and 40 characters in length: " +
|
||||
"'\(longerName)'")
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testClosureLengths() {
|
||||
@@ -207,6 +239,7 @@ class LinterTests: XCTestCase {
|
||||
|
||||
func testForceCasting() {
|
||||
XCTAssertEqual(violations("NSNumber() as? Int\n"), [])
|
||||
XCTAssertEqual(violations("// NSNumber() as! Int\n"), [])
|
||||
XCTAssertEqual(violations("NSNumber() as! Int\n"),
|
||||
[StyleViolation(type: .ForceCast,
|
||||
location: Location(file: nil, line: 1),
|
||||
|
||||
@@ -16,7 +16,8 @@ let fileManager = NSFileManager.defaultManager()
|
||||
|
||||
struct LintCommand: CommandType {
|
||||
let verb = "lint"
|
||||
let function = "Print lint warnings and errors for the Swift files in the current directory (default command)"
|
||||
let function = "Print lint warnings and errors for the Swift files in the current directory " +
|
||||
"(default command)"
|
||||
|
||||
func run(mode: CommandMode) -> Result<(), CommandantError<()>> {
|
||||
println("Finding Swift files in current directory...")
|
||||
|
||||
Reference in New Issue
Block a user