Skip to content

Commit 52fdc83

Browse files
committed
Address fourth review
1 parent 312bbc9 commit 52fdc83

File tree

2 files changed

+98
-102
lines changed

2 files changed

+98
-102
lines changed

Sources/SwiftSyntax/Trivia.swift

+71-35
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ public struct Trivia: Sendable {
4343
}
4444

4545
/// The string contents of all the comment pieces with any comments tokens trimmed.
46-
public var commentValue: String {
46+
public var commentValue: String? {
4747
var comments = [Substring]()
48+
var hasBlockComment = false
49+
var hasLineComment = false
4850

4951
// Determine if all line comments have a single space
5052
lazy var allLineCommentsHaveSpace: Bool = {
@@ -62,79 +64,113 @@ public struct Trivia: Sendable {
6264

6365
// Returns a substring with leading and trailing spaces removed.
6466
func trimWhitespace(_ text: Substring) -> Substring {
65-
let trimmed = text.drop(while: { $0 == " " })
66-
let reversed = trimmed.reversed()
67-
let trimmedEnd = reversed.drop(while: { $0 == " " })
68-
let final = trimmedEnd.reversed()
69-
return Substring(final)
67+
let trimmed = text.drop(while: { $0 == " " })
68+
let reversed = trimmed.reversed()
69+
let trimmedEnd = reversed.drop(while: { $0 == " " })
70+
let final = trimmedEnd.reversed()
71+
return Substring(final)
7072
}
7173

7274
// Strips /* */ markers and aligns content by removing common indentation.
7375
func processBlockComment(_ text: Substring) -> String {
7476
var lines = text.split(separator: "\n", omittingEmptySubsequences: false)
7577

76-
let minIndentation =
78+
let (minSpaceIndentation, minTabIndentation) =
7779
lines
7880
.dropFirst()
7981
.filter { !$0.isEmpty }
80-
.map { $0.prefix { $0 == " " }.count }
81-
.min() ?? 0
82-
83-
var firstLineRemoved = false;
84-
var firstLine = lines[0]
85-
if trimWhitespace(firstLine) == "/*" || trimWhitespace(firstLine) == "/**" {
86-
lines.removeFirst()
87-
firstLineRemoved = true;
88-
} else {
89-
firstLine = firstLine.hasPrefix("/**") ? firstLine.dropFirst(3) : firstLine.dropFirst(2)
90-
while firstLine.first?.isWhitespace == true {
91-
firstLine = firstLine.dropFirst()
82+
.reduce((Int.max, Int.max)) { (currentMin, line) in
83+
var spaceCount = 0, tabCount = 0
84+
var inLeadingWhitespace = true
85+
86+
for char in line {
87+
guard inLeadingWhitespace else { break }
88+
89+
switch char {
90+
case " ":
91+
spaceCount += 1
92+
case "\t":
93+
tabCount += 1
94+
default:
95+
inLeadingWhitespace = false
96+
}
9297
}
93-
lines[0] = firstLine
98+
99+
return (Swift.min(currentMin.0, spaceCount), Swift.min(currentMin.1, tabCount))
100+
}
101+
102+
var minIndentation = minSpaceIndentation == Int.max ? 0 : minSpaceIndentation
103+
minIndentation += minTabIndentation == Int.max ? 0 : minTabIndentation
104+
105+
if let first = lines.first {
106+
let prefixToDrop = first.hasPrefix("/**") ? 3 : 2
107+
lines[0] = first.dropFirst(prefixToDrop)
94108
}
95-
96-
if let lastLine = lines.last {
97-
if trimWhitespace(lastLine) == "*/" {
98-
lines.removeLast()
99-
} else {
100-
var lastLine = lines[lines.count - 1]
101-
lastLine = lastLine.hasSuffix("*/") ? lastLine.dropLast(2) : lastLine
102-
while lastLine.last?.isWhitespace == true {
103-
lastLine = lastLine.dropLast()
104-
}
105-
lines[lines.count - 1] = lastLine
106-
}
109+
110+
var firstLineRemoved = false
111+
if trimWhitespace(lines[0]).isEmpty {
112+
lines.removeFirst()
113+
firstLineRemoved = true
107114
}
108115

109-
let unindentedLines = lines.enumerated().map { index, line -> Substring in
116+
var unindentedLines = lines.enumerated().map { index, line -> Substring in
110117
if index == 0 && firstLineRemoved == false {
111-
return line
118+
return line
112119
}
113120
return line.count >= minIndentation ? line.dropFirst(minIndentation) : line
114121
}
115122

123+
if let last = unindentedLines.last, last.hasSuffix("*/") {
124+
unindentedLines[unindentedLines.count - 1] = last.dropLast(2)
125+
}
126+
127+
if trimWhitespace(unindentedLines[unindentedLines.count - 1]).isEmpty {
128+
unindentedLines.removeLast()
129+
}
130+
116131
return unindentedLines.joined(separator: "\n")
117132
}
118133

119134
for piece in pieces {
120135
switch piece {
121136
case .blockComment(let text), .docBlockComment(let text):
137+
if hasBlockComment || hasLineComment {
138+
return nil
139+
}
140+
hasBlockComment = true
122141
let processedText = processBlockComment(text[...])
123142
comments.append(processedText[...])
124143

125144
case .lineComment(let text):
145+
if hasBlockComment {
146+
return nil
147+
}
148+
hasLineComment = true
126149
let prefix = allLineCommentsHaveSpace ? "// " : "//"
127150
comments.append(text.dropFirst(prefix.count))
128151

129152
case .docLineComment(let text):
153+
if hasBlockComment {
154+
return nil
155+
}
156+
hasLineComment = true
130157
let prefix = allLineCommentsHaveSpace ? "/// " : "///"
131158
comments.append(text.dropFirst(prefix.count))
132159

133160
default:
134161
break
135162
}
136163
}
137-
return comments.joined(separator: "\n")
164+
165+
guard !comments.isEmpty else { return nil }
166+
167+
// If we have multiple line comments, they can be joined with newlines
168+
if hasLineComment {
169+
return comments.joined(separator: "\n")
170+
}
171+
172+
// In case of block comments, we should only have one
173+
return comments.first.map(String.init)
138174
}
139175

140176
/// The length of all the pieces in this ``Trivia``.

Tests/SwiftSyntaxTest/TriviaTests.swift

+27-67
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,14 @@ class TriviaTests: XCTestCase {
152152

153153
// MARK: Block comment
154154

155-
assertCommentValue("/* Some block comment */", commentValue: "Some block comment")
155+
assertCommentValue("/* Some block comment */", commentValue: " Some block comment ")
156156

157157
assertCommentValue(
158158
"""
159159
/* Some block comment
160160
* spread on many lines */
161161
""",
162-
commentValue: "Some block comment\n* spread on many lines"
162+
commentValue: " Some block comment\n* spread on many lines "
163163
)
164164

165165
assertCommentValue(
@@ -168,7 +168,7 @@ class TriviaTests: XCTestCase {
168168
* spread on many lines
169169
*/
170170
""",
171-
commentValue: "Some block comment\n* spread on many lines"
171+
commentValue: " Some block comment\n* spread on many lines"
172172
)
173173

174174
assertCommentValue(
@@ -177,26 +177,7 @@ class TriviaTests: XCTestCase {
177177
Some block comment
178178
spread on many lines */
179179
""",
180-
commentValue: "Some block comment\nspread on many lines"
181-
)
182-
183-
assertCommentValue(
184-
"""
185-
/* Some block comment
186-
* spread on many lines */
187-
/* Another block comment */
188-
""",
189-
commentValue: "Some block comment\n* spread on many lines\nAnother block comment"
190-
)
191-
192-
assertCommentValue(
193-
"""
194-
/* Some block comment
195-
* spread on many lines */
196-
197-
/* Another block comment */
198-
""",
199-
commentValue: "Some block comment\n* spread on many lines\nAnother block comment"
180+
commentValue: "Some block comment\nspread on many lines "
200181
)
201182

202183
assertCommentValue(
@@ -229,7 +210,7 @@ class TriviaTests: XCTestCase {
229210
commentValue: "/abc"
230211
)
231212

232-
assertCommentValue("/* ///// abc */", commentValue: "///// abc")
213+
assertCommentValue("/* ///// abc */", commentValue: " ///// abc ")
233214

234215
assertCommentValue(
235216
"""
@@ -266,51 +247,51 @@ class TriviaTests: XCTestCase {
266247
Comment
267248
Comment */
268249
""",
269-
commentValue: "Comment\n Comment")
270-
271-
// MARK: Doc block comment
250+
commentValue: "Comment\n Comment "
251+
)
272252

273253
assertCommentValue(
274254
"""
275-
/** Some doc block comment */
255+
/*
256+
\t\tComment
257+
\t\t\tComment */
276258
""",
277-
commentValue: "Some doc block comment"
259+
commentValue: "Comment\n\tComment "
278260
)
279261

280262
assertCommentValue(
281263
"""
282-
/** Some doc block comment
283-
* spread on many lines */
264+
/*
265+
\t\tComment
266+
\t\t\tComment */
284267
""",
285-
commentValue: "Some doc block comment\n* spread on many lines"
268+
commentValue: "\tComment\n\tComment "
286269
)
287270

271+
// MARK: Doc block comment
272+
288273
assertCommentValue(
289274
"""
290-
/** Some doc block comment
291-
* spread on many lines
292-
*/
275+
/** Some doc block comment */
293276
""",
294-
commentValue: "Some doc block comment\n* spread on many lines"
277+
commentValue: " Some doc block comment "
295278
)
296279

297280
assertCommentValue(
298281
"""
299282
/** Some doc block comment
300283
* spread on many lines */
301-
/** Another doc block comment */
302284
""",
303-
commentValue: "Some doc block comment\n* spread on many lines\nAnother doc block comment"
285+
commentValue: " Some doc block comment\n* spread on many lines "
304286
)
305287

306288
assertCommentValue(
307289
"""
308290
/** Some doc block comment
309-
* spread on many lines */
310-
311-
/** Another doc block comment */
291+
* spread on many lines
292+
*/
312293
""",
313-
commentValue: "Some doc block comment\n* spread on many lines\nAnother doc block comment"
294+
commentValue: " Some doc block comment\n* spread on many lines"
314295
)
315296

316297
assertCommentValue(
@@ -343,7 +324,7 @@ class TriviaTests: XCTestCase {
343324
commentValue: "* Some doc block comment\n* with a line comment"
344325
)
345326

346-
assertCommentValue("/** ///// abc */", commentValue: "///// abc")
327+
assertCommentValue("/** ///// abc */", commentValue: " ///// abc ")
347328

348329
assertCommentValue(
349330
"""
@@ -396,20 +377,8 @@ class TriviaTests: XCTestCase {
396377
397378
/// Some doc line comment
398379
// Some line comment
399-
400-
/* Some block comment
401-
* spread on many lines */
402-
/** Another doc block comment */
403380
""",
404-
commentValue: """
405-
Some doc block comment
406-
* spread on many lines
407-
Some doc line comment
408-
Some line comment
409-
Some block comment
410-
* spread on many lines
411-
Another doc block comment
412-
"""
381+
commentValue: nil
413382
)
414383

415384
assertCommentValue(
@@ -418,26 +387,17 @@ class TriviaTests: XCTestCase {
418387
* // A line comment in a block
419388
* spread on many lines */
420389
/** Some doc block comment
421-
* /// A doc line comment in a block
422390
* spread on
423391
* many lines */
424392
""",
425-
commentValue: """
426-
Some block comment
427-
* // A line comment in a block
428-
* spread on many lines
429-
Some doc block comment
430-
* /// A doc line comment in a block
431-
* spread on
432-
* many lines
433-
"""
393+
commentValue: nil
434394
)
435395
}
436396
}
437397

438398
func assertCommentValue(
439399
_ input: String,
440-
commentValue expected: String,
400+
commentValue expected: String?,
441401
file: StaticString = #filePath,
442402
line: UInt = #line
443403
) {

0 commit comments

Comments
 (0)