swiftlang/swift-syntax

MacroSystem should add newline at the end of added members for an empty type

Closed this issue · 4 comments

Description

Given a macro AddMembers that does as its name suggests, MacroSystem will currently expand the following:

@AddMembers struct Foo {}

To:

struct Foo {
  func addedMember() {
    ...
  }}

Note the lack of a newline after the added member. This usually makes sense as there would already be one, but when there isn't, we should add it.

rdar://116773975

Here is a possible test case for this bug:

func testAddMemberToEmptyDeclaration() {
  struct TestMacro: MemberMacro {
    static func expansion(
      of node: AttributeSyntax,
      providingMembersOf declaration: some DeclGroupSyntax,
      conformingTo protocols: [TypeSyntax],
      in context: some MacroExpansionContext
    ) throws -> [DeclSyntax] {
      return [DeclSyntax("var x = 0")]
    }
  }

  assertMacroExpansion(
    """
    @Test
    struct Foo {}
    """,
    expandedSource: """
      struct Foo {

        var x = 0
      }
      """,
    macros: [
      "Test": TestMacro.self
    ],
    indentationWidth: indentationWidth
  )
} 

I'm wondering if we should add an empty line before the new member. The current implementation of macro system in swift-syntax will do that. 🤔

What is interesting is that the case with a new line at the end of the declaration added by macro is neither works as expected:

func testAddMemberToEmptyDeclaration() {
  struct TestMacro: MemberMacro {
    static func expansion(
      of node: AttributeSyntax,
      providingMembersOf declaration: some DeclGroupSyntax,
      conformingTo protocols: [TypeSyntax],
      in context: some MacroExpansionContext
    ) throws -> [DeclSyntax] {
      return [DeclSyntax("var x = 0\n")]
    }
  }

  assertMacroExpansion(
    """
    @Test
    struct Foo {}
    """,
    expandedSource: """
      """,
    macros: [
      "Test": TestMacro.self
    ],
    indentationWidth: indentationWidth
  )
}

The problem seems to be in the SyntaxExpressibleByStringInterpolation.init(stringLiteral:) since the following code:

(lldb) po MemberBlockItemListSyntax(stringLiteral: "\n\n var x = 0\n\n").description
"\n\n var x = 0"

is discarding trailing trivia 🤔

The problem seems to be in the SyntaxExpressibleByStringInterpolation.init(stringLiteral:) since the following code is discarding trailing trivia 🤔

Oh, that’s a bug as well. We should be adding the leading trivia of the endOfFile token to the trailing trivia of the parsed node. That’s probably best done in Parser.parseRemainder

I'm wondering if we should add an empty line before the new member. The current implementation of macro system in swift-syntax will do that. 🤔

Ah, nice catch. Yeah, ideally we wouldn't add the extra newline there.