MemberAttribute Macro -- Bug when Member has existing attributes?

Consider this code with some custom macros:

@CouchbaseModel
final class Foo
{
    @Relationship var child: Bar? = nil
}

@Relationship expands to nothing; it's a marker that helps me decide some things about Bar, since type information isn't available in the AST at the time macros expand.

@CouchbaseModel has several roles, but ONE of the things it's supposed to do is add a second macro attribute, @CouchbasePersisted to stored properties. Here's that implementation:

extension CouchbaseModelMacro: MemberAttributeMacro
{
    public static func expansion(...) throws -> [SwiftSyntax.AttributeSyntax]
    {
        // Some logic to check attributes of the member is omitted for brevity. It's not relevant to the problem.
        return [
            AttributeSyntax(stringLiteral:
                """
                @CouchbasePersisted
                """
            )
        ]
    }
}


The Problem

This works great, unless the stored property already has some attributes. In that case, the macro expands to this:

final class Foo
{
   @Relationship var child: Bar? = nil
       @CouchbasePersisted
}

This, of course, is useless. @CouchbasePersisted is in the wrong spot and attached to nothing. @CouchbasePersisted (an Accessor and Peer macro) therefore does nothing. But as far as I can see, I don't have any control over how the memberAttribute macro positions/orders the attributes on members.

Am I misusing the memberAttribute macro? Is there a way to work around this issue?

Another Approach

I also tried constructing the AttributeSyntax this way, which produced the same mis-positioned result when a member has existing attributes:

AttributeSyntax(
    attributeName: IdentifierTypeSyntax(name: .identifier("CouchbasePersisted"))
)
1 Like

A Workaround

For now, I've worked around this issue by simply having @Relationship adopt the same Accessor and Peer macro roles as @CouchbasePersisted and then, in the implementations of those roles, calling @CouchbasePersisted's implementations.

Then I simply skip adding @CouchbasePersisted to any member that's already decorated with @Relationship.

That's definitely not great though. What's the actual solution to the misplacement problem?