`assertMacroExpansion` passes 0 protocols to `ExtensionMacro`.
drekka opened this issue · 4 comments
Description
I've been writing at attached extension macro to apply some protocols to certain types which looks something like this:
public protocol PX {}
/// THis defines the macro as it will be seen by the source code.
@attached(extension, conformances: PX, Hashable, Identifiable, names: named(hash(into:)))
public macro pathElement() = #externalMacro(module: "SwiftUIExtensionsMacros", type: "PathElementMacro")
With an implementation of:
public enum PathElementMacro: ExtensionMacro {
public static func expansion(
of node: AttributeSyntax,
attachedTo declaration: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
let count:Int = protocols.count
let equatableExtension = try ExtensionDeclSyntax("extension \(type.trimmed): Hashable { let x = \(raw: count) }")
return [equatableExtension]
}
}
Obviously this is not a finished macro as I''m still working out what it will do. However it does show the number of protocols
passed which I eventually intend to use in generating extensions.
The bug is that when I debug this macro using this unit test code:
assertMacroExpansion(
"""
@pathElement
struct X: Hashable {}
""",
expandedSource: """
struct X: Hashable {}
extension X: Identifiable {
let id = UUID()
}
""",
macros: [
"pathElement": PathElementMacro.self,
]
)
and breakpoint inside the macro, the protocols
array argument is always zero length. However when I run this macro on a live source code file, I see let x = 3
in the generated extension indicating that the 3 protocols were passed as expected.
Any I correct? Is this a missed bug?
Or have I missed something in my test code?
Steps to Reproduce
No response
Synced to Apple’s issue tracker as rdar://131441049
Hey there!
Thanks for bringing this up.
There's a bit of a mismatch between what your test is doing and how the macro actually behaves in real code–since the unit tests expansion is based on a totally different expansion system than source code (compiler) expansion.
If you want to cover conformances
in your unit tests, you have to provide a list of conformances to the assertMacroExpansion
function. The function has an argument called macroSpecs
that you need to fill up if you want to receive conformances in your macro implementation from unit tests.
Here's the documentation for this argument:
swift-syntax/Sources/SwiftSyntaxMacrosTestSupport/Assertions.swift
Lines 88 to 91 in 70e3741
Basically, there's this MacroSpec
struct with a conformances
property that you need to fill in for your tests. It's a new thing that came with swift-syntax version 6.0, which is part of the upcoming Swift 6.0 release. If you're really keen, you can check it out on the main
branch right now.
Thanks @Matejkob However I'm on a client's project where we have to support iOS16 and Swift 5. Is there any way to address this without Swift 6?
Ok, I updated to use the main branch and now I can interrogate the protocols.