Ian_Keen
(Ian Keen)
1
I'm attempting to build a fairly simple macro:
public struct PreviewWithBindingsMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
guard let builder = node.trailingClosure?.trimmed else {
fatalError("trailing closure expected")
}
let prefix = context.createUniqueName("View")
let previews = try! StructDeclSyntax("struct \(raw: prefix)_Previews: PreviewProvider") {
try VariableDeclSyntax("static var previews: some View") {
StmtSyntax("PreviewView \(raw: builder)")
}
}
return "\(raw: previews.formatted())"
}
}
I wonder if im holding this right.. there are a couple of problems
Firstly, The test input is
#PreviewWithBindings { bindings in
Text("Hello")
}
and the output is:
struct __macro_local_4ViewfMu__Previews: PreviewProvider {
static var previews: some View {
PreviewView { bindings in
Text(" Hello")
}
}
}
Note the additional spaces in the text String literal. Am I constructing the struct and outputting correctly?
Secondly, literal issue aside no matter what I do xcode will not recognize my preview and open the preview pane.. is there something hardcoded into xcode to only look for blessed macros? copy/pasting my macro output allows the pane to appear but xcode must not look at it otherwise?
ahoppen
(Alex Hoppen)
2
The problem is that you declared PreviewWithBindingsMacro as an ExpressionMacro, but the macro is generating a declaration. This probably throws the parser off in multiple ways and makes it generate a completely invalid tree. Change the macro to a DeclarationMacro and you should be fine. That way you can also return previews as DecSyntax(previews), without the need for another string interpolation.
Ian_Keen
(Ian Keen)
3
Good point on using the wrong type! but after updating the issue persists 
Ian_Keen
(Ian Keen)
4
There's also a possible bug, the compiler is saying:
Use of protocol 'PreviewProvider' as a type must be written 'any PreviewProvider'
Even though copy/pasting the expanded code works without issue.
There's a feedback at FB12326868 for anyone able to peek into it.
ahoppen
(Alex Hoppen)
5
Can you share the macro package with a test case that reproduces the issue? I suspect there’s some other issue where a node is parsed as a different type than it should be.
1 Like
Ian_Keen
(Ian Keen)
6
Yup, no problem.
@freestanding(declaration, names: arbitrary)
public macro MyMacro<Content: View>(@ViewBuilder _ content: () -> Content) -> Void = #externalMacro(module: "MyMacros", type: "MyMacro")
public struct MyMacro: DeclarationMacro {
public static func expansion<Node: FreestandingMacroExpansionSyntax, Context: MacroExpansionContext>(
of node: Node,
in context: Context
) throws -> [DeclSyntax] {
guard let builder = node.trailingClosure?.trimmed else { fatalError("trailing closure expected") }
let prefix = context.createUniqueName("View")
let previews = try StructDeclSyntax("struct \(raw: prefix)_Previews: PreviewProvider") {
try VariableDeclSyntax("static var previews: some View") {
StmtSyntax("Wrapper \(raw: builder)")
}
}
return [DeclSyntax(previews)]
}
}```
```swift
assertMacroExpansion(
"""
#MyMacro {
Text("Hello")
}
""",
expandedSource: """
struct __macro_local_4ViewfMu__Previews: PreviewProvider {
static var previews: some View {
Wrapper {
Text("Hello")
}
}
}
""",
macros: ["MyMacro": MyMacro.self]
)
the diff provided with the test failure is:
struct __macro_local_4ViewfMu__Previews: PreviewProvider {
static var previews: some View {
Wrapper {
– Text("Hello")
+ Text(" Hello")
}
}
}
ahoppen
(Alex Hoppen)
7
The call to wrapper is a function call expression and so it needs to be
ExprSyntax("Wrapper \(raw: builder)")
Ian_Keen
(Ian Keen)
8
ah that worked. thanks!
I dont suppose you might know if its possible to make xcode recognize my code and open the preview pane (which I can't even do manually)
Ian_Keen
(Ian Keen)
9
actually nevermind.. I forgot im blocked on the compiler bug 