FunctionBodyLengthRule

This commit is contained in:
JP Simard
2015-05-18 05:58:57 +02:00
parent 0af4e05cc7
commit e4c05d592a
4 changed files with 87 additions and 40 deletions
+1 -40
View File
@@ -50,52 +50,13 @@ extension File {
violations.extend(self.validateTypeName(kind, dict: subDict))
violations.extend(self.validateVariableName(kind, dict: subDict))
violations.extend(TypeBodyLengthRule.validateFile(self, kind: kind, dictionary: subDict))
violations.extend(self.validateFunctionBodyLength(kind, dict: subDict))
violations.extend(FunctionBodyLengthRule.validateFile(self, kind: kind, dictionary: subDict))
violations.extend(self.validateNesting(kind, dict: subDict))
}
return violations
}
}
func validateFunctionBodyLength(kind: SwiftDeclarationKind, dict: XPCDictionary) ->
[StyleViolation] {
let functionKinds: [SwiftDeclarationKind] = [
.FunctionAccessorAddress,
.FunctionAccessorDidset,
.FunctionAccessorGetter,
.FunctionAccessorMutableaddress,
.FunctionAccessorSetter,
.FunctionAccessorWillset,
.FunctionConstructor,
.FunctionDestructor,
.FunctionFree,
.FunctionMethodClass,
.FunctionMethodInstance,
.FunctionMethodStatic,
.FunctionOperator,
.FunctionSubscript
]
if !contains(functionKinds, kind) {
return []
}
var violations = [StyleViolation]()
if let offset = flatMap(dict["key.offset"] as? Int64, { Int($0) }),
let bodyOffset = flatMap(dict["key.bodyoffset"] as? Int64, { Int($0) }),
let bodyLength = flatMap(dict["key.bodylength"] as? Int64, { Int($0) }) {
let location = Location(file: self, offset: offset)
let startLine = self.contents.lineAndCharacterForByteOffset(bodyOffset)
let endLine = self.contents.lineAndCharacterForByteOffset(bodyOffset + bodyLength)
if let startLine = startLine?.line, let endLine = endLine?.line
where endLine - startLine > 40 {
violations.append(StyleViolation(type: .Length,
location: location,
reason: "Function body should be span 40 lines or less: currently spans " +
"\(endLine - startLine) lines"))
}
}
return violations
}
func validateTypeName(kind: SwiftDeclarationKind, dict: XPCDictionary) -> [StyleViolation] {
let typeKinds: [SwiftDeclarationKind] = [
.Class,
@@ -0,0 +1,81 @@
//
// FunctionBodyLengthRule.swift
// SwiftLint
//
// Created by JP Simard on 5/18/15.
// Copyright (c) 2015 Realm. All rights reserved.
//
import SourceKittenFramework
import SwiftXPC
struct FunctionBodyLengthRule: Rule {
static let identifier = "function_body_length"
static let parameters = [
RuleParameter(severity: .VeryLow, value: 40),
RuleParameter(severity: .Low, value: 50),
RuleParameter(severity: .Medium, value: 75),
RuleParameter(severity: .High, value: 100),
RuleParameter(severity: .VeryHigh, value: 200)
]
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 functionKinds: [SwiftDeclarationKind] = [
.FunctionAccessorAddress,
.FunctionAccessorDidset,
.FunctionAccessorGetter,
.FunctionAccessorMutableaddress,
.FunctionAccessorSetter,
.FunctionAccessorWillset,
.FunctionConstructor,
.FunctionDestructor,
.FunctionFree,
.FunctionMethodClass,
.FunctionMethodInstance,
.FunctionMethodStatic,
.FunctionOperator,
.FunctionSubscript
]
if !contains(functionKinds, kind) {
return []
}
var violations = [StyleViolation]()
if let offset = flatMap(dictionary["key.offset"] as? Int64, { Int($0) }),
let bodyOffset = flatMap(dictionary["key.bodyoffset"] as? Int64, { Int($0) }),
let bodyLength = flatMap(dictionary["key.bodylength"] as? Int64, { Int($0) }) {
let location = Location(file: file, offset: offset)
let startLine = file.contents.lineAndCharacterForByteOffset(bodyOffset)
let endLine = file.contents.lineAndCharacterForByteOffset(bodyOffset + bodyLength)
for parameter in reverse(parameters) {
if let startLine = startLine?.line, let endLine = endLine?.line
where endLine - startLine > parameter.value {
violations.append(StyleViolation(type: .Length,
location: location,
severity: parameter.severity,
reason: "Function body should be span 40 lines or less: currently spans " +
"\(endLine - startLine) lines"))
}
}
}
return violations
}
}
@@ -123,6 +123,7 @@ class LinterTests: XCTestCase {
"}\n"
XCTAssertEqual(violations(longerFunctionBody), [StyleViolation(type: .Length,
location: Location(file: nil, line: 1),
severity: .VeryLow,
reason: "Function body should be span 40 lines or less: currently spans 41 lines")])
}
+4
View File
@@ -38,6 +38,7 @@
E88DEA8A1B0992B300A66CB0 /* FileLengthRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E88DEA891B0992B300A66CB0 /* FileLengthRule.swift */; };
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 */; };
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 */; };
@@ -146,6 +147,7 @@
E88DEA891B0992B300A66CB0 /* FileLengthRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileLengthRule.swift; sourceTree = "<group>"; };
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>"; };
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; };
@@ -361,6 +363,7 @@
E88DEA871B09924C00A66CB0 /* TrailingNewlineRule.swift */,
E88DEA891B0992B300A66CB0 /* FileLengthRule.swift */,
E88DEA8D1B0999CD00A66CB0 /* TypeBodyLengthRule.swift */,
E88DEA8F1B099A3100A66CB0 /* FunctionBodyLengthRule.swift */,
);
path = Rules;
sourceTree = "<group>";
@@ -528,6 +531,7 @@
E88DEA711B09847500A66CB0 /* ViolationSeverity.swift in Sources */,
E88DEA8C1B0999A000A66CB0 /* ASTRule.swift in Sources */,
E88DEA821B0990A700A66CB0 /* TodoRule.swift in Sources */,
E88DEA901B099A3100A66CB0 /* FunctionBodyLengthRule.swift in Sources */,
E88DEA6B1B0983FE00A66CB0 /* StyleViolation.swift in Sources */,
E88DEA7E1B098F2A00A66CB0 /* LeadingWhitespaceRule.swift in Sources */,
);