Files
SwiftLint/Source/SwiftLintFramework/Rules/FunctionParameterCountRule.swift
T
2016-02-06 18:55:16 -08:00

103 lines
3.8 KiB
Swift

//
// FunctionParameterCountRule.swift
// SwiftLint
//
// Created by Denis Lebedev on 26/01/2016.
// Copyright © 2016 Realm. All rights reserved.
//
import Foundation
import SourceKittenFramework
public struct FunctionParameterCountRule: ASTRule, ConfigProviderRule {
public var config = SeverityLevelsConfig(warning: 5, error: 8)
public init() {}
public static let description = RuleDescription(
identifier: "function_parameter_count",
name: "Function Parameter Count",
description: "Number of function parameters should be low.",
nonTriggeringExamples: [
"func f2(p1: Int, p2: Int) { }",
"func f(a: Int, b: Int, c: Int, d: Int, x: Int = 42) {}",
"func f(a: [Int], b: Int, c: Int, d: Int, f: Int) -> [Int] {\n" +
"let s = a.flatMap { $0 as? [String: Int] } ?? []}}"
],
triggeringExamples: [
"func f(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int) {}",
"func f(a: Int, b: Int, c: Int, d: Int, e: Int, f: Int = 2, g: Int) {}",
]
)
public func validateFile(file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
if !functionKinds.contains(kind) {
return []
}
let nameOffset = Int(dictionary["key.nameoffset"] as? Int64 ?? 0)
let length = Int(dictionary["key.namelength"] as? Int64 ?? 0)
let substructure = dictionary["key.substructure"] as? [SourceKitRepresentable] ?? []
let parameterCount =
allFunctionParameterCount(substructure, offset: nameOffset, length: length) -
defaultFunctionParameterCount(file, offset: nameOffset, length: length)
for parameter in config.params where parameterCount > parameter.value {
let offset = Int(dictionary["key.offset"] as? Int64 ?? 0)
return [StyleViolation(ruleDescription: self.dynamicType.description,
severity: parameter.severity,
location: Location(file: file, byteOffset: offset),
reason: "Function should have \(config.warning) parameters or less: " +
"it currently has \(parameterCount)")]
}
return []
}
private func allFunctionParameterCount(structure: [SourceKitRepresentable],
offset: Int, length: Int) -> Int {
var parameterCount = 0
for substructure in structure {
guard let subDict = substructure as? [String: SourceKitRepresentable],
key = subDict["key.kind"] as? String,
parameterOffset = subDict["key.offset"] as? Int64 else {
continue
}
guard offset..<offset+length ~= Int(parameterOffset) else {
return parameterCount
}
if SwiftDeclarationKind(rawValue: key) == .VarParameter {
parameterCount += 1
}
}
return parameterCount
}
private func defaultFunctionParameterCount(file: File, offset: Int, length: Int) -> Int {
return (file.contents as NSString)
.substringWithByteRange(start: offset, length: length)?
.characters.filter { $0 == "=" }.count ?? 0
}
private let functionKinds: [SwiftDeclarationKind] = [
.FunctionAccessorAddress,
.FunctionAccessorDidset,
.FunctionAccessorGetter,
.FunctionAccessorMutableaddress,
.FunctionAccessorSetter,
.FunctionAccessorWillset,
.FunctionConstructor,
.FunctionDestructor,
.FunctionFree,
.FunctionMethodClass,
.FunctionMethodInstance,
.FunctionMethodStatic,
.FunctionOperator,
.FunctionSubscript
]
}