Skip to content

Commit 36df0fc

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 36df0fc

File tree

3 files changed

+177
-62
lines changed

3 files changed

+177
-62
lines changed

Diff for: Sources/SwiftSyntax/Trivia.swift

+56-55
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,62 @@ 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+
var comments = [String]()
50+
var partialComments = [String]()
51+
52+
var foundStartOfCodeBlock = false
53+
var foundEndOfCodeBlock = false
54+
var isInCodeBlock: Bool { foundStartOfCodeBlock && !foundEndOfCodeBlock }
55+
56+
for piece in pieces {
57+
switch piece {
58+
case .blockComment(let text), .docBlockComment(let text):
59+
let text = text.trimmingCharacters(in: "\n")
60+
61+
foundStartOfCodeBlock = text.hasPrefix("/*")
62+
foundEndOfCodeBlock = text.hasSuffix("*/")
63+
64+
let sanitized =
65+
text
66+
.split(separator: "\n")
67+
.map { $0.trimmingAnyCharacters(in: "/*").trimmingAnyCharacters(in: " ") }
68+
.filter { !$0.isEmpty }
69+
.joined(separator: " ")
70+
71+
appendPartialCommentIfPossible(sanitized)
72+
73+
case .lineComment(let text), .docLineComment(let text):
74+
if isInCodeBlock {
75+
appendPartialCommentIfPossible(text)
76+
} else {
77+
comments.append(String(text.trimmingPrefix("/ ")))
78+
}
79+
80+
default:
81+
break
82+
}
83+
84+
if foundEndOfCodeBlock, !partialComments.isEmpty {
85+
appendSubstringsToLines()
86+
partialComments.removeAll()
87+
}
88+
}
89+
90+
if !partialComments.isEmpty {
91+
appendSubstringsToLines()
92+
}
93+
94+
func appendPartialCommentIfPossible(_ text: String) {
95+
guard partialComments.isEmpty || !text.isEmpty else { return }
96+
97+
partialComments.append(text)
98+
}
99+
100+
func appendSubstringsToLines() {
101+
comments.append(partialComments.joined(separator: " "))
102+
}
103+
104+
return comments
53105
}
54106

55107
/// The length of all the pieces in this ``Trivia``.
@@ -225,54 +277,3 @@ extension RawTriviaPiece: CustomDebugStringConvertible {
225277
TriviaPiece(raw: self).debugDescription
226278
}
227279
}
228-
229-
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-
246-
var sanitizedBlockCommentValues: [String] {
247-
var lines = [String]()
248-
var substrings = [Substring]()
249-
var foundTerminator = false
250-
251-
for piece in self {
252-
switch piece {
253-
case .blockComment(let text), .docBlockComment(let text):
254-
let sanitized = text.trimmingCharacters(in: "/* ")
255-
256-
if substrings.isEmpty || sanitized.isEmpty == false {
257-
substrings.append(sanitized)
258-
}
259-
260-
foundTerminator = text.hasSuffix("*/")
261-
262-
default:
263-
break
264-
}
265-
266-
if foundTerminator, substrings.isEmpty == false {
267-
lines.append(substrings.joined(separator: " "))
268-
substrings.removeAll()
269-
}
270-
}
271-
272-
if substrings.isEmpty == false {
273-
lines.append(substrings.joined(separator: " "))
274-
}
275-
276-
return lines
277-
}
278-
}

Diff for: Sources/SwiftSyntax/Utils.swift

+9-5
Original file line numberDiff line numberDiff line change
@@ -124,24 +124,28 @@ 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...].trimmingAnyCharacters(in: charactersToTrim)
128128
}
129129

130130
func trimmingPrefix(_ charactersToTrim: any BidirectionalCollection<Character>) -> Substring {
131-
self[startIndex...].trimmingPrefix(charactersToTrim)
131+
self[startIndex...].trimmingAnyCharactersFromPrefix(in: charactersToTrim)
132132
}
133133

134134
func trimmingSuffix(_ charactersToTrim: any BidirectionalCollection<Character>) -> Substring {
135-
self[startIndex...].trimmingSuffix(charactersToTrim)
135+
self[startIndex...].trimmingAnyCharactersFromSuffix(in: charactersToTrim)
136136
}
137137
}
138138

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

144-
func trimmingSuffix(_ charactersToTrim: any BidirectionalCollection<Character>) -> Self {
148+
func trimmingAnyCharactersFromSuffix(in charactersToTrim: any BidirectionalCollection<Character>) -> Self {
145149
dropLast(countOfSequentialCharacters(charactersToTrim, in: reversed()))
146150
}
147151
}

Diff for: Tests/SwiftSyntaxTest/TriviaTests.swift

+112-2
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)