Skip to content

Commit f555ff9

Browse files
authored
Merge pull request swiftlang#191 from google/format-fix-accessor-spaces
Remove extra spaces inside empty accessor blocks and accessor decls.
2 parents 290a28c + fcebea0 commit f555ff9

File tree

2 files changed

+134
-47
lines changed

2 files changed

+134
-47
lines changed

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

+76-47
Original file line numberDiff line numberDiff line change
@@ -223,27 +223,12 @@ private final class TokenStreamCreator: SyntaxVisitor {
223223
}
224224

225225
override func visit(_ node: SubscriptDeclSyntax) {
226-
let bodyContentsAreEmpty: Bool
227-
if let accessor = node.accessor {
228-
if let accessorList = accessor.accessorListOrStmtList as? AccessorListSyntax {
229-
bodyContentsAreEmpty = accessorList.isEmpty
230-
} else if let stmtList = accessor.accessorListOrStmtList as? CodeBlockItemListSyntax {
231-
bodyContentsAreEmpty = stmtList.isEmpty
232-
} else {
233-
// We shouldn't get here because it should be one of the two above, but to be future-proof,
234-
// we'll use false if we see something else.
235-
bodyContentsAreEmpty = false
236-
}
237-
} else {
238-
bodyContentsAreEmpty = true
239-
}
240-
241226
arrangeFunctionLikeDecl(
242227
node,
243228
attributes: node.attributes,
244229
genericWhereClause: node.genericWhereClause,
245230
body: node.accessor,
246-
bodyContentsAreEmpty: bodyContentsAreEmpty)
231+
bodyContentsAreEmpty: isBodyEmpty(node.accessor))
247232

248233
before(node.result.firstToken, tokens: .break)
249234
super.visit(node)
@@ -304,6 +289,81 @@ private final class TokenStreamCreator: SyntaxVisitor {
304289
after(node.lastToken, tokens: .close)
305290
}
306291

