Skip to content

Commit b0a8d9a

Browse files
authored
Merge pull request #92 from allevato/decl-trailing-comments
Handle end-of-line comments correctly in BlankLineBetweenMembers.
2 parents dd6ec9e + 142e160 commit b0a8d9a

File tree

4 files changed

+61
-5
lines changed

4 files changed

+61
-5
lines changed

Sources/SwiftFormatCore/Syntax+Convenience.swift

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,19 @@ extension Syntax {
4444
// Iterate over the trivia, stopping at the first comment, and using that as the start
4545
// position.
4646
var currentPosition = firstToken.position
47-
for piece in firstToken.leadingTrivia {
47+
var sawNewline = false
48+
loop: for piece in firstToken.leadingTrivia {
4849
switch piece {
49-
case .lineComment, .blockComment, .docLineComment, .docBlockComment:
50-
break
50+
case .docLineComment,
51+
.docBlockComment,
52+
.lineComment where sawNewline,
53+
.blockComment where sawNewline:
54+
// Non-doc line or block comments before we've seen the first newline should actually be
55+
// considered trailing comments of the previous line.
56+
break loop
57+
case .newlines, .carriageReturns, .carriageReturnLineFeeds:
58+
sawNewline = true
59+
fallthrough
5160
default:
5261
currentPosition += piece.sourceLength
5362
}

Sources/SwiftFormatRules/BlankLineBetweenMembers.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,10 @@ public final class BlankLineBetweenMembers: SyntaxFormatRule {
6161

6262
let ignoreMember = ignoreSingleLine && isMemberSingleLine
6363
if (!previousMemberWasSingleLine || !ignoreMember) && !isLeadingBlankLinePresent(on: member) {
64-
let blankLinePrefacedTrivia = Trivia.newlines(1) + (member.leadingTrivia ?? [])
6564
memberToAdd = replaceTrivia(
6665
on: memberToAdd,
6766
token: memberToAdd.firstToken,
68-
leadingTrivia: blankLinePrefacedTrivia
67+
leadingTrivia: blankLinePrefixedTrivia(member.leadingTrivia)
6968
) as! MemberDeclListItemSyntax
7069
diagnose(.addBlankLine, on: member)
7170
}
@@ -80,6 +79,26 @@ public final class BlankLineBetweenMembers: SyntaxFormatRule {
8079
return node.withMembers(SyntaxFactory.makeMemberDeclList(membersList))
8180
}
8281

82+
/// Returns new trivia with a blank line inserted at the "beginning" of the given trivia, but
83+
/// respecting any end-of-line comments associated with the previous line that may be present.
84+
private func blankLinePrefixedTrivia(_ trivia: Trivia?) -> Trivia {
85+
guard let trivia = trivia else { return .newlines(1) }
86+
87+
guard let firstNewlineIndex = trivia.firstIndex(where: {
88+
switch $0 {
89+
case .newlines, .carriageReturns, .carriageReturnLineFeeds:
90+
return true
91+
default:
92+
return false
93+
}
94+
}) else {
95+
return .newlines(1) + trivia
96+
}
97+
98+
let newPieces = trivia[..<firstNewlineIndex] + [.newlines(1)] + trivia[firstNewlineIndex...]
99+
return Trivia(pieces: newPieces).condensed()
100+
}
101+
83102
/// Returns whether any comments in the leading trivia of the given node are separated from the
84103
/// non-trivia tokens by at least 1 blank line.
85104
private func isLeadingTriviaSeparate(from node: Syntax) -> Bool {

Tests/SwiftFormatRulesTests/BlankLineBetweenMembersTests.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,4 +335,31 @@ public class BlankLineBetweenMembersTests: DiagnosingTestCase {
335335
expected: expected,
336336
configuration: config)
337337
}
338+
339+
func testTrailingCommentsAreKeptTrailing() {
340+
XCTAssertFormatting(
341+
BlankLineBetweenMembers.self,
342+
input:
343+
"""
344+
enum Foo {
345+
static let foo = "foo" // foo
346+
static let bar = "bar" // bar
347+
// this should move down
348+
static let baz = "baz" // baz
349+
static let andSo = "should" // this
350+
}
351+
""",
352+
expected:
353+
"""
354+
enum Foo {
355+
static let foo = "foo" // foo
356+
static let bar = "bar" // bar
357+
358+
// this should move down
359+
static let baz = "baz" // baz
360+
361+
static let andSo = "should" // this
362+
}
363+
""")
364+
}
338365
}

Tests/SwiftFormatRulesTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ extension BlankLineBetweenMembersTests {
5050
("testInvalidBlankLineBetweenMembers", testInvalidBlankLineBetweenMembers),
5151
("testNestedMembers", testNestedMembers),
5252
("testNoBlankLineBetweenSingleLineMembers", testNoBlankLineBetweenSingleLineMembers),
53+
("testTrailingCommentsAreKeptTrailing", testTrailingCommentsAreKeptTrailing),
5354
("testTwoMembers", testTwoMembers),
5455
]
5556
}

0 commit comments

Comments
 (0)