Skip to content

Commit 3856e2e

Browse files
committed
Merge branch 'main' into fix/document-tutorial
2 parents c7901ea + 7c1c56c commit 3856e2e

File tree

12 files changed

+153
-24
lines changed

12 files changed

+153
-24
lines changed

CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public let COMMON_NODES: [Node] = [
5656
kind: .codeBlock,
5757
base: .syntax,
5858
nameForDiagnostics: "code block",
59+
parserFunction: "parseCodeBlock",
5960
traits: [
6061
"Braced",
6162
"WithStatements",

CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ public let DECL_NODES: [Node] = [
8282
base: .decl,
8383
nameForDiagnostics: "accessor",
8484
parserFunction: "parseAccessorDecl",
85-
traits: ["WithAttributes"],
85+
traits: [
86+
"WithOptionalCodeBlock",
87+
"WithAttributes",
88+
],
8689
children: [
8790
Child(
8891
name: "attributes",
@@ -493,6 +496,7 @@ public let DECL_NODES: [Node] = [
493496
traits: [
494497
"WithAttributes",
495498
"WithModifiers",
499+
"WithOptionalCodeBlock",
496500
],
497501
children: [
498502
Child(
@@ -879,6 +883,7 @@ public let DECL_NODES: [Node] = [
879883
"WithAttributes",
880884
"WithGenericParameters",
881885
"WithModifiers",
886+
"WithOptionalCodeBlock",
882887
],
883888
children: [
884889
Child(
@@ -1217,6 +1222,7 @@ public let DECL_NODES: [Node] = [
12171222
"WithAttributes",
12181223
"WithGenericParameters",
12191224
"WithModifiers",
1225+
"WithOptionalCodeBlock",
12201226
],
12211227
children: [
12221228
Child(

CodeGeneration/Sources/SyntaxSupport/Traits.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ public let TRAITS: [Trait] = [
151151
Child(name: "modifiers", kind: .node(kind: .declModifierList))
152152
]
153153
),
154+
Trait(
155+
traitName: "WithOptionalCodeBlock",
156+
children: [
157+
Child(name: "body", kind: .node(kind: .codeBlock), isOptional: true)
158+
]
159+
),
154160
Trait(
155161
traitName: "WithStatements",
156162
children: [

Examples/Sources/MacroExamples/Implementation/Peer/AddCompletionHandlerMacro.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public struct AddCompletionHandlerMacro: PeerMacro {
3434
var newEffects: FunctionEffectSpecifiersSyntax
3535
if let existingEffects = funcDecl.signature.effectSpecifiers {
3636
newEffects = existingEffects
37-
newEffects.asyncSpecifier = .keyword(.async)
37+
newEffects.asyncSpecifier = .keyword(.async, trailingTrivia: .space)
3838
} else {
39-
newEffects = FunctionEffectSpecifiersSyntax(asyncSpecifier: .keyword(.async))
39+
newEffects = FunctionEffectSpecifiersSyntax(asyncSpecifier: .keyword(.async, trailingTrivia: .space))
4040
}
4141

4242
var newSignature = funcDecl.signature

Examples/Tests/MacroExamples/Implementation/Expression/AddBlockerTests.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,33 @@ final class AddBlockerTests: XCTestCase {
3939
)
4040
}
4141

42+
func testExpansionWithSubtractionAppliesFixIt() {
43+
assertMacroExpansion(
44+
"""
45+
#addBlocker(x * y + z)
46+
""",
47+
expandedSource: """
48+
x * y - z
49+
""",
50+
diagnostics: [
51+
DiagnosticSpec(
52+
message: "blocked an add; did you mean to subtract?",
53+
line: 1,
54+
column: 19,
55+
severity: .warning,
56+
fixIts: [FixItSpec(message: "use '-'")]
57+
)
58+
],
59+
macros: macros,
60+
applyFixIts: ["use '-'"],
61+
fixedSource:
62+
"""
63+
#addBlocker(x * y - z)
64+
""",
65+
indentationWidth: .spaces(2)
66+
)
67+
}
68+
4269
func testExpansionPreservesSubtraction() {
4370
assertMacroExpansion(
4471
"""

Examples/Tests/MacroExamples/Implementation/Peer/AddCompletionHandlerMacroTests.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,44 @@ final class AddCompletionHandlerMacroTests: XCTestCase {
9898
indentationWidth: .spaces(2)
9999
)
100100
}
101+
102+
func testExpansionOnNonAsyncFunctionAppliesFixIt() {
103+
assertMacroExpansion(
104+
"""
105+
struct Test {
106+
@AddCompletionHandler
107+
func fetchData() -> String {
108+
return "Hello, World!"
109+
}
110+
}
111+
""",
112+
expandedSource: """
113+
struct Test {
114+
func fetchData() -> String {
115+
return "Hello, World!"
116+
}
117+
}
118+
""",
119+
diagnostics: [
120+
DiagnosticSpec(
121+
message: "can only add a completion-handler variant to an 'async' function",
122+
line: 3,
123+
column: 3,
124+
severity: .error,
125+
fixIts: [FixItSpec(message: "add 'async'")]
126+
)
127+
],
128+
macros: macros,
129+
applyFixIts: ["add 'async'"],
130+
fixedSource: """
131+
struct Test {
132+
@AddCompletionHandler
133+
func fetchData() async -> String {
134+
return "Hello, World!"
135+
}
136+
}
137+
""",
138+
indentationWidth: .spaces(2)
139+
)
140+
}
101141
}

Release Notes/511.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
- Description: Enum to exhaustively switch over all different syntax nodes of each base type.
2121
- Pull Request: https://github.com/apple/swift-syntax/pull/2351
2222

23+
- `WithOptionalCodeBlock`
24+
- Description: A trait for syntax nodes that have an optional code block, such as `FunctionDeclSyntax` and `InitializerDeclSyntax`.
25+
- Pull Request: https://github.com/apple/swift-syntax/pull/2359
26+
2327
## API Behavior Changes
2428

2529
## Deprecations

Sources/SwiftParser/generated/LayoutNodes+Parsable.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,24 @@ extension CodeBlockItemSyntax: SyntaxParseable {
126126
}
127127
}
128128

129+
extension CodeBlockSyntax: SyntaxParseable {
130+
public static func parse(from parser: inout Parser) -> Self {
131+
// Keep the parser alive so that the arena in which `raw` is allocated
132+
// doesn’t get deallocated before we have a chance to create a syntax node
133+
// from it. We can’t use `parser.arena` as the parameter to
134+
// `Syntax(raw:arena:)` because the node might have been re-used during an
135+
// incremental parse and would then live in a different arena than
136+
// `parser.arena`.
137+
defer {
138+
withExtendedLifetime(parser) {
139+
}
140+
}
141+
let node = parser.parseCodeBlock()
142+
let raw = RawSyntax(parser.parseRemainder(into: node))
143+
return Syntax(raw: raw, rawNodeArena: raw.arena).cast(Self.self)
144+
}
145+
}
146+
129147
extension DeclSyntax: SyntaxParseable {
130148
public static func parse(from parser: inout Parser) -> Self {
131149
// Keep the parser alive so that the arena in which `raw` is allocated

Sources/SwiftSyntax/Documentation.docc/generated/SwiftSyntax.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ These articles are intended for developers wishing to contribute to SwiftSyntax
401401
- <doc:SwiftSyntax/WithCodeBlockSyntax>
402402
- <doc:SwiftSyntax/WithGenericParametersSyntax>
403403
- <doc:SwiftSyntax/WithModifiersSyntax>
404+
- <doc:SwiftSyntax/WithOptionalCodeBlockSyntax>
404405
- <doc:SwiftSyntax/WithStatementsSyntax>
405406
- <doc:SwiftSyntax/WithTrailingCommaSyntax>
406407

Sources/SwiftSyntax/generated/SyntaxTraits.swift

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,43 @@ public extension SyntaxProtocol {
570570
}
571571
}
572572

573+
// MARK: - WithOptionalCodeBlockSyntax
574+
575+
576+
public protocol WithOptionalCodeBlockSyntax: SyntaxProtocol {
577+
var body: CodeBlockSyntax? {
578+
get
579+
set
580+
}
581+
}
582+
583+
public extension WithOptionalCodeBlockSyntax {
584+
/// Without this function, the `with` function defined on `SyntaxProtocol`
585+
/// does not work on existentials of this protocol type.
586+
@_disfavoredOverload
587+
func with<T>(_ keyPath: WritableKeyPath<WithOptionalCodeBlockSyntax, T>, _ newChild: T) -> WithOptionalCodeBlockSyntax {
588+
var copy: WithOptionalCodeBlockSyntax = self
589+
copy[keyPath: keyPath] = newChild
590+
return copy
591+
}
592+
}
593+
594+
public extension SyntaxProtocol {
595+
/// Check whether the non-type erased version of this syntax node conforms to
596+
/// `WithOptionalCodeBlockSyntax`.
597+
/// Note that this will incur an existential conversion.
598+
func isProtocol(_: WithOptionalCodeBlockSyntax.Protocol) -> Bool {
599+
return self.asProtocol(WithOptionalCodeBlockSyntax.self) != nil
600+
}
601+
602+
/// Return the non-type erased version of this syntax node if it conforms to
603+
/// `WithOptionalCodeBlockSyntax`. Otherwise return `nil`.
604+
/// Note that this will incur an existential conversion.
605+
func asProtocol(_: WithOptionalCodeBlockSyntax.Protocol) -> WithOptionalCodeBlockSyntax? {
606+
return Syntax(self).asProtocol(SyntaxProtocol.self) as? WithOptionalCodeBlockSyntax
607+
}
608+
}
609+
573610
// MARK: - WithStatementsSyntax
574611

575612

@@ -649,7 +686,7 @@ public extension SyntaxProtocol {
649686

650687
extension AccessorBlockSyntax: BracedSyntax {}
651688

652-
extension AccessorDeclSyntax: WithAttributesSyntax {}
689+
extension AccessorDeclSyntax: WithOptionalCodeBlockSyntax, WithAttributesSyntax {}
653690

654691
extension AccessorEffectSpecifiersSyntax: EffectSpecifiersSyntax {}
655692

@@ -693,7 +730,7 @@ extension DeclNameArgumentsSyntax: ParenthesizedSyntax {}
693730

694731
extension DeferStmtSyntax: WithCodeBlockSyntax {}
695732

696-
extension DeinitializerDeclSyntax: WithAttributesSyntax, WithModifiersSyntax {}
733+
extension DeinitializerDeclSyntax: WithAttributesSyntax, WithModifiersSyntax, WithOptionalCodeBlockSyntax {}
697734

698735
extension DictionaryElementSyntax: WithTrailingCommaSyntax {}
699736

@@ -723,7 +760,7 @@ extension ExtensionDeclSyntax: DeclGroupSyntax, WithAttributesSyntax, WithModifi
723760

724761
extension ForStmtSyntax: WithCodeBlockSyntax {}
725762

726-
extension FunctionDeclSyntax: NamedDeclSyntax, WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax {}
763+
extension FunctionDeclSyntax: NamedDeclSyntax, WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax, WithOptionalCodeBlockSyntax {}
727764

728765
extension FunctionEffectSpecifiersSyntax: EffectSpecifiersSyntax {}
729766

@@ -747,7 +784,7 @@ extension ImportDeclSyntax: WithAttributesSyntax, WithModifiersSyntax {}
747784

748785
extension InheritedTypeSyntax: WithTrailingCommaSyntax {}
749786

750-
extension InitializerDeclSyntax: WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax {}
787+
extension InitializerDeclSyntax: WithAttributesSyntax, WithGenericParametersSyntax, WithModifiersSyntax, WithOptionalCodeBlockSyntax {}
751788

752789
extension LabeledExprSyntax: WithTrailingCommaSyntax {}
753790

Sources/SwiftSyntaxBuilder/SyntaxNodeWithBody.swift

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,9 @@ extension SyntaxStringInterpolation {
4040
}
4141
}
4242

43-
// MARK: - HasCodeBlock
44-
45-
public protocol HasTrailingCodeBlock {
46-
var body: CodeBlockSyntax { get set }
43+
// MARK: - HasTrailingCodeBlock
4744

45+
public protocol HasTrailingCodeBlock: WithCodeBlockSyntax {
4846
/// Constructs a syntax node where `header` builds the text of the node before the body in braces and `bodyBuilder` is used to build the node’s body.
4947
///
5048
/// For example, you can construct
@@ -90,11 +88,9 @@ extension ForStmtSyntax: HasTrailingCodeBlock {}
9088
extension GuardStmtSyntax: HasTrailingCodeBlock {}
9189
extension WhileStmtSyntax: HasTrailingCodeBlock {}
9290

93-
// MARK: - HasOptionalCodeBlock
94-
95-
public protocol HasTrailingOptionalCodeBlock {
96-
var body: CodeBlockSyntax? { get set }
91+
// MARK: - WithOptionalCodeBlockSyntax
9792

93+
public extension WithOptionalCodeBlockSyntax where Self: DeclSyntaxProtocol {
9894
/// Constructs a syntax node where `header` builds the text of the node before the body in braces and `bodyBuilder` is used to build the node’s body.
9995
///
10096
/// For example, you can construct
@@ -114,10 +110,6 @@ public protocol HasTrailingOptionalCodeBlock {
114110
/// ```
115111
///
116112
/// Throws an error if `header` defines a different node type than the type the initializer is called on. E.g. if calling `try FunctionDeclSyntax("init") {}`
117-
init(_ header: SyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax) throws
118-
}
119-
120-
public extension HasTrailingOptionalCodeBlock where Self: DeclSyntaxProtocol {
121113
init(_ header: SyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () throws -> CodeBlockItemListSyntax) throws {
122114
let decl = DeclSyntax("\(header) {}")
123115
guard let castedDecl = decl.as(Self.self) else {
@@ -128,11 +120,6 @@ public extension HasTrailingOptionalCodeBlock where Self: DeclSyntaxProtocol {
128120
}
129121
}
130122

131-
extension AccessorDeclSyntax: HasTrailingOptionalCodeBlock {}
132-
extension DeinitializerDeclSyntax: HasTrailingOptionalCodeBlock {}
133-
extension FunctionDeclSyntax: HasTrailingOptionalCodeBlock {}
134-
extension InitializerDeclSyntax: HasTrailingOptionalCodeBlock {}
135-
136123
// MARK: HasTrailingMemberDeclBlock
137124

138125
public protocol HasTrailingMemberDeclBlock {

Sources/SwiftSyntaxBuilder/generated/SyntaxExpressibleByStringInterpolationConformances.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ extension ClosureParameterSyntax: SyntaxExpressibleByStringInterpolation {}
2626

2727
extension CodeBlockItemSyntax: SyntaxExpressibleByStringInterpolation {}
2828

29+
extension CodeBlockSyntax: SyntaxExpressibleByStringInterpolation {}
30+
2931
extension DeclSyntax: SyntaxExpressibleByStringInterpolation {}
3032

3133
extension EnumCaseParameterSyntax: SyntaxExpressibleByStringInterpolation {}

0 commit comments

Comments
 (0)