mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
d387532929
For a function that takes a closure as default value, the array of
parameter reported by sourcekit also includes the parameters of that
closure.
In other words, a function like
func foo(param1: Int,
param2: Bool,
param3: (Int) -> Void = { (x: Int) in }) { }
reports 4 parameters (param 1, param2, param3, and x).
This commit uses the bounds of the method/function parameters to filter
out parameters within parameters. Below, a 1, a 2, and a 3 would be
filtered out since they're inside parameter 3.
----------------------------------------------------------------|
| |---------| |---------| |----------------------------| |
| | param 1 | | param 2 | | param 3: |a 1| |a 2| |a 3| | |
| |---------| |---------| |----------------------------| |
----------------------------------------------------------------|
85 lines
2.8 KiB
Swift
85 lines
2.8 KiB
Swift
//
|
|
// MultilineParametersRule.swift
|
|
// SwiftLint
|
|
//
|
|
// Created by Ornithologist Coder on 22/05/17.
|
|
// Copyright © 2017 Realm. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import SourceKittenFramework
|
|
|
|
public struct MultilineParametersRule: ASTRule, OptInRule, ConfigurationProviderRule {
|
|
public var configuration = SeverityConfiguration(.warning)
|
|
|
|
private typealias ParameterRange = (offset: Int, length: Int)
|
|
|
|
public init() {}
|
|
|
|
public static let description = RuleDescription(
|
|
identifier: "multiline_parameters",
|
|
name: "Multiline Parameters",
|
|
description: "Functions and methods parameters should be either on the same line, or one per line.",
|
|
kind: .style,
|
|
nonTriggeringExamples: MultilineParametersRuleExamples.nonTriggeringExamples,
|
|
triggeringExamples: MultilineParametersRuleExamples.triggeringExamples
|
|
)
|
|
|
|
public func validate(file: File,
|
|
kind: SwiftDeclarationKind,
|
|
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
|
|
guard
|
|
SwiftDeclarationKind.functionKinds.contains(kind),
|
|
let offset = dictionary.nameOffset,
|
|
let length = dictionary.nameLength
|
|
else {
|
|
return []
|
|
}
|
|
|
|
let parameterRanges = dictionary.substructure.flatMap { subStructure -> ParameterRange? in
|
|
guard
|
|
let offset = subStructure.offset,
|
|
let length = subStructure.length,
|
|
let kind = subStructure.kind, SwiftDeclarationKind(rawValue: kind) == .varParameter
|
|
else {
|
|
return nil
|
|
}
|
|
|
|
return (offset, length)
|
|
}
|
|
|
|
var numberOfParameters = 0
|
|
var linesWithParameters = Set<Int>()
|
|
|
|
for range in parameterRanges {
|
|
guard
|
|
let (line, _) = file.contents.bridge().lineAndCharacter(forByteOffset: range.offset),
|
|
offset..<(offset + length) ~= range.offset,
|
|
isRange(range, withinRanges: parameterRanges)
|
|
else {
|
|
continue
|
|
}
|
|
|
|
linesWithParameters.insert(line)
|
|
numberOfParameters += 1
|
|
}
|
|
|
|
guard
|
|
linesWithParameters.count > 1,
|
|
numberOfParameters != linesWithParameters.count
|
|
else {
|
|
return []
|
|
}
|
|
|
|
return [StyleViolation(ruleDescription: type(of: self).description,
|
|
severity: configuration.severity,
|
|
location: Location(file: file, byteOffset: offset))]
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func isRange(_ range: ParameterRange, withinRanges ranges: [ParameterRange]) -> Bool {
|
|
return ranges.filter { $0 != range && ($0.offset..<($0.offset + $0.length)).contains(range.offset) }.isEmpty
|
|
}
|
|
}
|