Files
SwiftLint/Source/SwiftLintBuiltInRules/Rules/Lint/MultilineCallArgumentsRuleExamples.swift
2026-04-11 08:40:43 +02:00

530 lines
16 KiB
Swift

// swiftlint:disable file_length
// swiftlint:disable type_body_length
struct MultilineCallArgumentsRuleExamples {
static let nonTriggeringExamples: [Example] = [
// MARK: - Baseline: multi-line OK
Example("""
foo(param1: 1,
param2: false,
param3: [])
""",
configuration: ["max_number_of_single_line_parameters": 1]
),
Example("""
func foo(one: [Int], animated: Bool) {}
add(one: [
1,
2,
3
], animated: true)
"""),
Example("""
foo(
param1: 1,
param2: 2,
param3: 3
)
""",
configuration: ["allows_single_line": false]
),
// MARK: - Baseline: single-line OK
Example(
"foo(param1: 1, param2: false)",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example(
"Enum.foo(param1: 1, param2: false)",
configuration: ["max_number_of_single_line_parameters": 2]
),
// allows_single_line=false does NOT affect 0/1-arg calls
Example("foo()", configuration: ["allows_single_line": false]),
Example("foo(param1: 1)", configuration: ["allows_single_line": false]),
Example("Enum.foo(param1: 1)", configuration: ["allows_single_line": false]),
// MARK: - Unlabeled / mixed arguments
Example("foo(1, 2)", configuration: ["max_number_of_single_line_parameters": 2]),
Example("foo(1, b: 2)", configuration: ["max_number_of_single_line_parameters": 2]),
Example("foo(1, b: 2, c: 3)", configuration: ["max_number_of_single_line_parameters": 3]),
// MARK: - Enum-case constructor calls are normal calls (stable by declaring the enum)
Example("""
enum EnumCase {
case first(one: Int, two: Int, three: Int, four: Int)
}
EnumCase.first(one: 1, two: 2, three: 3, four: 4)
""",
configuration: ["allows_single_line": true]
),
Example("""
enum EnumCase {
case first(one: Int, two: Int, three: Int, four: Int)
}
let test = EnumCase.first(
one: 1,
two: 2,
three: 3,
four: 4
)
""",
configuration: ["allows_single_line": false]
),
// MARK: - Trailing closures are ignored by this rule (args-only)
// Single-line args still use max_number_of_single_line_parameters
Example("""
foo(a: 1, b: 2) { value in
print(value)
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// Multi-line args remain valid regardless of closure placement
Example("""
foo(
a: 1,
b: 2
) { value in
print(value)
}
""",
configuration: ["allows_single_line": false]
),
Example("""
foo(
a: 1,
b: 2
)
{ value in
print(value)
}
""",
configuration: ["allows_single_line": false]
),
// No-parens form: no arguments list -> never violates
Example("""
foo { value in
print(value)
}
""",
configuration: ["max_number_of_single_line_parameters": 1]
),
// Multiple trailing closures: still args-only
Example("""
foo(a: 1, b: 2) { _ in
print("main")
} trailing: { _ in
print("extra")
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
foo(with: { _ in
9_999
}, and: { _ in
nil
})
"""),
// MARK: - Trivia / comments
Example("""
foo(
a: 1,
// comment
b: 2,
c: 3
)
"""),
// Note: arguments start on the same line, so this is treated as a single-line-args call;
// the comma-newline check applies only when argument start lines are already split.
Example("""
foo(
a: (1, 2), b: 3
)
"""),
Example("""
foo(
a: (1, 2),
b: 3
)
""",
configuration: ["allows_single_line": false]
),
Example("""
foo(
a: 1, // comment
b: 2,
c: 3
)
"""),
Example("""
enum EnumCase {
case caseOne(Int, Int, Int, Int)
}
let enumCase: EnumCase = .caseOne(
1,
2,
3,
4
)
if case let .caseOne(_, _, three, _) = enumCase {
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
enum EnumCase {
case caseOne(one: Int, two: Int, three: Int, four: Int)
}
let enumCase: EnumCase = .caseOne(
one: 1,
two: 2,
three: 3,
four: 4
)
switch enumCase {
case let .caseOne(one: _, two: _, three: three, four: _):
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
enum EnumCase { case caseOne(Int, Int, Int, Int) }
let array: [EnumCase] = [
.caseOne(
1,
2,
3,
4
)
]
for case let .caseOne(_, _, three, _) in array {
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
enum EnumCase {
case caseOne(Int, Int, Int, Int)
}
let enumCase: EnumCase = .caseOne(
1,
2,
3,
4
)
guard case let .caseOne(_, _, three, _) = enumCase else { return }
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
enum EnumCase {
case caseOne(Int, Int, Int, Int)
}
let enumCase: EnumCase = .caseOne(
1,
2,
3,
4
)
while case let .caseOne(_, _, three, _) = enumCase {
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// MARK: - Pattern matching MUST be ignored: catch patterns
Example("""
enum EnumCase: Error {
case caseOne(Int, Int, Int, Int)
}
func mayThrow() throws {
}
do {
try mayThrow()
} catch let EnumCase.caseOne(_, _, three, _) {
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
enum EnumCase: Error {
case caseOne(one: Int, two: Int, three: Int, four: Int)
}
func mayThrow() throws {
}
do {
try mayThrow()
} catch let EnumCase.caseOne(one: _, two: _, three: three, four: _) {
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// MARK: - Regular calls near patterns are still linted
Example("""
func foo(a: Int, b: Int, c: Int) -> Int { a + b + c }
enum EnumCase { case caseOne(Int, Int, Int, Int) }
if case let .caseOne(_, _, _, _) = EnumCase.caseOne(
1,
2,
3,
4
) {
_ = foo(
a: 1,
b: 2,
c: 3
)
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// MARK: - Pattern matching MUST be ignored: enum-case patterns with literal subpatterns
Example("""
enum EnumCase {
case caseOne(Int, Int, Int, Int)
}
// Real call is written multi-line to avoid noise for max=2
let enumCase: EnumCase = .caseOne(
0,
0,
0,
0
)
// This is a PATTERN, not a call, and must be ignored even though it looks like `.caseOne(1,2,3,4)`
if case .caseOne(1, 2, 3, 4) = enumCase {
// no-op
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
enum EnumCase {
case caseOne(one: Int, two: Int, three: Int, four: Int)
}
let enumCase: EnumCase = .caseOne(
one: 0,
two: 0,
three: 0,
four: 0
)
switch enumCase {
case .caseOne(one: 1, two: 2, three: 3, four: 4):
break
default:
break
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
enum EnumCase: Error {
case caseOne(Int, Int, Int, Int)
}
func mayThrow() throws {}
do {
try mayThrow()
} catch EnumCase.caseOne(1, 2, 3, 4) {
// pattern — must be ignored
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
]
static let triggeringExamples: [Example] = [
// MARK: - Single-line: too many args
Example(
"foo(param1: 1, param2: false, ↓param3: [])",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example(
"Enum.foo(param1: 1, param2: false, ↓param3: [])",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("foo(1, 2, ↓3)", configuration: ["max_number_of_single_line_parameters": 2]),
Example("foo(1, b: 2, ↓3)", configuration: ["max_number_of_single_line_parameters": 2]),
// allows_single_line=false: any 2+ single-line call violates at 2nd argument
Example("foo(param1: 1, ↓param2: false)", configuration: ["allows_single_line": false]),
Example("Enum.foo(param1: 1, ↓param2: false)", configuration: ["allows_single_line": false]),
// MARK: - Multi-line: two args start on the same line
Example("""
foo(
a: 1, ↓b: 2,
c: 3
)
"""),
Example("""
foo(
a: 1,
b: 2, ↓c: 3
)
"""),
Example("""
foo(
a: 1,
b: 2,
c: 3, ↓d: 4,
e: 5
)
"""),
Example("""
foo(
a: (
1,
2
), ↓b: 3
)
""",
configuration: ["max_number_of_single_line_parameters": 1]
),
Example("""
foo(
a: 1, /* comment */ ↓b: 2,
c: 3
)
"""),
// MARK: - Enum-case constructor calls are linted like normal calls
Example("""
enum EnumCase {
case first(one: Int, two: Int, three: Int, four: Int)
}
EnumCase.first(one: 1, ↓two: 2, three: 3, four: 4)
""",
configuration: ["allows_single_line": false]
),
Example("""
enum EnumCase {
case first(one: Int, two: Int, three: Int, four: Int)
}
let test = EnumCase.first(one: 1, two: 2, ↓three: 3, four: 4)
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// MARK: - Trailing closure: parentheses args still checked
Example("""
foo(a: 1, ↓b: 2) { _ in
print("x")
}
""",
configuration: ["max_number_of_single_line_parameters": 1]
),
// MARK: - Targeted tests
// Targeted: real `.caseOne(1,2,3,4)` call MUST be linted (not a pattern)
Example("""
enum EnumCase { case caseOne(Int, Int, Int, Int) }
let x: EnumCase = .caseOne(1, 2, ↓3, 4)
_ = x
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// Targeted: labeled enum-case constructor call MUST be linted
Example("""
enum EnumCase {
case caseOne(one: Int, two: Int, three: Int, four: Int)
}
let x: EnumCase = .caseOne(one: 1, two: 2, ↓three: 3, four: 4)
_ = x
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// Targeted: pattern-part ignored, RHS call linted
Example("""
func foo(a: Int, b: Int, c: Int) -> Int { a + b + c }
enum EnumCase { case caseOne(Int, Int, Int, Int) }
let enumCase: EnumCase = .caseOne(
1,
2,
3,
4
)
if case let .caseOne(_, _, _, _) = enumCase {
_ = foo(a: 1, b: 2, ↓c: 3)
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// Targeted: switch-where RHS call linted, pattern ignored
Example("""
func foo(a: Int, b: Int, c: Int) -> Bool { a + b == c }
enum EnumCase { case caseOne(Int, Int, Int, Int) }
let enumCase: EnumCase = .caseOne(
1,
2,
3,
4
)
switch enumCase {
case .caseOne where foo(a: 1, b: 2, ↓c: 3):
break
default:
break
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
// Targeted: for-case pattern ignored, body call linted
Example("""
func foo(a: Int, b: Int, c: Int) -> Int { a + b + c }
enum EnumCase { case caseOne(Int, Int, Int, Int) }
let array: [EnumCase] = [
.caseOne(
1,
2,
3,
4
)
]
for case let .caseOne(_, _, _, _) in array {
_ = foo(a: 1, b: 2, ↓c: 3)
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
Example("""
func foo(a: Int, b: Int, c: Int) -> Int { a + b + c }
enum EnumCase: Error { case caseOne(Int, Int, Int, Int) }
func mayThrow() throws {
}
do {
try mayThrow()
} catch let EnumCase.caseOne(_, _, _, _) {
_ = foo(a: 1, b: 2, ↓c: 3)
}
""",
configuration: ["max_number_of_single_line_parameters": 2]
),
]
}
// swiftlint:enable type_body_length
// swiftlint:enable file_length