Skip to content

Commit e5718e0

Browse files
committed
Breakdown comment blocks with new lines
This also keeps comment lines within comment blocks with their leading comment markers in tact
1 parent e8cd9f9 commit e5718e0

File tree

3 files changed

+147
-30
lines changed

3 files changed

+147
-30
lines changed

Sources/SwiftSyntax/Trivia.swift

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,7 @@ public struct Trivia: Sendable {
4646
///
4747
/// Each element in the array is the trimmed contents of a line comment, or, in the case of a multi-line comment a trimmed, concatenated single string.
4848
public var commentValues: [String] {
49-
[
50-
sanitizedLineCommentValues,
51-
sanitizedBlockCommentValues,
52-
].flatMap { $0 }
49+
sanitizedBlockCommentValues
5350
}
5451

5552
/// The length of all the pieces in this ``Trivia``.
@@ -227,43 +224,49 @@ extension RawTriviaPiece: CustomDebugStringConvertible {
227224
}
228225

229226
private extension Trivia {
230-
var sanitizedLineCommentValues: [String] {
231-
compactMap {
232-
switch $0 {
233-
case .lineComment(let text), .docLineComment(let text):
234-
String(sanitizingLineComment(text))
235-
236-
default:
237-
nil
238-
}
239-
}
240-
}
241-
242-
func sanitizingLineComment(_ text: String) -> Substring {
243-
text.trimmingPrefix("/ ")
244-
}
245-
246227
var sanitizedBlockCommentValues: [String] {
228+
// TODO: adammcarter - make new hashable struct to identify pieces instead of relying on indexes to remove later on...
229+
247230
var lines = [String]()
248-
var substrings = [Substring]()
249-
var foundTerminator = false
231+
var substrings = [String]()
250232

251-
for piece in self {
233+
var foundStartOfCodeBlock = false
234+
var foundEndOfCodeBlock = false
235+
var isInCodeBlock: Bool { foundStartOfCodeBlock && foundEndOfCodeBlock == false }
236+
237+
for piece in pieces {
252238
switch piece {
253-
case .blockComment(let text), .docBlockComment(let text):
254-
let sanitized = text.trimmingCharacters(in: "/* ")
239+
case .blockComment(let text),
240+
.docBlockComment(let text):
241+
foundStartOfCodeBlock = text.trimmingPrefix("\n").hasPrefix("/*")
242+
foundEndOfCodeBlock = text.trimmingSuffix("\n").hasSuffix("*/")
243+
244+
let sanitized =
245+
text
246+
.split(separator: "\n")
247+
.map { $0.trimmingCharacters(in: "/*").trimmingCharacters(in: " ") }
248+
.filter { $0.isEmpty == false }
249+
.joined(separator: " ")
255250

256251
if substrings.isEmpty || sanitized.isEmpty == false {
257252
substrings.append(sanitized)
258253
}
259254

260-
foundTerminator = text.hasSuffix("*/")
255+
case .lineComment(let text),
256+
.docLineComment(let text):
257+
if isInCodeBlock {
258+
if substrings.isEmpty || text.isEmpty == false {
259+
substrings.append(text)
260+
}
261+
} else {
262+
lines.append(String(text.trimmingPrefix("/ ")))
263+
}
261264

262265
default:
263266
break
264267
}
265268

266-
if foundTerminator, substrings.isEmpty == false {
269+
if foundEndOfCodeBlock, substrings.isEmpty == false {
267270
lines.append(substrings.joined(separator: " "))
268271
substrings.removeAll()
269272
}

Sources/SwiftSyntax/Utils.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ extension RawUnexpectedNodesSyntax {
124124
extension String {
125125
func trimmingCharacters(in charactersToTrim: any BidirectionalCollection<Character>) -> Substring {
126126
// TODO: adammcarter - this feels a bit dirty
127-
self[startIndex...].trimmingPrefix(charactersToTrim).trimmingSuffix(charactersToTrim)
127+
self[startIndex...].trimmingCharacters(in: charactersToTrim)
128128
}
129129

130130
func trimmingPrefix(_ charactersToTrim: any BidirectionalCollection<Character>) -> Substring {
@@ -137,6 +137,10 @@ extension String {
137137
}
138138

139139
extension Substring {
140+
func trimmingCharacters(in charactersToTrim: any BidirectionalCollection<Character>) -> Substring {
141+
trimmingPrefix(charactersToTrim).trimmingSuffix(charactersToTrim)
142+
}
143+
140144
func trimmingPrefix(_ charactersToTrim: any BidirectionalCollection<Character>) -> Self {
141145
dropFirst(countOfSequentialCharacters(charactersToTrim, in: self))
142146
}

Tests/SwiftSyntaxTest/TriviaTests.swift

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,34 @@ class TriviaTests: XCTestCase {
214214
]
215215
)
216216

217+
XCTAssertEqual(
218+
Trivia(pieces: [
219+
.blockComment(
220+
"""
221+
/*
222+
Some block comment
223+
spread on many lines
224+
*/
225+
"""
226+
)
227+
]).commentValues,
228+
["Some block comment spread on many lines"]
229+
)
230+
231+
XCTAssertEqual(
232+
Trivia(pieces: [
233+
.blockComment(
234+
"""
235+
/*
236+
* Some block comment
237+
* spread on many lines
238+
*/
239+
"""
240+
)
241+
]).commentValues,
242+
["Some block comment spread on many lines"]
243+
)
244+
217245
// MARK: doc block comment
218246

219247
XCTAssertEqual(
@@ -277,7 +305,89 @@ class TriviaTests: XCTestCase {
277305
]
278306
)
279307

280-
// TODO: adammcarter - mixing trivia of lines and blocks
281-
// TODO: adammcarter - newline chars in the prefix/suffix of code block too
308+
XCTAssertEqual(
309+
Trivia(pieces: [
310+
.docBlockComment(
311+
"""
312+
/**
313+
Some doc block comment
314+
spread on many lines
315+
*/
316+
"""
317+
)
318+
]).commentValues,
319+
["Some doc block comment spread on many lines"]
320+
)
321+
322+
XCTAssertEqual(
323+
Trivia(pieces: [
324+
.docBlockComment(
325+
"""
326+
/**
327+
* Some doc block comment
328+
* spread on many lines
329+
*/
330+
"""
331+
)
332+
]).commentValues,
333+
["Some doc block comment spread on many lines"]
334+
)
335+
336+
// MARK: Mixing comment styles
337+
338+
XCTAssertEqual(
339+
Trivia(pieces: [
340+
.docBlockComment(
341+
"""
342+
/**
343+
* Some doc block comment
344+
* // spread on many lines
345+
* with a line comment
346+
*/
347+
"""
348+
)
349+
]).commentValues,
350+
["Some doc block comment // spread on many lines with a line comment"]
351+
)
352+
353+
XCTAssertEqual(
354+
Trivia(pieces: [
355+
.docBlockComment("/** Some doc block comment"),
356+
.docBlockComment("* spread on many lines */"),
357+
.newlines(2),
358+
.docLineComment("/// Some doc line comment"),
359+
.docLineComment("// Some line comment"),
360+
.newlines(2),
361+
.spaces(4),
362+
.blockComment("/* Some block comment"),
363+
.blockComment("* spread on many lines */"),
364+
.newlines(2),
365+
.docBlockComment("/** Another doc block comment */"),
366+
]).commentValues,
367+
[
368+
"Some doc block comment spread on many lines",
369+
"Some doc line comment",
370+
"Some line comment",
371+
"Some block comment spread on many lines",
372+
"Another doc block comment",
373+
]
374+
)
375+
376+
XCTAssertEqual(
377+
Trivia(pieces: [
378+
.docBlockComment("/* Some block comment"),
379+
.docLineComment("// A line comment in a block"),
380+
.docBlockComment("* spread on many lines */"),
381+
.newlines(2),
382+
.blockComment("/** Some doc block comment"),
383+
.docLineComment("/// A doc line comment in a block"),
384+
.blockComment("* spread on"),
385+
.blockComment("* many lines */"),
386+
]).commentValues,
387+
[
388+
"Some block comment // A line comment in a block spread on many lines",
389+
"Some doc block comment /// A doc line comment in a block spread on many lines",
390+
]
391+
)
282392
}
283393
}

0 commit comments

Comments
 (0)