Summary: As part of supporting function body macros on closure expressions, I've added a new requirement to the BodyMacro protocol to accept a value of ClosureExprSyntax, and I generalized the public expandAttachedMacro APIs to accept some SyntaxProtocol instead of DeclSyntax to allow passing a value of ClosureExprSyntax as the node that the macro is attached to.
Swift Interface
My PR adds the following public API in SwiftSyntaxMacroExpansion:
/// Expand `@attached(XXX)` macros.
///
/// - Parameters:
/// - definition: a type that conforms to one or more attached `Macro` protocols.
/// - macroRole: indicates which `Macro` protocol expansion should be performed
/// - attributeNode: attribute syntax node (e.g. `@macroName(argument)`).
/// - node: target syntax node to apply the expansion. This is either a declaration
/// or a closure syntax node.
/// - parentDeclNode: Only used for `MacroRole.memberAttribute`. The parent
/// context node of `declarationNode`.
/// - context: context of the expansion.
/// - indentationWidth: The indentation that should be added for each additional
/// nesting level
/// - Returns: A list of expanded source text. Upon failure (i.e.
/// `definition.expansion()` throws) returns `nil`, and the diagnostics
/// representing the `Error` are guaranteed to be added to context.
public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext>(
definition: Macro.Type,
macroRole: MacroRole,
attributeNode: AttributeSyntax,
node: some SyntaxProtocol,
parentDeclNode: DeclSyntax?,
extendedType: TypeSyntax?,
conformanceList: InheritedTypeListSyntax?,
in context: Context,
indentationWidth: Trivia? = nil
) -> [String]?
/// Expand `@attached(XXX)` macros.
///
/// - Parameters:
/// - definition: a type that conforms to one or more attached `Macro` protocols.
/// - macroRole: indicates which `Macro` protocol expansion should be performed
/// - attributeNode: attribute syntax node (e.g. `@macroName(argument)`).
/// - node: target declaration syntax node to apply the expansion. This is either
/// a declaration or a closure syntax node.
/// - parentDeclNode: Only used for `MacroRole.memberAttribute`. The parent
/// context node of `declarationNode`.
/// - context: context of the expansion.
/// - indentationWidth: The indentation that should be added for each additional
/// nesting level
/// - Returns: expanded source text. Upon failure (i.e. `defintion.expansion()`
/// throws) returns `nil`, and the diagnostics representing the `Error` are
/// guaranteed to be added to context.
public func expandAttachedMacro<Context: MacroExpansionContext>(
definition: Macro.Type,
macroRole: MacroRole,
attributeNode: AttributeSyntax,
node: some SyntaxProtocol,
parentDeclNode: DeclSyntax?,
extendedType: TypeSyntax?,
conformanceList: InheritedTypeListSyntax?,
in context: Context,
indentationWidth: Trivia? = nil
) -> String? {
I also deprecated the overloads that accept declarationNode: DeclSyntax, with a message to rename the declarationNode: argument label to node:. Because the new overloads accept some SyntaxProtocol, direct only require changing the argument label; an argument type of DeclSyntax is still valid.
I also added the following requirement to the BodyMacro protocol in SwiftSyntaxMacros:
/// Expand a macro described by the given custom attribute and
/// attached to the given closure and evaluated within a
/// particular expansion context.
///
/// The macro expansion can replace the body of the given closure.
static func expansion(
of node: AttributeSyntax,
providingBodyFor closure: ClosureExprSyntax,
in context: some MacroExpansionContext
) throws -> [CodeBlockItemSyntax]
For existing API: This change will cause warnings in existing callers of the expandAttachedMacro APIs and existing conformances to BodyMacro.
- Migration: To facilitate migration, the old overloads of the
expandAttachedMacroAPIs are deprecated, and the default implementation of the newBodyMacroprotocol requirement is deprecated. This will cause warnings in existing clients of these APIs. Existing callers ofexpandAttachedMacro{WithoutCollapsing}will get a warning to change thedeclarationNodeargument label tonode. Existing conformances ofBodyMacrowill get a warning to implement the new protocol requirement.