Skip to content

Commit 3b008a7

Browse files
committed
Flesh out unknown node handling.
We previously only covered a subset of the unknown nodes. Treat them all as verbatim text so that malformed or unrecognized syntax does not get completely clobbered. (Note that in some cases, depending on how breaks/spaces are inserted into the token stream relative to tokens in the unknown nodes, leading spaces may still get compressed).
1 parent a64e12b commit 3b008a7

File tree

4 files changed

+118
-29
lines changed

4 files changed

+118
-29
lines changed

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,10 +1658,6 @@ private final class TokenStreamCreator: SyntaxVisitor {
16581658
return .visitChildren
16591659
}
16601660

1661-
override func visit(_ node: UnknownPatternSyntax) -> SyntaxVisitorContinueKind {
1662-
return .visitChildren
1663-
}
1664-
16651661
override func visit(_ node: SomeTypeSyntax) -> SyntaxVisitorContinueKind {
16661662
after(node.someSpecifier, tokens: .space)
16671663
return .visitChildren
@@ -1937,18 +1933,45 @@ private final class TokenStreamCreator: SyntaxVisitor {
19371933
return .visitChildren
19381934
}
19391935

1936+
// MARK: - Nodes representing unknown or malformed syntax
1937+
19401938
override func visit(_ node: UnknownDeclSyntax) -> SyntaxVisitorContinueKind {
19411939
verbatimToken(Syntax(node))
1942-
// Visiting children is not needed here.
1940+
return .skipChildren
1941+
}
1942+
1943+
override func visit(_ node: UnknownExprSyntax) -> SyntaxVisitorContinueKind {
1944+
verbatimToken(Syntax(node))
1945+
return .skipChildren
1946+
}
1947+
1948+
override func visit(_ node: UnknownPatternSyntax) -> SyntaxVisitorContinueKind {
1949+
verbatimToken(Syntax(node))
19431950
return .skipChildren
19441951
}
19451952

19461953
override func visit(_ node: UnknownStmtSyntax) -> SyntaxVisitorContinueKind {
19471954
verbatimToken(Syntax(node))
1948-
// Visiting children is not needed here.
19491955
return .skipChildren
19501956
}
19511957

1958+
override func visit(_ node: UnknownSyntax) -> SyntaxVisitorContinueKind {
1959+
verbatimToken(Syntax(node))
1960+
return .skipChildren
1961+
}
1962+
1963+
override func visit(_ node: UnknownTypeSyntax) -> SyntaxVisitorContinueKind {
1964+
verbatimToken(Syntax(node))
1965+
return .skipChildren
1966+
}
1967+
1968+
override func visit(_ node: NonEmptyTokenListSyntax) -> SyntaxVisitorContinueKind {
1969+
verbatimToken(Syntax(node))
1970+
return .skipChildren
1971+
}
1972+
1973+
// MARK: - Token handling
1974+
19521975
override func visit(_ token: TokenSyntax) -> SyntaxVisitorContinueKind {
19531976
// Arrange the tokens and trivia such that before tokens that start a new "scope" (which may
19541977
// increase indentation) are inserted in the stream *before* the leading trivia, but tokens

Tests/SwiftFormatPrettyPrintTests/UnknownDeclTests.swift

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/// Tests for unknown/malformed nodes that ensure that they are handled as verbatim text so that
2+
/// their internal tokens do not get squashed together.
3+
final class UnknownNodeTests: PrettyPrintTestCase {
4+
func testUnknownDecl() {
5+
let input =
6+
"""
7+
struct MyStruct where {
8+
let a = 123
9+
}
10+
"""
11+
12+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 45)
13+
}
14+
15+
func testUnknownExpr() {
16+
let input =
17+
"""
18+
(foo where bar)
19+
"""
20+
21+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 45)
22+
}
23+
24+
func testUnknownPattern() {
25+
// This one loses the space after the word `case` because the break would normally be
26+
// inserted before the first token in the pattern.
27+
let input =
28+
"""
29+
if case * ! = x {
30+
bar()
31+
}
32+
"""
33+
34+
let expected =
35+
"""
36+
if case* ! = x {
37+
bar()
38+
}
39+
40+
"""
41+
42+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 45)
43+
}
44+
45+
func testUnknownStmt() {
46+
let input =
47+
"""
48+
if foo where {
49+
bar()
50+
}
51+
"""
52+
53+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 45)
54+
}
55+
56+
func testUnknownType() {
57+
// This one loses the space after the colon because the break would normally be inserted before
58+
// the first token in the type name.
59+
let input =
60+
"""
61+
let x: where
62+
"""
63+
64+
let expected =
65+
"""
66+
let x:where
67+
68+
"""
69+
70+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 45)
71+
}
72+
73+
func testNonEmptyTokenList() {
74+
let input =
75+
"""
76+
@(foo ! @ # bar)
77+
"""
78+
79+
assertPrettyPrintEqual(input: input, expected: input + "\n", linelength: 45)
80+
}
81+
}

Tests/SwiftFormatPrettyPrintTests/XCTestManifests.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -705,12 +705,17 @@ extension TypeAliasTests {
705705
]
706706
}
707707

708-
extension UnknownDeclTests {
708+
extension UnknownNodeTests {
709709
// DO NOT MODIFY: This is autogenerated, use:
710710
// `swift test --generate-linuxmain`
711711
// to regenerate.
712-
static let __allTests__UnknownDeclTests = [
712+
static let __allTests__UnknownNodeTests = [
713+
("testNonEmptyTokenList", testNonEmptyTokenList),
713714
("testUnknownDecl", testUnknownDecl),
715+
("testUnknownExpr", testUnknownExpr),
716+
("testUnknownPattern", testUnknownPattern),
717+
("testUnknownStmt", testUnknownStmt),
718+
("testUnknownType", testUnknownType),
714719
]
715720
}
716721

@@ -795,7 +800,7 @@ public func __allTests() -> [XCTestCaseEntry] {
795800
testCase(TryCatchTests.__allTests__TryCatchTests),
796801
testCase(TupleDeclTests.__allTests__TupleDeclTests),
797802
testCase(TypeAliasTests.__allTests__TypeAliasTests),
798-
testCase(UnknownDeclTests.__allTests__UnknownDeclTests),
803+
testCase(UnknownNodeTests.__allTests__UnknownNodeTests),
799804
testCase(VariableDeclarationTests.__allTests__VariableDeclarationTests),
800805
testCase(WhileStmtTests.__allTests__WhileStmtTests),
801806
testCase(YieldStmtTests.__allTests__YieldStmtTests),

0 commit comments

Comments
 (0)