Skip to content

Commit 12beca4

Browse files
committed
[Syntax] Fix TriviaPiece.isNewline
In Swift, only 'CR', 'LF', and 'CR+LF' are considered newline characters. `TriviaPiece.isNewline` should not return true for 'VT' and 'FF'. Instead of using 'Swift.Character.isNewline', introduce 'TriviaTraits' in CodeGeneration, and manually set them for each trivia piece kind.
1 parent fd232f9 commit 12beca4

File tree

3 files changed

+119
-73
lines changed

3 files changed

+119
-73
lines changed

CodeGeneration/Sources/SyntaxSupport/Trivia.swift

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@
1212

1313
import SwiftSyntax
1414

15+
public struct TriviaTraits: OptionSet {
16+
public var rawValue: UInt8
17+
18+
public init(rawValue: UInt8) {
19+
self.rawValue = rawValue
20+
}
21+
22+
public static var whitespace: Self { .init(rawValue: 1 << 0) }
23+
public static var newline: Self { .init(rawValue: 1 << 1) }
24+
public static var spaceOrTab: Self { .init(rawValue: 1 << 2) }
25+
public static var comment: Self { .init(rawValue: 1 << 3) }
26+
}
27+
1528
public class Trivia {
1629
/// The name of the trivia.
1730
public let name: TokenSyntax
@@ -32,7 +45,7 @@ public class Trivia {
3245
/// Indicates if the trivia represents a comment.
3346
///
3447
/// If `true`, the trivia is some form of a comment in the Swift code.
35-
public let isComment: Bool
48+
public let traits: TriviaTraits
3649

3750
/// The name of the trivia in lowercase.
3851
public var lowerName: TokenSyntax { .identifier(lowercaseFirstWord(name: name.text)) }
@@ -60,16 +73,6 @@ public class Trivia {
6073
/// If `true`, the trivia is made up of multiple characters.
6174
public var isCollection: Bool { charactersLen > 0 }
6275

63-
/// Indicates if the trivia contains only whitespace characters.
64-
public var isBlank: Bool {
65-
characters.contains { $0.isWhitespace }
66-
}
67-
68-
/// Indicates if the trivia contains newline characters.
69-
public var isNewLine: Bool {
70-
characters.contains { $0.isNewline }
71-
}
72-
7376
/// Initializes a new `Trivia` instance.
7477
///
7578
/// - Parameters:
@@ -83,12 +86,12 @@ public class Trivia {
8386
comment: SwiftSyntax.Trivia,
8487
characters: [Character] = [],
8588
swiftCharacters: [Character] = [],
86-
isComment: Bool = false
89+
traits: TriviaTraits = []
8790
) {
8891
self.name = name
8992
self.comment = comment
90-
self.isComment = isComment
9193
self.characters = characters
94+
self.traits = traits
9295

9396
// Swift sometimes doesn't support escaped characters like \f or \v;
9497
// we should allow specifying alternatives explicitly.
@@ -115,7 +118,7 @@ public let TRIVIAS: [Trivia] = [
115118
Trivia(
116119
name: "BlockComment",
117120
comment: #"A developer block comment, starting with '/*' and ending with '*/'."#,
118-
isComment: true
121+
traits: [.comment]
119122
),
120123

121124
Trivia(
@@ -126,7 +129,8 @@ public let TRIVIAS: [Trivia] = [
126129
],
127130
swiftCharacters: [
128131
Character("\r")
129-
]
132+
],
133+
traits: [.whitespace, .newline]
130134
),
131135

132136
Trivia(
@@ -139,19 +143,20 @@ public let TRIVIAS: [Trivia] = [
139143
swiftCharacters: [
140144
Character("\r"),
141145
Character("\n"),
142-
]
146+
],
147+
traits: [.whitespace, .newline]
143148
),
144149

145150
Trivia(
146151
name: "DocBlockComment",
147152
comment: #"A documentation block comment, starting with '/**' and ending with '*/'."#,
148-
isComment: true
153+
traits: [.comment]
149154
),
150155

151156
Trivia(
152157
name: "DocLineComment",
153158
comment: #"A documentation line comment, starting with '///' and excluding the trailing newline."#,
154-
isComment: true
159+
traits: [.comment]
155160
),
156161

157162
// Swift don't support form feed '\f' so we use the raw unicode
@@ -163,13 +168,14 @@ public let TRIVIAS: [Trivia] = [
163168
],
164169
swiftCharacters: [
165170
Character("\u{240C}")
166-
]
171+
],
172+
traits: [.whitespace]
167173
),
168174

169175
Trivia(
170176
name: "LineComment",
171177
comment: #"A developer line comment, starting with '//' and excluding the trailing newline."#,
172-
isComment: true
178+
traits: [.comment]
173179
),
174180

175181
Trivia(
@@ -180,7 +186,8 @@ public let TRIVIAS: [Trivia] = [
180186
],
181187
swiftCharacters: [
182188
Character("\n")
183-
]
189+
],
190+
traits: [.whitespace, .newline]
184191
),
185192

186193
Trivia(
@@ -202,7 +209,8 @@ public let TRIVIAS: [Trivia] = [
202209
],
203210
swiftCharacters: [
204211
Character(" ")
205-
]
212+
],
213+
traits: [.whitespace, .spaceOrTab]
206214
),
207215

