mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
With the binding of configurations to their associated rule types "unknown configuration" errors can be made more specific mentioning also the rule's identifier in the printed message.
109 lines
4.3 KiB
Swift
109 lines
4.3 KiB
Swift
import SwiftSyntax
|
|
|
|
struct EmptyParenthesesWithTrailingClosureRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
|
|
var configuration = SeverityConfiguration<Self>(.warning)
|
|
|
|
static let description = RuleDescription(
|
|
identifier: "empty_parentheses_with_trailing_closure",
|
|
name: "Empty Parentheses with Trailing Closure",
|
|
description: "When using trailing closures, empty parentheses should be avoided " +
|
|
"after the method call",
|
|
kind: .style,
|
|
nonTriggeringExamples: [
|
|
Example("[1, 2].map { $0 + 1 }\n"),
|
|
Example("[1, 2].map({ $0 + 1 })\n"),
|
|
Example("[1, 2].reduce(0) { $0 + $1 }"),
|
|
Example("[1, 2].map { number in\n number + 1 \n}\n"),
|
|
Example("let isEmpty = [1, 2].isEmpty()\n"),
|
|
Example("""
|
|
UIView.animateWithDuration(0.3, animations: {
|
|
self.disableInteractionRightView.alpha = 0
|
|
}, completion: { _ in
|
|
()
|
|
})
|
|
""")
|
|
],
|
|
triggeringExamples: [
|
|
Example("[1, 2].map↓() { $0 + 1 }\n"),
|
|
Example("[1, 2].map↓( ) { $0 + 1 }\n"),
|
|
Example("[1, 2].map↓() { number in\n number + 1 \n}\n"),
|
|
Example("[1, 2].map↓( ) { number in\n number + 1 \n}\n"),
|
|
Example("func foo() -> [Int] {\n return [1, 2].map↓() { $0 + 1 }\n}\n")
|
|
],
|
|
corrections: [
|
|
Example("[1, 2].map↓() { $0 + 1 }\n"): Example("[1, 2].map { $0 + 1 }\n"),
|
|
Example("[1, 2].map↓( ) { $0 + 1 }\n"): Example("[1, 2].map { $0 + 1 }\n"),
|
|
Example("[1, 2].map↓() { number in\n number + 1 \n}\n"):
|
|
Example("[1, 2].map { number in\n number + 1 \n}\n"),
|
|
Example("[1, 2].map↓( ) { number in\n number + 1 \n}\n"):
|
|
Example("[1, 2].map { number in\n number + 1 \n}\n"),
|
|
Example("func foo() -> [Int] {\n return [1, 2].map↓() { $0 + 1 }\n}\n"):
|
|
Example("func foo() -> [Int] {\n return [1, 2].map { $0 + 1 }\n}\n"),
|
|
Example("class C {\n#if true\nfunc f() {\n[1, 2].map↓() { $0 + 1 }\n}\n#endif\n}"):
|
|
Example("class C {\n#if true\nfunc f() {\n[1, 2].map { $0 + 1 }\n}\n#endif\n}")
|
|
]
|
|
)
|
|
|
|
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
|
|
Visitor(viewMode: .sourceAccurate)
|
|
}
|
|
|
|
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? {
|
|
Rewriter(
|
|
locationConverter: file.locationConverter,
|
|
disabledRegions: disabledRegions(file: file)
|
|
)
|
|
}
|
|
}
|
|
|
|
private extension EmptyParenthesesWithTrailingClosureRule {
|
|
final class Visitor: ViolationsSyntaxVisitor {
|
|
override func visitPost(_ node: FunctionCallExprSyntax) {
|
|
guard let position = node.violationPosition else {
|
|
return
|
|
}
|
|
|
|
violations.append(position)
|
|
}
|
|
}
|
|
|
|
private final class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter {
|
|
private(set) var correctionPositions: [AbsolutePosition] = []
|
|
let locationConverter: SourceLocationConverter
|
|
let disabledRegions: [SourceRange]
|
|
|
|
init(locationConverter: SourceLocationConverter, disabledRegions: [SourceRange]) {
|
|
self.locationConverter = locationConverter
|
|
self.disabledRegions = disabledRegions
|
|
}
|
|
|
|
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
|
|
guard
|
|
let violationPosition = node.violationPosition,
|
|
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter)
|
|
else {
|
|
return super.visit(node)
|
|
}
|
|
|
|
let newNode = node
|
|
.with(\.leftParen, nil)
|
|
.with(\.rightParen, nil)
|
|
.with(\.trailingClosure, node.trailingClosure?.with(\.leadingTrivia, .spaces(1)))
|
|
correctionPositions.append(violationPosition)
|
|
return super.visit(newNode)
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension FunctionCallExprSyntax {
|
|
var violationPosition: AbsolutePosition? {
|
|
guard trailingClosure != nil,
|
|
let leftParen,
|
|
argumentList.isEmpty else {
|
|
return nil
|
|
}
|
|
|
|
return leftParen.positionAfterSkippingLeadingTrivia
|
|
}
|
|
}
|