Files
SwiftLint/Source/SwiftLintBuiltInRules/Rules/Style/ClosingBraceRule.swift
Danny Mösch 47335d7f95 Remove tracking of correction positions (#5950)
Report number of corrections per file instead.
2025-04-05 06:04:37 -04:00

73 lines
2.2 KiB
Swift

import SwiftSyntax
@SwiftSyntaxRule(explicitRewriter: true)
struct ClosingBraceRule: Rule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "closing_brace",
name: "Closing Brace Spacing",
description: "Closing brace with closing parenthesis should not have any whitespaces in the middle",
kind: .style,
nonTriggeringExamples: [
Example("[].map({ })"),
Example("[].map(\n { }\n)"),
],
triggeringExamples: [
Example("[].map({ ↓} )"),
Example("[].map({ ↓}\t)"),
],
corrections: [
Example("[].map({ ↓} )"): Example("[].map({ })")
]
)
}
private extension ClosingBraceRule {
final class Visitor: ViolationsSyntaxVisitor<ConfigurationType> {
override func visitPost(_ node: TokenSyntax) {
if node.hasClosingBraceViolation {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}
final class Rewriter: ViolationsSyntaxRewriter<ConfigurationType> {
override func visit(_ node: TokenSyntax) -> TokenSyntax {
guard node.hasClosingBraceViolation else {
return super.visit(node)
}
numberOfCorrections += 1
return super.visit(node.with(\.trailingTrivia, Trivia()))
}
}
}
private extension TokenSyntax {
var hasClosingBraceViolation: Bool {
guard
tokenKind == .rightBrace,
let nextToken = nextToken(viewMode: .sourceAccurate),
nextToken.tokenKind == .rightParen
else {
return false
}
let isImmediatelyNext = positionAfterSkippingLeadingTrivia
== nextToken.positionAfterSkippingLeadingTrivia - SourceLength(utf8Length: 1)
if isImmediatelyNext || nextToken.hasLeadingNewline {
return false
}
return true
}
private var hasLeadingNewline: Bool {
leadingTrivia.contains { piece in
if case .newlines = piece {
return true
}
return false
}
}
}