I haven't tried this, but from reading the docs the some MacroExpansionContext parameter that gets passed into your expansion method should have a .lexicalContext: [any Syntax] property from which you should (I think!) be able to extract this information by walking the hierarchy upward. Have you tried something like this?
I assumed that @MyMacro in above example conforms to AttachedMacro, however it should be possible as long as you have access to MacroExpansionContext, specifically lexicalContext property as iterating over it will provide you with enough information to create fully qualified name of a nested declaration
enum MyMacro: MemberMacro {
static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
for lexicalContext in context.lexicalContext {
// Based on your example, it contains elements in such order,
StructDeclSyntax // (First element)
├─attributes: AttributeListSyntax
├─modifiers: DeclModifierListSyntax
├─structKeyword: keyword(SwiftSyntax.Keyword.struct)
├─name: identifier("Parent")
╰─memberBlock: MemberBlockSyntax
├─leftBrace: leftBrace
├─members: MemberBlockItemListSyntax
╰─rightBrace: rightBrace (from macro 'MyMacro')
StructDeclSyntax // (Second element)
├─attributes: AttributeListSyntax
├─modifiers: DeclModifierListSyntax
├─structKeyword: keyword(SwiftSyntax.Keyword.struct)
├─name: identifier("GrandParent")
╰─memberBlock: MemberBlockSyntax
├─leftBrace: leftBrace
├─members: MemberBlockItemListSyntax
╰─rightBrace: rightBrace (from macro 'MyMacro')
}
// And then, you can extract the name of "Child" to which MyMacro has been attached via declaration argument, and it should look like this
StructDeclSyntax
├─attributes: AttributeListSyntax
│ ╰─[0]: AttributeSyntax
│ ├─atSign: atSign
│ ╰─attributeName: IdentifierTypeSyntax
│ ╰─name: identifier("MyMacro")
├─modifiers: DeclModifierListSyntax
├─structKeyword: keyword(SwiftSyntax.Keyword.struct)
├─name: identifier("Child")
╰─memberBlock: MemberBlockSyntax
├─leftBrace: leftBrace
├─members: MemberBlockItemListSyntax
╰─rightBrace: rightBrace (from macro 'MyMacro')
// return some syntax
}
}
What's left is to either convert extracted syntax into MemberAccessExprSyntax or interpolate names to produce fully qualified name as a String
PS: Regarding your actual goal, I don't remember if what you want (have a macro declare a possibly arbitrary extension at the top level) is supported, but an extension macro should be able to add a conformance to a nested type out of the box without you having to construct the fully qualified name.
In this situation, the macro expansion containing the extension is inserted at the top level of the file, instead of immediately where the macro is invoked, where the extension would be invalid.
Okay, it was easier than expected. Below is the signature of the ExtensionMacro requirement:
public static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax]
I was focusing on declaration, but it's rather type that comes with the fully qualified type name, as mentioned in the @ole SE-402 reference:
Each ExtensionDeclSyntax in the resulting array must use the providingExtensionsOf parameter as the extended type, which is a qualified type name.
Therefore, it was as trivial as using type.description.