292+
// MARK: - Property and subscript accessor block nodes
293+
294+
override func visit(_ node: AccessorBlockSyntax) {
295+
if !(node.parent is SubscriptDeclSyntax) {
296+
// The body may be free of other syntax nodes, but we still need to insert the breaks if it
297+
// contains a comment (which will be in the leading trivia of the right brace).
298+
let commentPrecedesRightBrace = node.rightBrace.leadingTrivia.numberOfComments > 0
299+
let isBodyCompletelyEmpty = isBodyEmpty(node) && !commentPrecedesRightBrace
300+
301+
if !isBodyCompletelyEmpty {
302+
after(node.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
303+
before(node.rightBrace, tokens: .break(offset: -2), .close)
304+
} else {
305+
// The size-0 break in the empty case allows for a break between the braces in the rare
306+
// event that the declaration would be exactly the column limit + 1.
307+
after(node.leftBrace, tokens: .break(size: 0))
308+
}
309+
}
310+
super.visit(node)
311+
}
312+
313+
override func visit(_ node: AccessorListSyntax) {
314+
if node.count > 1 {
315+
after(node.first?.lastToken, tokens: .break)
316+
}
317+
super.visit(node)
318+
}
319+
320+
override func visit(_ node: AccessorDeclSyntax) {
321+
before(node.firstToken, tokens: .space(size: 0), .open(.consistent, 0))
322+
323+
if let body = node.body {
324+
before(node.accessorKind, tokens: .open, .open)
325+
before(body.leftBrace, tokens: .break)
326+
327+
// The body may be free of other syntax nodes, but we still need to insert the breaks if it
328+
// contains a comment (which will be in the leading trivia of the right brace).
329+
let commentPrecedesRightBrace = body.rightBrace.leadingTrivia.numberOfComments > 0
330+
let isBodyCompletelyEmpty = body.statements.isEmpty && !commentPrecedesRightBrace
331+
332+
if !isBodyCompletelyEmpty {
333+
after(body.leftBrace, tokens: .close, .break(offset: 2), .open(.consistent, 0))
334+
before(body.rightBrace, tokens: .break(offset: -2), .close, .close)
335+
} else {
336+
// The size-0 break in the empty case allows for a break between the braces in the rare
337+
// event that the declaration would be exactly the column limit + 1.
338+
after(body.leftBrace, tokens: .close, .close, .break(size: 0))
339+
}
340+
}
341+
342+
after(node.lastToken, tokens: .close)
343+
super.visit(node)
344+
}
345+
346+
override func visit(_ node: AccessorParameterSyntax) {
347+
super.visit(node)
348+
}
349+
350+
/// Returns a value indicating whether the body of the accessor block (regardless of whether it
351+
/// contains accessors or statements) is empty.
352+
private func isBodyEmpty(_ node: AccessorBlockSyntax?) -> Bool {
353+
guard let node = node else { return true }
354+
355+
if let accessorList = node.accessorListOrStmtList as? AccessorListSyntax {
356+
return accessorList.isEmpty
357+
}
358+
if let stmtList = node.accessorListOrStmtList as? CodeBlockItemListSyntax {
359+
return stmtList.isEmpty
360+
}
361+
362+
// We shouldn't get here because it should be one of the two above, but to be future-proof,
363+
// we'll use false if we see something else.
364+
return false
365+
}
366+
307367
// TODO: - Other nodes (yet to be organized)
308368

309369
override func visit(_ node: DeclNameArgumentsSyntax) {
@@ -606,37 +666,6 @@ private final class TokenStreamCreator: SyntaxVisitor {
606666
super.visit(node)
607667
}
608668

609-
override func visit(_ node: AccessorParameterSyntax) {
610-
super.visit(node)
611-
}
612-
613-
override func visit(_ node: AccessorDeclSyntax) {
614-
before(node.firstToken, tokens: .space(size: 0), .open(.consistent, 0))
615-
if let body = node.body {
616-
before(node.accessorKind, tokens: .open, .open)
617-
before(body.leftBrace, tokens: .break)
618-
after(body.leftBrace, tokens: .close, .break(offset: 2), .open(.consistent, 0))
619-
before(body.rightBrace, tokens: .break(offset: -2), .close, .close)
620-
}
621-
after(node.lastToken, tokens: .close)
622-
super.visit(node)
623-
}
624-
625-
override func visit(_ node: AccessorBlockSyntax) {
626-
if !(node.parent is SubscriptDeclSyntax) {
627-
after(node.leftBrace, tokens: .break(offset: 2), .open(.consistent, 0))
628-
before(node.rightBrace, tokens: .break(offset: -2), .close)
629-
}
630-
super.visit(node)
631-
}
632-
633-
override func visit(_ node: AccessorListSyntax) {
634-
if node.count > 1 {
635-
after(node.first?.lastToken, tokens: .break)
636-
}
637-
super.visit(node)
638-
}
639-
640669
override func visit(_ node: CodeBlockSyntax) {
641670
insertToken(.break(size: maxlinelength), betweenChildrenOf: node.statements)
642671
super.visit(node)

Tests/SwiftFormatPrettyPrintTests/AccessorTests.swift

+58
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,62 @@ public class AccessorTests: PrettyPrintTestCase {
8686

8787
assertPrettyPrintEqual(input: input, expected: expected, linelength: 45)
8888
}
89+
90+
public func testEmptyAccessorList() {
91+
// The comment inside the struct prevents it from *also* being collapsed onto a single line.
92+
let input = """
93+
struct Foo {
94+
//
95+
var x: Int {}
96+
}
97+
"""
98+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 50)
99+
100+
let wrapped = """
101+
struct Foo {
102+
//
103+
var x: Int {
104+
}
105+
}
106+
107+
"""
108+
assertPrettyPrintEqual(input: input, expected: wrapped, linelength: 14)
109+
}
110+
111+
public func testEmptyAccessorBody() {
112+
// The comment inside the struct prevents it from *also* being collapsed onto a single line.
113+
let input = """
114+
struct Foo {
115+
//
116+
var x: Int { set(longNewValueName) {} }
117+
}
118+
"""
119+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 50)
120+
121+
let wrapped = """
122+
struct Foo {
123+
//
124+
var x: Int {
125+
set(longNewValueName) {
126+
}
127+
}
128+
}
129+
130+
"""
131+
assertPrettyPrintEqual(input: input, expected: wrapped, linelength: 27)
132+
}
133+
134+
public func testEmptyAccessorBodyWithComment() {
135+
let input = """
136+
struct Foo {
137+
//
138+
var x: Int {
139+
get {
140+
// comment
141+
}
142+
}
143+
}
144+
"""
145+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 50)
146+
}
89147
}

0 commit comments

Comments
 (0)