Skip to content

Commit 0e3e9d8

Browse files
committed
Transform nested structs in UseEnumForNamespacing.
The rule was not visiting any structs nested in other structs, because it wasn't calling super to visit the node's children. I tried to combine `super.visit` with the member enumeration in `membersToKeepIfUsedAsNamespace(_:)` but that method intentionally returns nil to signal that the decl shouldn't be rewritten which would discard the changes to the nested nodes. Instead, the rule now visits the members and uses the rewritten member list even if it's not converted to an enum to keep any changes to nested structs.
1 parent f9bd95a commit 0e3e9d8

File tree

4 files changed

+78
-5
lines changed

4 files changed

+78
-5
lines changed

Sources/SwiftFormatRules/UseEnumForNamespacing.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,18 @@ import SwiftSyntax
2929
public final class UseEnumForNamespacing: SyntaxFormatRule {
3030

3131
public override func visit(_ node: StructDeclSyntax) -> DeclSyntax {
32+
let rewrittenMembers = node.members.members.compactMap {
33+
super.visit($0).as(MemberDeclListItemSyntax.self)
34+
}
35+
guard rewrittenMembers.count == node.members.members.count else {
36+
// No members should be deleted - exit early instead of breaking the source.
37+
return DeclSyntax(node)
38+
}
39+
let rewrittenMemberDeclList = SyntaxFactory.makeMemberDeclList(rewrittenMembers)
3240
guard node.genericParameterClause == nil, node.inheritanceClause == nil,
33-
let memberDecls = membersToKeepIfUsedAsNamespace(node.members.members)
41+
let memberDecls = membersToKeepIfUsedAsNamespace(rewrittenMemberDeclList)
3442
else {
35-
return DeclSyntax(node)
43+
return DeclSyntax(node.withMembers(node.members.withMembers(rewrittenMemberDeclList)))
3644
}
3745

3846
diagnose(.convertToEnum(kind: "struct", name: node.identifier), on: node)
@@ -76,9 +84,11 @@ public final class UseEnumForNamespacing: SyntaxFormatRule {
7684
// Do not append private initializer.
7785

7886
case .ifConfigDecl(let decl):
79-
let membersToKeep: [MemberDeclListSyntax] = decl.clauses
80-
.compactMap { clause in
81-
(clause.elements.as(MemberDeclListSyntax.self)).flatMap(membersToKeepIfUsedAsNamespace(_:))
87+
// Note that the child nodes have already been rewritten, so any nested structs that should
88+
// become enums have already been transformed.
89+
let membersToKeep: [MemberDeclListSyntax] =
90+
decl.clauses.compactMap {
91+
($0.elements.as(MemberDeclListSyntax.self)).flatMap(membersToKeepIfUsedAsNamespace(_:))
8292
}
8393

8494
if membersToKeep.count < decl.clauses.count {

Tests/SwiftFormatPrettyPrintTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ extension ClosureExprTests {
136136
("testClosureArgumentsWithTrailingClosure", testClosureArgumentsWithTrailingClosure),
137137
("testClosureCapture", testClosureCapture),
138138
("testClosureCaptureWithoutArguments", testClosureCaptureWithoutArguments),
139+
("testClosureOutputGrouping", testClosureOutputGrouping),
139140
("testClosuresWithIfs", testClosuresWithIfs),
140141
("testClosureVariables", testClosureVariables),
141142
("testTrailingClosure", testTrailingClosure),

Tests/SwiftFormatRulesTests/UseEnumForNamespacingTests.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,65 @@ public class UseEnumForNamespacingTests: DiagnosingTestCase {
164164
}
165165
""")
166166
}
167+
168+
public func testNestedEnumsForNameSpaces() {
169+
XCTAssertFormatting(
170+
UseEnumForNamespacing.self,
171+
input: """
172+
struct A {
173+
static func fooA() {}
174+
struct B {
175+
static func fooB() {}
176+
}
177+
}
178+
struct C {
179+
func fooC() {}
180+
struct D {
181+
static func fooB() {}
182+
}
183+
}
184+
struct E {
185+
static func fooE() {}
186+
struct F {
187+
func fooF() {}
188+
}
189+
}
190+
struct G {
191+
func fooG() {}
192+
#if useH
193+
struct H {
194+
static func fooH() {}
195+
}
196+
#endif
197+
}
198+
""",
199+
expected: """
200+
enum A {
201+
static func fooA() {}
202+
enum B {
203+
static func fooB() {}
204+
}
205+
}
206+
struct C {
207+
func fooC() {}
208+
enum D {
209+
static func fooB() {}
210+
}
211+
}
212+
enum E {
213+
static func fooE() {}
214+
struct F {
215+
func fooF() {}
216+
}
217+
}
218+
struct G {
219+
func fooG() {}
220+
#if useH
221+
enum H {
222+
static func fooH() {}
223+
}
224+
#endif
225+
}
226+
""")
227+
}
167228
}

Tests/SwiftFormatRulesTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ extension UseEnumForNamespacingTests {
288288
// `swift test --generate-linuxmain`
289289
// to regenerate.
290290
static let __allTests__UseEnumForNamespacingTests = [
291+
("testNestedEnumsForNameSpaces", testNestedEnumsForNameSpaces),
291292
("testNonEnumsUsedAsNamespaces", testNonEnumsUsedAsNamespaces),
292293
]
293294
}

0 commit comments

Comments
 (0)