208216
Trivia(
@@ -213,7 +221,8 @@ public let TRIVIAS: [Trivia] = [
213221
],
214222
swiftCharacters: [
215223
Character("\t")
216-
]
224+
],
225+
traits: [.whitespace, .spaceOrTab]
217226
),
218227

219228
Trivia(
@@ -230,6 +239,7 @@ public let TRIVIAS: [Trivia] = [
230239
],
231240
swiftCharacters: [
232241
Character("\u{2B7F}")
233-
]
242+
],
243+
traits: [.whitespace]
234244
),
235245
]

CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/TriviaPiecesFile.swift

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -271,58 +271,52 @@ let triviaPiecesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
271271
}
272272

273273
fileprivate func generateIsHelpers(for pieceName: TokenSyntax) throws -> ExtensionDeclSyntax {
274-
return try ExtensionDeclSyntax("extension \(pieceName)") {
275-
DeclSyntax(
276-
"""
277-
/// Returns `true` if this piece is a newline, space or tab.
278-
public var isWhitespace: Bool {
279-
return isSpaceOrTab || isNewline
280-
}
281-
"""
282-
)
283-
284-
try VariableDeclSyntax("public var isNewline: Bool") {
274+
func generateHelper(_ header: SyntaxNodeString, trait: TriviaTraits) throws -> VariableDeclSyntax {
275+
try VariableDeclSyntax(header) {
285276
try SwitchExprSyntax("switch self") {
286-
for trivia in TRIVIAS {
287-
if trivia.isNewLine {
288-
SwitchCaseSyntax("case .\(trivia.enumCaseName):") {
289-
StmtSyntax("return true")
290-
}
277+
for trivia in TRIVIAS where trivia.traits.contains(trait) {
278+
SwitchCaseSyntax("case .\(trivia.enumCaseName):") {
279+
StmtSyntax("return true")
291280
}
292281
}
293282
SwitchCaseSyntax("default:") {
294283
StmtSyntax("return false")
295284
}
296285
}
297286
}
287+
}
288+
289+
return try ExtensionDeclSyntax("extension \(pieceName)") {
290+
try generateHelper(
291+
"""
292+
/// Returns `true` if this piece is a whitespace.
293+
public var isWhitespace: Bool
294+
""",
295+
trait: .whitespace
296+
)
298297

299-
DeclSyntax(
298+
try generateHelper(
300299
"""
301-
public var isSpaceOrTab: Bool {
302-
switch self {
303-
case .spaces:
304-
return true
305-
case .tabs:
306-
return true
307-
default:
308-
return false
309-
}
310-
}
300+
/// Returns `true` if this piece is a newline, space or tab.
301+
public var isNewline: Bool
302+
""",
303+
trait: .newline
304+
)
305+
306+
try generateHelper(
311307
"""
308+
/// Returns `true` if this piece is a space or tab.
309+
public var isSpaceOrTab: Bool
310+
""",
311+
trait: .spaceOrTab
312312
)
313313

314-
DeclSyntax(
314+
try generateHelper(
315315
"""
316316
/// Returns `true` if this piece is a comment.
317-
public var isComment: Bool {
318-
switch self {
319-
case .lineComment, .blockComment, .docLineComment, .docBlockComment:
320-
return true
321-
default:
322-
return false
323-
}
324-
}
325-
"""
317+
public var isComment: Bool
318+
""",
319+
trait: .comment
326320
)
327321
}
328322
}

Sources/SwiftSyntax/generated/TriviaPieces.swift

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -443,12 +443,8 @@ extension RawTriviaPiece {
443443
}
444444

445445
extension TriviaPiece {
446-
/// Returns `true` if this piece is a newline, space or tab.
446+
/// Returns `true` if this piece is a whitespace.
447447
public var isWhitespace: Bool {
448-
return isSpaceOrTab || isNewline
449-
}
450-
451-
public var isNewline: Bool {
452448
switch self {
453449
case .carriageReturns:
454450
return true
@@ -458,13 +454,32 @@ extension TriviaPiece {
458454
return true
459455
case .newlines:
460456
return true
457+
case .spaces:
458+
return true
459+
case .tabs:
460+
return true
461461
case .verticalTabs:
462462
return true
463463
default:
464464
return false
465465
}
466466
}
467467

468+
/// Returns `true` if this piece is a newline, space or tab.
469+
public var isNewline: Bool {
470+
switch self {
471+
case .carriageReturns:
472+
return true
473+
case .carriageReturnLineFeeds:
474+
return true
475+
case .newlines:
476+
return true
477+
default:
478+
return false
479+
}
480+
}
481+
482+
/// Returns `true` if this piece is a space or tab.
468483
public var isSpaceOrTab: Bool {
469484
switch self {
470485
case .spaces:
@@ -479,7 +494,13 @@ extension TriviaPiece {
479494
/// Returns `true` if this piece is a comment.
480495
public var isComment: Bool {
481496
switch self {
482-
case .lineComment, .blockComment, .docLineComment, .docBlockComment:
497+
case .blockComment:
498+
return true
499+
case .docBlockComment:
500+
return true
501+
case .docLineComment:
502+
return true
503+
case .lineComment:
483504
return true
484505
default:
485506
return false
@@ -488,12 +509,8 @@ extension TriviaPiece {
488509
}
489510

490511
extension RawTriviaPiece {
491-
/// Returns `true` if this piece is a newline, space or tab.
512+
/// Returns `true` if this piece is a whitespace.
492513
public var isWhitespace: Bool {
493-
return isSpaceOrTab || isNewline
494-
}
495-
496-
public var isNewline: Bool {
497514
switch self {
498515
case .carriageReturns:
499516
return true
@@ -503,13 +520,32 @@ extension RawTriviaPiece {
503520
return true
504521
case .newlines:
505522
return true
523+
case .spaces:
524+
return true
525+
case .tabs:
526+
return true
506527
case .verticalTabs:
507528
return true
508529
default:
509530
return false
510531
}
511532
}
512533

534+
/// Returns `true` if this piece is a newline, space or tab.
535+
public var isNewline: Bool {
536+
switch self {
537+
case .carriageReturns:
538+
return true
539+
case .carriageReturnLineFeeds:
540+
return true
541+
case .newlines:
542+
return true
543+
default:
544+
return false
545+
}
546+
}
547+
548+
/// Returns `true` if this piece is a space or tab.
513549
public var isSpaceOrTab: Bool {
514550
switch self {
515551
case .spaces:
@@ -524,7 +560,13 @@ extension RawTriviaPiece {
524560
/// Returns `true` if this piece is a comment.
525561
public var isComment: Bool {
526562
switch self {
527-
case .lineComment, .blockComment, .docLineComment, .docBlockComment:
563+
case .blockComment:
564+
return true
565+
case .docBlockComment:
566+
return true
567+
case .docLineComment:
568+
return true
569+
case .lineComment:
528570
return true
529571
default:
530572
return false

0 commit comments

Comments
 (0)