When using Swift 5.3's multiple trailing closure syntax (disabling the rule for multiple_closures_with_trailing_closure), a function call with only multiple trailing closures as arguments will trigger "No Space in Method Call Violation."
Common examples of such functions are:
Button { // No Space in Method Call Violation
print("Button tapped")
} label: {
Text("Button")
}
sink Operator:Just(1)
.sink { completion in // No Space in Method Call Violation
print(completion)
} receiveValue: { value in
print(value)
}
.store(in: &disposeBag)
Function calls that begin with non-closure parameters followed by multiple trailing closures work just fine. For example:
UIView.animate(withDuration: 0.5) { // All clear, no violation
print("animating")
} completion: { _ in
print("done")
}
Removing the space properly triggers "Opening Brace Spacing Violation" (see swiftlint autocorrect output below).
$ swiftlint lint
Loading configuration from '.swiftlint.yml'
Linting Swift files at paths
Linting 'ContentView.swift' (1/2)
Linting 'LintTestApp.swift' (2/2)
.../LintTest/ContentView.swift:17:15: warning: No Space in Method Call Violation: Don't add a space between the method name and the parentheses. (no_space_in_method_call)
Done linting! Found 1 violations, 0 serious in 2 files.
$ swiftlint autocorrect
Loading configuration from '.swiftlint.yml'
Correcting Swift files at paths
Correcting 'AnimationView.swift' (1/4)
Correcting 'LintViewModel.swift' (2/4)
Correcting 'ContentView.swift' (3/4)
Correcting 'LintTestApp.swift' (4/4)
.../LintTest/LintTest/ContentView.swift:17:15 Corrected No Space in Method Call
.../LintTest/LintTest/ContentView.swift:17:15 Corrected Opening Brace Spacing
.../LintTest/LintTest/LintViewModel.swift:20:18 Corrected No Space in Method Call
.../LintTest/LintTest/LintViewModel.swift:20:18 Corrected Opening Brace Spacing
Done correcting 4 files!
swiftlint version to be sure)?0.39.2disabled_rules:
- multiple_closures_with_trailing_closure
# Implicitly relevant:
# - no_space_in_method_call
# - opening_brace
xcodebuild -version)?Button { // No Space in Method Call Violation
print("Button tapped")
} label: {
Text("Button")
}
Looking into fixing this by adjusting NoSpaceInMethodCallRule.swift. Once the issue is resolved, it may be worth considering disabling the multiple_closures_with_trailing_closure rule by default. While the new syntax isn't universally loved, it mitigates the call site ambiguity that motivated the rule's creation.
I am seeing this same issue, and getting two warnings:
Button { // No Space in Method Call Violation
print("Button tapped")
} label: { // Multiple Closures with Trailing Closure Violation
Text("Button")
}
@ohayon I assumed the "Multiple Closures with Trailing Closure" to be working correctly in detecting multiple closures when a trailing closure is used, and that it could be disabled now. However, it could be modified to detect _multiple trailing closures_ instead.
This way, it won't trigger on:
Button {
print("Tapped")
} label: {
Text("Button")
}
But will trigger on the current violation:
Button(action: {
print("Tapped")
}) {
Text("Button")
}
And trigger on a three-closure parameters function not using three trailing closure:
myMethod(param1: { "closure1" }) {
"closure 2"
} param3: {
"closure 3"
}
I'm playing around with the SourceKit params for structures to understand how some of the current rules around these are implemented, then learn how to determine when a closure is a proper trailing closure.
@giladronat Can you open another issue to discuss multiple_closures_with_trailing_closure? Let's focus on no_space_in_method_call here 馃檹
Wow fantastic work @marcelofabri, thank you. Yes, will gladly open another issue to discuss multiple_closures_with_trailing_closure.
Regarding #3280, if you have a moment, could you explain how the initial closure's body offset matching the body offset of the function call determines it's the beginning of trailing closures (this line)?
I'll admit I spent far too long trying to understand what differentiates a trailing closure from non-trailing closures and unnamed closure arguments in order to PR a fix I knew accounted for this case without breaking others. For example, looking at TrailingClosureRule and MultipleClosuresWithTrailingClosures gave me the impression the solution would be more involved.
Opened #3295 to discuss multiple_closures_with_trailing_closure in Swift 5.3.