Skip to content

Commit b2091bd

Browse files
committed
Fix up AttributeTypeSyntax handling
There's a few issues here: 1. Type specifiers can now have arguments (eg. `nonisolated(nonsending)`) 2. Some type specifiers can be specified "late", which are currently unhandled 3. We were using a mix of `.same` and `.continue` breaks (`.continue` for specifiers and `.same` for attributes) 4. Attributes were grouped separately to specifiers Fixes #1081
1 parent 1058a40 commit b2091bd

File tree

2 files changed

+136
-30
lines changed

2 files changed

+136
-30
lines changed

Sources/SwiftFormat/PrettyPrint/TokenStreamCreator.swift

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2395,13 +2395,25 @@ private final class TokenStreamCreator: SyntaxVisitor {
23952395

23962396
override func visit(_ node: AttributedTypeSyntax) -> SyntaxVisitorContinueKind {
23972397
before(node.firstToken(viewMode: .sourceAccurate), tokens: .open)
2398-
arrangeAttributeList(node.attributes)
2398+
2399+
let breakToken: Token = .break(.continue, newlines: .elective(ignoresDiscretionary: true))
23992400
for specifier in node.specifiers {
24002401
after(
2401-
specifier.firstToken(viewMode: .sourceAccurate),
2402-
tokens: .break(.continue, newlines: .elective(ignoresDiscretionary: true))
2402+
specifier.lastToken(viewMode: .sourceAccurate),
2403+
tokens: breakToken
2404+
)
2405+
}
2406+
arrangeAttributeList(node.attributes, suppressFinalBreak: false, lineBreak: breakToken, shouldGroup: false)
2407+
for specifier in node.lateSpecifiers {
2408+
after(
2409+
specifier.lastToken(viewMode: .sourceAccurate),
2410+
tokens: breakToken
24032411
)
24042412
}
2413+
2414+
before(node.baseType.firstToken(viewMode: .sourceAccurate), tokens: .open)
2415+
after(node.baseType.lastToken(viewMode: .sourceAccurate), tokens: .close)
2416+
24052417
after(node.lastToken(viewMode: .sourceAccurate), tokens: .close)
24062418
return .visitChildren
24072419
}
@@ -3067,40 +3079,73 @@ private final class TokenStreamCreator: SyntaxVisitor {
30673079
private func arrangeAttributeList(
30683080
_ attributes: AttributeListSyntax?,
30693081
suppressFinalBreak: Bool = false,
3070-
separateByLineBreaks: Bool = false
3082+
separateByLineBreaks: Bool = false,
3083+
shouldGroup: Bool = true
30713084
) {
3072-
if let attributes = attributes {
3073-
let behavior: NewlineBehavior = separateByLineBreaks ? .hard : .elective
3085+
let behavior: NewlineBehavior = separateByLineBreaks ? .hard : .elective
3086+
arrangeAttributeList(
3087+
attributes,
3088+
suppressFinalBreak: suppressFinalBreak,
3089+
lineBreak: .break(.same, newlines: behavior),
3090+
shouldGroup: shouldGroup
3091+
)
3092+
}
3093+
3094+
/// Applies formatting tokens around and between the attributes in an attribute list.
3095+
private func arrangeAttributeList(
3096+
_ attributes: AttributeListSyntax?,
3097+
suppressFinalBreak: Bool,
3098+
lineBreak: Token,
3099+
shouldGroup: Bool
3100+
) {
3101+
guard let attributes, !attributes.isEmpty else {
3102+
return
3103+
}
3104+
3105+
if shouldGroup {
30743106
before(attributes.firstToken(viewMode: .sourceAccurate), tokens: .open)
3075-
if attributes.dropLast().isEmpty,
3076-
let ifConfig = attributes.first?.as(IfConfigDeclSyntax.self)
3077-
{
3078-
for clause in ifConfig.clauses {
3079-
if let nestedAttributes = AttributeListSyntax(clause.elements) {
3080-
arrangeAttributeList(nestedAttributes, suppressFinalBreak: true, separateByLineBreaks: separateByLineBreaks)
3081-
}
3107+
}
3108+
3109+
if attributes.dropLast().isEmpty,
3110+
let ifConfig = attributes.first?.as(IfConfigDeclSyntax.self)
3111+
{
3112+
for clause in ifConfig.clauses {
3113+
if let nestedAttributes = AttributeListSyntax(clause.elements) {
3114+
arrangeAttributeList(
3115+
nestedAttributes,
3116+
suppressFinalBreak: true,
3117+
lineBreak: lineBreak,
3118+
shouldGroup: shouldGroup
3119+
)
30823120
}
3083-
} else {
3084-
for element in attributes.dropLast() {
3085-
if let ifConfig = element.as(IfConfigDeclSyntax.self) {
3086-
for clause in ifConfig.clauses {
3087-
if let nestedAttributes = AttributeListSyntax(clause.elements) {
3088-
arrangeAttributeList(
3089-
nestedAttributes,
3090-
suppressFinalBreak: true,
3091-
separateByLineBreaks: separateByLineBreaks
3092-
)
3093-
}
3121+
}
3122+
} else {
3123+
for element in attributes.dropLast() {
3124+
if let ifConfig = element.as(IfConfigDeclSyntax.self) {
3125+
for clause in ifConfig.clauses {
3126+
if let nestedAttributes = AttributeListSyntax(clause.elements) {
3127+
arrangeAttributeList(
3128+
nestedAttributes,
3129+
suppressFinalBreak: true,
3130+
lineBreak: lineBreak,
3131+
shouldGroup: shouldGroup
3132+
)
30943133
}
3095-
} else {
3096-
after(element.lastToken(viewMode: .sourceAccurate), tokens: .break(.same, newlines: behavior))
30973134
}
3135+
} else {
3136+
after(element.lastToken(viewMode: .sourceAccurate), tokens: lineBreak)
30983137
}
30993138
}
3100-
var afterAttributeTokens = [Token.close]
3101-
if !suppressFinalBreak {
3102-
afterAttributeTokens.append(.break(.same, newlines: behavior))
3103-
}
3139+
}
3140+
3141+
var afterAttributeTokens = [Token]()
3142+
if shouldGroup {
3143+
afterAttributeTokens.append(.close)
3144+
}
3145+
if !suppressFinalBreak {
3146+
afterAttributeTokens.append(lineBreak)
3147+
}
3148+
if !afterAttributeTokens.isEmpty {
31043149
after(attributes.lastToken(viewMode: .sourceAccurate), tokens: afterAttributeTokens)
31053150
}
31063151
}

Tests/SwiftFormatTests/PrettyPrint/FunctionTypeTests.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,4 +283,65 @@ final class FunctionTypeTests: PrettyPrintTestCase {
283283

284284
assertPrettyPrintEqual(input: input, expected: expected, linelength: 17)
285285
}
286+
287+
func testFunctionTypeWithTypeSpecifier() {
288+
let input =
289+
"""
290+
func f(_ body: nonisolated(nonsending) () async -> Void) {}
291+
292+
func f(_ body: @Foo @Bar nonisolated(nonsending) () async -> Void) {}
293+
294+
func f(_ body: nonisolated(nonsending) @Foo @Bar () async -> Void) {}
295+
296+
func f(_ body: inout @Foo @Bar nonisolated(nonsending) () async -> Void) {}
297+
"""
298+
299+
assertPrettyPrintEqual(
300+
input: input,
301+
expected: """
302+
func f(_ body: nonisolated(nonsending) () async -> Void) {}
303+
304+
func f(_ body: @Foo @Bar nonisolated(nonsending) () async -> Void) {}
305+
306+
func f(_ body: nonisolated(nonsending) @Foo @Bar () async -> Void) {}
307+
308+
func f(_ body: inout @Foo @Bar nonisolated(nonsending) () async -> Void) {}
309+
310+
""",
311+
linelength: 80
312+
)
313+
314+
assertPrettyPrintEqual(
315+
input: input,
316+
expected: """
317+
func f(
318+
_ body:
319+
nonisolated(nonsending)
320+
() async -> Void
321+
) {}
322+
323+
func f(
324+
_ body:
325+
@Foo @Bar
326+
nonisolated(nonsending)
327+
() async -> Void
328+
) {}
329+
330+
func f(
331+
_ body:
332+
nonisolated(nonsending)
333+
@Foo @Bar () async -> Void
334+
) {}
335+
336+
func f(
337+
_ body:
338+
inout @Foo @Bar
339+
nonisolated(nonsending)
340+
() async -> Void
341+
) {}
342+
343+
""",
344+
linelength: 30
345+
)
346+
}
286347
}

0 commit comments

Comments
 (0)