Skip to content

Commit a8f5553

Browse files
authored
Merge pull request #666 from allevato/various-fixes
Various fixes for some 509.0.0 bugs.
2 parents 0002372 + b268ae8 commit a8f5553

File tree

6 files changed

+115
-12
lines changed

6 files changed

+115
-12
lines changed

Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,11 +1894,31 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
18941894
}
18951895

18961896
override func visit(_ node: KeyPathSubscriptComponentSyntax) -> SyntaxVisitorContinueKind {
1897-
after(node.leftSquare, tokens: .break(.open, size: 0), .open)
1898-
before(node.rightSquare, tokens: .break(.close, size: 0), .close)
1897+
var breakBeforeRightParen = !isCompactSingleFunctionCallArgument(node.arguments)
1898+
if let component = node.parent?.as(KeyPathComponentSyntax.self) {
1899+
breakBeforeRightParen = !isLastKeyPathComponent(component)
1900+
}
1901+
1902+
arrangeFunctionCallArgumentList(
1903+
node.arguments,
1904+
leftDelimiter: node.leftSquare,
1905+
rightDelimiter: node.rightSquare,
1906+
forcesBreakBeforeRightDelimiter: breakBeforeRightParen)
18991907
return .visitChildren
19001908
}
19011909

1910+
/// Returns a value indicating whether the given key path component was the last component in the
1911+
/// list containing it.
1912+
private func isLastKeyPathComponent(_ component: KeyPathComponentSyntax) -> Bool {
1913+
guard
1914+
let componentList = component.parent?.as(KeyPathComponentListSyntax.self),
1915+
let lastComponent = componentList.last
1916+
else {
1917+
return false
1918+
}
1919+
return component == lastComponent
1920+
}
1921+
19021922
override func visit(_ node: TernaryExprSyntax) -> SyntaxVisitorContinueKind {
19031923
// The order of the .open/.close tokens here is intentional. They are normally paired with the
19041924
// corresponding breaks, but in this case, we want to prioritize keeping the entire `? a : b`

Sources/SwiftFormat/Rules/NoEmptyTrailingClosureParentheses.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ public final class NoEmptyTrailingClosureParentheses: SyntaxFormatRule {
2727
guard
2828
let trailingClosure = node.trailingClosure,
2929
let leftParen = node.leftParen,
30-
node.arguments.isEmpty
30+
let rightParen = node.rightParen,
31+
node.arguments.isEmpty,
32+
!leftParen.trailingTrivia.hasAnyComments,
33+
!rightParen.leadingTrivia.hasAnyComments
3134
else {
3235
return super.visit(node)
3336
}

Sources/SwiftFormat/Rules/UseShorthandTypeNames.swift

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,12 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
238238
) -> TypeSyntax {
239239
var wrappedType = wrappedType
240240

241-
// Function types and some-or-any types must be wrapped in parentheses before using shorthand
242-
// optional syntax, otherwise the "?" will bind incorrectly (in the function case it binds to
243-
// only the result, and in the some-or-any case it only binds to the child protocol). Attach the
244-
// leading trivia to the left-paren that we're adding in these cases.
241+
// Certain types must be wrapped in parentheses before using shorthand optional syntax to avoid
242+
// the "?" from binding incorrectly when re-parsed. Attach the leading trivia to the left-paren
243+
// that we're adding in these cases.
245244
switch Syntax(wrappedType).as(SyntaxEnum.self) {
245+
case .attributedType(let attributedType):
246+
wrappedType = parenthesizedType(attributedType, leadingTrivia: leadingTrivia)
246247
case .functionType(let functionType):
247248
wrappedType = parenthesizedType(functionType, leadingTrivia: leadingTrivia)
248249
case .someOrAnyType(let someOrAnyType):
@@ -319,12 +320,11 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
319320
) -> OptionalChainingExprSyntax? {
320321
guard var wrappedTypeExpr = expressionRepresentation(of: wrappedType) else { return nil }
321322

322-
// Function types and some-or-any types must be wrapped in parentheses before using shorthand
323-
// optional syntax, otherwise the "?" will bind incorrectly (in the function case it binds to
324-
// only the result, and in the some-or-any case it only binds to the child protocol). Attach the
325-
// leading trivia to the left-paren that we're adding in these cases.
323+
// Certain types must be wrapped in parentheses before using shorthand optional syntax to avoid
324+
// the "?" from binding incorrectly when re-parsed. Attach the leading trivia to the left-paren
325+
// that we're adding in these cases.
326326
switch Syntax(wrappedType).as(SyntaxEnum.self) {
327-
case .functionType, .someOrAnyType:
327+
case .attributedType, .functionType, .someOrAnyType:
328328
wrappedTypeExpr = parenthesizedExpr(wrappedTypeExpr, leadingTrivia: leadingTrivia)
329329
default:
330330
// Otherwise, the argument type can safely become an optional by simply appending a "?". If
@@ -448,6 +448,9 @@ public final class UseShorthandTypeNames: SyntaxFormatRule {
448448
case .someOrAnyType(let someOrAnyType):
449449
return ExprSyntax(TypeExprSyntax(type: someOrAnyType))
450450

451+
case .attributedType(let attributedType):
452+
return ExprSyntax(TypeExprSyntax(type: attributedType))
453+
451454
default:
452455
return nil
453456
}

Tests/SwiftFormatTests/PrettyPrint/KeyPathExprTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ final class KeyPathExprTests: PrettyPrintTestCase {
131131
#"""
132132
let x = \ReallyLongType.reallyLongProperty.anotherLongProperty
133133
let x = \.reeeeallyLongProperty.anotherLongProperty
134+
let x = \.longProperty.a.b.c[really + long + expression]
134135
let x = \.longProperty.a.b.c[really + long + expression].anotherLongProperty
136+
let x = \.longProperty.a.b.c[label:really + long + expression].anotherLongProperty
135137
"""#
136138

137139
let expected =
@@ -146,6 +148,16 @@ final class KeyPathExprTests: PrettyPrintTestCase {
146148
let x =
147149
\.longProperty.a.b.c[
148150
really + long
151+
+ expression]
152+
let x =
153+
\.longProperty.a.b.c[
154+
really + long
155+
+ expression
156+
].anotherLongProperty
157+
let x =
158+
\.longProperty.a.b.c[
159+
label: really
160+
+ long
149161
+ expression
150162
].anotherLongProperty
151163

Tests/SwiftFormatTests/Rules/NoEmptyTrailingClosureParenthesesTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,29 @@ final class NoEmptyTrailingClosureParenthesesTests: LintOrFormatRuleTestCase {
8383
]
8484
)
8585
}
86+
87+
func testDoNotRemoveParensContainingOnlyComments() {
88+
assertFormatting(
89+
NoEmptyTrailingClosureParentheses.self,
90+
input: """
91+
greetEnthusiastically(/*oldArg: x*/) { "John" }
92+
greetEnthusiastically(
93+
/*oldArg: x*/
94+
) { "John" }
95+
greetEnthusiastically(
96+
// oldArg: x
97+
) { "John" }
98+
""",
99+
expected: """
100+
greetEnthusiastically(/*oldArg: x*/) { "John" }
101+
greetEnthusiastically(
102+
/*oldArg: x*/
103+
) { "John" }
104+
greetEnthusiastically(
105+
// oldArg: x
106+
) { "John" }
107+
""",
108+
findings: []
109+
)
110+
}
86111
}

Tests/SwiftFormatTests/Rules/UseShorthandTypeNamesTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,4 +692,44 @@ final class UseShorthandTypeNamesTests: LintOrFormatRuleTestCase {
692692
]
693693
)
694694
}
695+
696+
func testAttributedTypesInOptionalsAreParenthesized() {
697+
// If we need to insert parentheses, verify that we do, but also verify that we don't insert
698+
// them unnecessarily.
699+
assertFormatting(
700+
UseShorthandTypeNames.self,
701+
input: """
702+
var x: 1️⃣Optional<consuming P> = S()
703+
var y: 2️⃣Optional<@Sendable (Int) -> Void> = S()
704+
var z = [3️⃣Optional<consuming P>]([S()])
705+
var a = [4️⃣Optional<@Sendable (Int) -> Void>]([S()])
706+
707+
var x: 5️⃣Optional<(consuming P)> = S()
708+
var y: 6️⃣Optional<(@Sendable (Int) -> Void)> = S()
709+
var z = [7️⃣Optional<(consuming P)>]([S()])
710+
var a = [8️⃣Optional<(@Sendable (Int) -> Void)>]([S()])
711+
""",
712+
expected: """
713+
var x: (consuming P)? = S()
714+
var y: (@Sendable (Int) -> Void)? = S()
715+
var z = [(consuming P)?]([S()])
716+
var a = [(@Sendable (Int) -> Void)?]([S()])
717+
718+
var x: (consuming P)? = S()
719+
var y: (@Sendable (Int) -> Void)? = S()
720+
var z = [(consuming P)?]([S()])
721+
var a = [(@Sendable (Int) -> Void)?]([S()])
722+
""",
723+
findings: [
724+
FindingSpec("1️⃣", message: "use shorthand syntax for this 'Optional' type"),
725+
FindingSpec("2️⃣", message: "use shorthand syntax for this 'Optional' type"),
726+
FindingSpec("3️⃣", message: "use shorthand syntax for this 'Optional' type"),
727+
FindingSpec("4️⃣", message: "use shorthand syntax for this 'Optional' type"),
728+
FindingSpec("5️⃣", message: "use shorthand syntax for this 'Optional' type"),
729+
FindingSpec("6️⃣", message: "use shorthand syntax for this 'Optional' type"),
730+
FindingSpec("7️⃣", message: "use shorthand syntax for this 'Optional' type"),
731+
FindingSpec("8️⃣", message: "use shorthand syntax for this 'Optional' type"),
732+
]
733+
)
734+
}
695735
}

0 commit comments

Comments
 (0)