Skip to content

Commit c3d4e7e

Browse files
committed
Replace with(...) calls with in-place mutation.
Also remove some extensions no longer in use, and rewrite the `DeclModifierListSyntax` helpers to take keywords instead of strings.
1 parent 2d5461e commit c3d4e7e

31 files changed

+400
-414
lines changed

Sources/SwiftFormat/Core/LegacyTriviaBehavior.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@ private final class LegacyTriviaBehaviorRewriter: SyntaxRewriter {
1818
override func visit(_ token: TokenSyntax) -> TokenSyntax {
1919
var token = token
2020
if let pendingLeadingTrivia = pendingLeadingTrivia {
21-
token = token.with(\.leadingTrivia, pendingLeadingTrivia + token.leadingTrivia)
21+
token.leadingTrivia = pendingLeadingTrivia + token.leadingTrivia
2222
self.pendingLeadingTrivia = nil
2323
}
2424
if token.nextToken(viewMode: .sourceAccurate) != nil,
2525
let firstIndexToMove = token.trailingTrivia.firstIndex(where: shouldTriviaPieceBeMoved)
2626
{
2727
pendingLeadingTrivia = Trivia(pieces: Array(token.trailingTrivia[firstIndexToMove...]))
28-
token =
29-
token.with(\.trailingTrivia, Trivia(pieces: Array(token.trailingTrivia[..<firstIndexToMove])))
28+
token.trailingTrivia = Trivia(pieces: Array(token.trailingTrivia[..<firstIndexToMove]))
3029
}
3130
return token
3231
}

Sources/SwiftFormat/Core/ModifierListSyntax+Convenience.swift

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313
import SwiftSyntax
1414

1515
extension DeclModifierListSyntax {
16-
17-
func has(modifier: String) -> Bool {
18-
return contains { $0.name.text == modifier }
19-
}
20-
21-
func has(modifier: TokenKind) -> Bool {
22-
return contains { $0.name.tokenKind == modifier }
23-
}
24-
2516
/// Returns the declaration's access level modifier, if present.
2617
var accessLevelModifier: DeclModifierSyntax? {
2718
for modifier in self {
@@ -35,16 +26,35 @@ extension DeclModifierListSyntax {
3526
return nil
3627
}
3728

38-
/// Returns modifier list without the given modifier.
39-
func remove(name: String) -> DeclModifierListSyntax {
40-
return filter { $0.name.text != name }
29+
/// Returns true if the modifier list contains any of the keywords in the given set.
30+
func contains(anyOf keywords: Set<Keyword>) -> Bool {
31+
return contains {
32+
switch $0.name.tokenKind {
33+
case .keyword(let keyword): return keywords.contains(keyword)
34+
default: return false
35+
}
36+
}
37+
}
38+
39+
/// Removes any of the modifiers in the given set from the modifier list, mutating it in-place.
40+
mutating func remove(anyOf keywords: Set<Keyword>) {
41+
self = filter {
42+
switch $0.name.tokenKind {
43+
case .keyword(let keyword): return !keywords.contains(keyword)
44+
default: return true
45+
}
46+
}
4147
}
4248

43-
/// Returns a formatted declaration modifier token with the given name.
44-
func createModifierToken(name: String) -> DeclModifierSyntax {
45-
let id = TokenSyntax.identifier(name, trailingTrivia: .spaces(1))
46-
let newModifier = DeclModifierSyntax(name: id, detail: nil)
47-
return newModifier
49+
50+
/// Returns a copy of the modifier list with any of the modifiers in the given set removed.
51+
func removing(anyOf keywords: Set<Keyword>) -> DeclModifierListSyntax {
52+
return filter {
53+
switch $0.name.tokenKind {
54+
case .keyword(let keyword): return !keywords.contains(keyword)
55+
default: return true
56+
}
57+
}
4858
}
4959

5060
/// Inserts the given modifier into the list at a specific index.

Sources/SwiftFormat/Core/TokenSyntax+Convenience.swift

Lines changed: 0 additions & 37 deletions
This file was deleted.

Sources/SwiftFormat/Core/Trivia+Convenience.swift

Lines changed: 5 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,15 @@
1313
import SwiftSyntax
1414

1515
extension Trivia {
16-
var numberOfComments: Int {
17-
var count = 0
18-
for piece in self {
19-
switch piece {
16+
var hasAnyComments: Bool {
17+
return contains {
18+
switch $0 {
2019
case .lineComment, .docLineComment, .blockComment, .docBlockComment:
21-
count += 1
20+
return true
2221
default:
23-
continue
22+
return false
2423
}
2524
}
26-
return count
2725
}
2826

2927
/// Returns whether the trivia contains at least 1 `lineComment`.
@@ -34,16 +32,6 @@ extension Trivia {
3432
}
3533
}
3634

37-
/// Returns this set of trivia, without any whitespace characters.
38-
func withoutSpaces() -> Trivia {
39-
return Trivia(
40-
pieces: filter {
41-
if case .spaces = $0 { return false }
42-
if case .tabs = $0 { return false }
43-
return true
44-
})
45-
}
46-
4735
/// Returns this set of trivia, without any leading spaces.
4836
func withoutLeadingSpaces() -> Trivia {
4937
return Trivia(
@@ -54,15 +42,6 @@ extension Trivia {
5442
}))
5543
}
5644

57-
/// Returns this set of trivia, without any newlines.
58-
func withoutNewlines() -> Trivia {
59-
return Trivia(
60-
pieces: filter {
61-
if case .newlines = $0 { return false }
62-
return true
63-
})
64-
}
65-
6645
/// Returns this trivia, excluding the last newline and anything following it.
6746
///
6847
/// If there is no newline in the trivia, it is returned unmodified.
@@ -80,61 +59,6 @@ extension Trivia {
8059
return Trivia(pieces: self.dropLast(self.count - lastNewlineOffset))
8160
}
8261

83-
/// Returns this set of trivia, with all spaces removed except for one at the
84-
/// end.
85-
func withOneTrailingSpace() -> Trivia {
86-
return withoutSpaces() + .spaces(1)
87-
}
88-
89-
/// Returns this set of trivia, with all spaces removed except for one at the
90-
/// beginning.
91-
func withOneLeadingSpace() -> Trivia {
92-
return .spaces(1) + withoutSpaces()
93-
}
94-
95-
/// Returns this set of trivia, with all newlines removed except for one.
96-
func withOneLeadingNewline() -> Trivia {
97-
return .newlines(1) + withoutNewlines()
98-
}
99-
100-
/// Returns this set of trivia, with all newlines removed except for one.
101-
func withOneTrailingNewline() -> Trivia {
102-
return withoutNewlines() + .newlines(1)
103-
}
104-
105-
/// Walks through trivia looking for multiple separate trivia entities with
106-
/// the same base kind, and condenses them.
107-
/// `[.spaces(1), .spaces(2)]` becomes `[.spaces(3)]`.
108-
func condensed() -> Trivia {
109-
guard var prev = first else { return self }
110-
var pieces = [TriviaPiece]()
111-
for piece in dropFirst() {
112-
switch (prev, piece) {
113-
case (.spaces(let l), .spaces(let r)):
114-
prev = .spaces(l + r)
115-
case (.tabs(let l), .tabs(let r)):
116-
prev = .tabs(l + r)
117-
case (.newlines(let l), .newlines(let r)):
118-
prev = .newlines(l + r)
119-
case (.carriageReturns(let l), .carriageReturns(let r)):
120-
prev = .carriageReturns(l + r)
121-
case (.carriageReturnLineFeeds(let l), .carriageReturnLineFeeds(let r)):
122-
prev = .carriageReturnLineFeeds(l + r)
123-
case (.verticalTabs(let l), .verticalTabs(let r)):
124-
prev = .verticalTabs(l + r)
125-
case (.unexpectedText(let l), .unexpectedText(let r)):
126-
prev = .unexpectedText(l + r)
127-
case (.formfeeds(let l), .formfeeds(let r)):
128-
prev = .formfeeds(l + r)
129-
default:
130-
pieces.append(prev)
131-
prev = piece
132-
}
133-
}
134-
pieces.append(prev)
135-
return Trivia(pieces: pieces)
136-
}
137-
13862
/// Returns `true` if this trivia contains any newlines.
13963
var containsNewlines: Bool {
14064
return contains(

Sources/SwiftFormat/Core/SemicolonSyntaxProtocol.swift renamed to Sources/SwiftFormat/Core/WithSemicolonSyntax.swift

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,20 @@
1313
import SwiftSyntax
1414

1515
/// Protocol that declares support for accessing and modifying a token that represents a semicolon.
16-
protocol SemicolonSyntaxProtocol: SyntaxProtocol {
16+
protocol WithSemicolonSyntax: SyntaxProtocol {
1717
var semicolon: TokenSyntax? { get set }
1818
}
1919

20-
extension MemberBlockItemSyntax: SemicolonSyntaxProtocol {}
21-
extension CodeBlockItemSyntax: SemicolonSyntaxProtocol {}
20+
extension MemberBlockItemSyntax: WithSemicolonSyntax {}
21+
extension CodeBlockItemSyntax: WithSemicolonSyntax {}
2222

23-
extension Syntax {
24-
func asProtocol(_: SemicolonSyntaxProtocol.Protocol) -> SemicolonSyntaxProtocol? {
25-
return self.asProtocol(SyntaxProtocol.self) as? SemicolonSyntaxProtocol
23+
extension SyntaxProtocol {
24+
func asProtocol(_: WithSemicolonSyntax.Protocol) -> WithSemicolonSyntax? {
25+
return Syntax(self).asProtocol(SyntaxProtocol.self) as? WithSemicolonSyntax
2626
}
2727

28-
func isProtocol(_: SemicolonSyntaxProtocol.Protocol) -> Bool {
29-
return self.asProtocol(SemicolonSyntaxProtocol.self) != nil
28+
func isProtocol(_: WithSemicolonSyntax.Protocol) -> Bool {
29+
return self.asProtocol(WithSemicolonSyntax.self) != nil
3030
}
3131
}
32+

Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
914914
}
915915

916916
override func visit(_ node: ArrayExprSyntax) -> SyntaxVisitorContinueKind {
917-
if !node.elements.isEmpty || node.rightSquare.leadingTrivia.numberOfComments > 0 {
917+
if !node.elements.isEmpty || node.rightSquare.leadingTrivia.hasAnyComments {
918918
after(node.leftSquare, tokens: .break(.open, size: 0), .open)
919919
before(node.rightSquare, tokens: .break(.close, size: 0), .close)
920920
}
@@ -954,8 +954,8 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
954954
// The node's content is either a `DictionaryElementListSyntax` or a `TokenSyntax` for a colon
955955
// token (for an empty dictionary).
956956
if !(node.content.as(DictionaryElementListSyntax.self)?.isEmpty ?? true)
957-
|| node.content.leadingTrivia.numberOfComments > 0
958-
|| node.rightSquare.leadingTrivia.numberOfComments > 0
957+
|| node.content.leadingTrivia.hasAnyComments
958+
|| node.rightSquare.leadingTrivia.hasAnyComments
959959
{
960960
after(node.leftSquare, tokens: .break(.open, size: 0), .open)
961961
before(node.rightSquare, tokens: .break(.close, size: 0), .close)
@@ -2775,7 +2775,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
27752775
) -> Bool where BodyContents.Element: SyntaxProtocol {
27762776
// If the collection is empty, then any comments that might be present in the block must be
27772777
// leading trivia of the right brace.
2778-
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.numberOfComments > 0
2778+
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.hasAnyComments
27792779
// We can't use `count` here because it also includes missing children. Instead, we get an
27802780
// iterator and check if it returns `nil` immediately.
27812781
var contentsIterator = node[keyPath: contentsKeyPath].makeIterator()
@@ -2796,7 +2796,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
27962796
) -> Bool where BodyContents.Element == Syntax {
27972797
// If the collection is empty, then any comments that might be present in the block must be
27982798
// leading trivia of the right brace.
2799-
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.numberOfComments > 0
2799+
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.hasAnyComments
28002800
// We can't use `count` here because it also includes missing children. Instead, we get an
28012801
// iterator and check if it returns `nil` immediately.
28022802
var contentsIterator = node[keyPath: contentsKeyPath].makeIterator()
@@ -2817,7 +2817,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
28172817
) -> Bool where BodyContents.Element == DeclSyntax {
28182818
// If the collection is empty, then any comments that might be present in the block must be
28192819
// leading trivia of the right brace.
2820-
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.numberOfComments > 0
2820+
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.hasAnyComments
28212821
// We can't use `count` here because it also includes missing children. Instead, we get an
28222822
// iterator and check if it returns `nil` immediately.
28232823
var contentsIterator = node[keyPath: contentsKeyPath].makeIterator()
@@ -2980,7 +2980,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
29802980
private func arrangeBracesAndContents(leftBrace: TokenSyntax, accessors: AccessorDeclListSyntax, rightBrace: TokenSyntax) {
29812981
// If the collection is empty, then any comments that might be present in the block must be
29822982
// leading trivia of the right brace.
2983-
let commentPrecedesRightBrace = rightBrace.leadingTrivia.numberOfComments > 0
2983+
let commentPrecedesRightBrace = rightBrace.leadingTrivia.hasAnyComments
29842984
// We can't use `count` here because it also includes missing children. Instead, we get an
29852985
// iterator and check if it returns `nil` immediately.
29862986
var accessorsIterator = accessors.makeIterator()
@@ -3890,10 +3890,13 @@ class CommentMovingRewriter: SyntaxRewriter {
38903890
}
38913891

38923892
override func visit(_ token: TokenSyntax) -> TokenSyntax {
3893-
if let rewrittenTrivia = rewriteTokenTriviaMap[token] {
3894-
return token.with(\.leadingTrivia, rewrittenTrivia)
3893+
guard let rewrittenTrivia = rewriteTokenTriviaMap[token] else {
3894+
return token
38953895
}
3896-
return token
3896+
3897+
var result = token
3898+
result.leadingTrivia = rewrittenTrivia
3899+
return result
38973900
}
38983901

38993902
override func visit(_ node: InfixOperatorExprSyntax) -> ExprSyntax {

Sources/SwiftFormat/Rules/AllPublicDeclarationsHaveDocumentation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ public final class AllPublicDeclarationsHaveDocumentation: SyntaxLintRule {
7373
private func diagnoseMissingDocComment(
7474
_ decl: DeclSyntax,
7575
name: String,
76-
modifiers: DeclModifierListSyntax?
76+
modifiers: DeclModifierListSyntax
7777
) {
7878
guard
7979
DocumentationCommentText(extractedFrom: decl.leadingTrivia) == nil,
80-
let mods = modifiers, mods.has(modifier: "public") && !mods.has(modifier: "override")
80+
modifiers.contains(anyOf: [.public, .override])
8181
else {
8282
return
8383
}

Sources/SwiftFormat/Rules/AlwaysUseLowerCamelCase.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public final class AlwaysUseLowerCamelCase: SyntaxLintRule {
4646
// Don't diagnose any issues when the variable is overriding, because this declaration can't
4747
// rename the variable. If the user analyzes the code where the variable is really declared,
4848
// then the diagnostic can be raised for just that location.
49-
if node.modifiers.has(modifier: "override") {
49+
if node.modifiers.contains(anyOf: [.override]) {
5050
return .visitChildren
5151
}
5252

@@ -114,7 +114,7 @@ public final class AlwaysUseLowerCamelCase: SyntaxLintRule {
114114
// Don't diagnose any issues when the function is overriding, because this declaration can't
115115
// rename the function. If the user analyzes the code where the function is really declared,
116116
// then the diagnostic can be raised for just that location.
117-
if node.modifiers.has(modifier: "override") {
117+
if node.modifiers.contains(anyOf: [.override]) {
118118
return .visitChildren
119119
}
120120

Sources/SwiftFormat/Rules/AmbiguousTrailingClosureOverload.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public final class AmbiguousTrailingClosureOverload: SyntaxLintRule {
4242
let params = fn.signature.parameterClause.parameters
4343
guard let firstParam = params.firstAndOnly else { continue }
4444
guard firstParam.type.is(FunctionTypeSyntax.self) else { continue }
45-
if fn.modifiers.has(modifier: "static") || fn.modifiers.has(modifier: "class") {
45+
if fn.modifiers.contains(anyOf: [.class, .static]) {
4646
staticOverloads[fn.name.text, default: []].append(fn)
4747
} else {
4848
overloads[fn.name.text, default: []].append(fn)

Sources/SwiftFormat/Rules/DoNotUseSemicolons.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public final class DoNotUseSemicolons: SyntaxFormatRule {
2828
/// - node: A node that contains items which may have semicolons or nested code blocks.
2929
/// - nodeCreator: A closure that creates a new node given an array of items.
3030
private func nodeByRemovingSemicolons<
31-
ItemType: SyntaxProtocol & SemicolonSyntaxProtocol & Equatable, NodeType: SyntaxCollection
31+
ItemType: SyntaxProtocol & WithSemicolonSyntax & Equatable, NodeType: SyntaxCollection
3232
>(from node: NodeType, nodeCreator: ([ItemType]) -> NodeType) -> NodeType
3333
where NodeType.Element == ItemType {
3434
var newItems = Array(node)
@@ -84,7 +84,7 @@ public final class DoNotUseSemicolons: SyntaxFormatRule {
8484
// whitespace, and the pretty printer adds any necessary spaces so it's safe to discard.
8585
// TODO: When we stop using the legacy trivia transform, we need to fix this to preserve
8686
// trailing comments.
87-
newItem = newItem.with(\.semicolon, nil)
87+
newItem.semicolon = nil
8888

8989
// When emitting the finding, tell the user to move the next statement down if there is
9090
// another statement following this one. Otherwise, just tell them to remove the semicolon.

0 commit comments

Comments
 (0)