Skip to content

Commit

Permalink
Fix macro signature generation (#63)
Browse files Browse the repository at this point in the history
Fixes a bug where ParsableMacros with multiple arguments would generate
a placeholder attribute missing commas between the arguments. Adds a
test to verify this behavior.
  • Loading branch information
rauhul authored Jan 5, 2024
1 parent 14fd664 commit c9600ea
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ extension ParsableMacro {
var attributeWithPlaceholders = AttributeSyntax(
atSign: .atSignToken(),
attributeName: TypeSyntax(stringLiteral: baseName))
var arguments: LabeledExprListSyntax? = nil
var arguments = LabeledExprListSyntax()

for child in Mirror(reflecting: Self()).children {
guard let child = child.value as? any ArgumentProtocol else { continue }
if arguments == nil {
if arguments.isEmpty {
signature += "("
attributeWithPlaceholders.leftParen = .leftParenToken()
arguments = .init()
Expand All @@ -67,10 +67,15 @@ extension ParsableMacro {
expression: EditorPlaceholderExprSyntax(
placeholder: .identifier("<#\(child.typePlaceholder)#>")))

arguments?.append(argument)
if !arguments.isEmpty {
let lastIndex = arguments.index(before: arguments.endIndex)
arguments[lastIndex].trailingComma = .commaToken(trailingTrivia: .space)
}

arguments.append(argument)
}

if let arguments = arguments {
if !arguments.isEmpty {
signature += ")"
attributeWithPlaceholders.arguments = .argumentList(arguments)
attributeWithPlaceholders.rightParen = .rightParenToken()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,25 @@ import XCTest
protocol MMIOArgumentParsingMacro: MMIOMemberMacro {}
extension MMIOArgumentParsingMacro {
static var memberMacroSuppressParsingDiagnostics: Bool { false }

mutating func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: MacroContext<Self, some MacroExpansionContext>
) throws -> [DeclSyntax] { [] }

mutating func update(
label: String,
from expression: ExprSyntax,
in context: MacroContext<some ParsableMacro, some MacroExpansionContext>
) throws {
fatalError()
}
}

final class ParsableMacroTests: XCTestCase {
func test_noArguments_parse() {
struct A: MMIOArgumentParsingMacro {
mutating func update(
label: String,
from expression: ExprSyntax,
in context: MacroContext<some ParsableMacro, some MacroExpansionContext>
) throws {
fatalError()
}
}
struct A: MMIOArgumentParsingMacro {}

// Good...
assertMacroExpansion(
Expand Down Expand Up @@ -526,4 +527,45 @@ final class ParsableMacroTests: XCTestCase {
],
macros: ["A": A.self])
}

func test_many_signatures() {
struct A: MMIOArgumentParsingMacro {}
struct B: MMIOArgumentParsingMacro {
@Argument(label: "foo")
var foo: Int
}
struct C: MMIOArgumentParsingMacro {
@Argument(label: "foo")
var foo: Int

@Argument(label: "bar")
var bar: Int
}
struct D: MMIOArgumentParsingMacro {
@Argument(label: "foo")
var foo: Int
}
struct E: MMIOArgumentParsingMacro {
@Argument(label: "foo")
var foo: Int?
}
struct F: MMIOArgumentParsingMacro {
@Argument(label: "foo")
var foo: [Int]
}

XCTAssertEqual(A.signature, "@A")
XCTAssertEqual(B.signature, "@B(foo:)")
XCTAssertEqual(C.signature, "@C(foo:bar:)")
XCTAssertEqual(D.signature, "@D(foo:)")
XCTAssertEqual(E.signature, "@E(foo:)")
XCTAssertEqual(F.signature, "@F(foo:)")

XCTAssertEqual("\(A.attributeWithPlaceholders)", "@A")
XCTAssertEqual("\(B.attributeWithPlaceholders)", "@B(foo: <#Int#>)")
XCTAssertEqual("\(C.attributeWithPlaceholders)", "@C(foo: <#Int#>, bar: <#Int#>)")
XCTAssertEqual("\(D.attributeWithPlaceholders)", "@D(foo: <#Int#>)")
XCTAssertEqual("\(E.attributeWithPlaceholders)", "@E(foo: <#Int#>)")
XCTAssertEqual("\(F.attributeWithPlaceholders)", "@F(foo: <#Int#>)")
}
}

0 comments on commit c9600ea

Please sign in to comment.