diff --git a/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift b/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift index 3cf445c1f26..f97f02b53a1 100644 --- a/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift +++ b/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift @@ -267,7 +267,8 @@ private func expandAccessorMacroWithoutExistingAccessors( conformanceList: nil, in: context, indentationWidth: indentationWidth - ) + ), + !expanded.isEmpty else { return nil } diff --git a/Tests/SwiftSyntaxMacroExpansionTest/AccessorMacroTests.swift b/Tests/SwiftSyntaxMacroExpansionTest/AccessorMacroTests.swift index bb857bdb4d4..76eecb6c5f1 100644 --- a/Tests/SwiftSyntaxMacroExpansionTest/AccessorMacroTests.swift +++ b/Tests/SwiftSyntaxMacroExpansionTest/AccessorMacroTests.swift @@ -18,7 +18,9 @@ // macros are invoked. // //==========================================================================// +import SwiftDiagnostics import SwiftSyntax +import SwiftSyntaxMacroExpansion import SwiftSyntaxMacros import SwiftSyntaxMacrosTestSupport import XCTest @@ -261,4 +263,61 @@ final class AccessorMacroTests: XCTestCase { indentationWidth: indentationWidth ) } + + func testEmpty() { + struct TestMacro: AccessorMacro { + static func expansion( + of node: AttributeSyntax, + providingAccessorsOf declaration: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [AccessorDeclSyntax] { + return [] + } + } + + // The compiler will reject this with + // 'Expansion of macro 'Test()' did not produce a non-observing accessor' + // We consider this a semantic error because swift-syntax doesn't have + // knowledge about which accessors are observing and which ones aren't. + assertMacroExpansion( + "@Test var x: Int", + expandedSource: "var x: Int", + macros: ["Test": TestMacro.self] + ) + + assertMacroExpansion( + "@Test var x: Int { 1 }", + expandedSource: "var x: Int { 1 }", + macros: ["Test": TestMacro.self] + ) + } + + func testEmitErrorFromMacro() { + struct TestMacro: AccessorMacro { + static func expansion( + of node: AttributeSyntax, + providingAccessorsOf declaration: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [AccessorDeclSyntax] { + context.diagnose(Diagnostic(node: node, message: MacroExpansionErrorMessage("test"))) + return [] + } + } + + assertMacroExpansion( + "@Test var x: Int", + expandedSource: "var x: Int", + diagnostics: [ + DiagnosticSpec(message: "test", line: 1, column: 1) + ], + macros: ["Test": TestMacro.self] + ) + + assertMacroExpansion( + "@Test var x: Int { 1 }", + expandedSource: "var x: Int { 1 }", + diagnostics: [DiagnosticSpec(message: "test", line: 1, column: 1)], + macros: ["Test": TestMacro.self] + ) + } } diff --git a/Tests/SwiftSyntaxMacroExpansionTest/CodeItemMacroTests.swift b/Tests/SwiftSyntaxMacroExpansionTest/CodeItemMacroTests.swift index 1733a2a4717..684eb03ee6e 100644 --- a/Tests/SwiftSyntaxMacroExpansionTest/CodeItemMacroTests.swift +++ b/Tests/SwiftSyntaxMacroExpansionTest/CodeItemMacroTests.swift @@ -133,4 +133,23 @@ final class CodeItemMacroTests: XCTestCase { indentationWidth: indentationWidth ) } + + func testEmpty() { + struct TestMacro: CodeItemMacro { + static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) throws -> [CodeBlockItemSyntax] { + return [] + } + } + + assertMacroExpansion( + "#test", + expandedSource: "", + macros: [ + "test": TestMacro.self + ] + ) + } } diff --git a/Tests/SwiftSyntaxMacroExpansionTest/DeclarationMacroTests.swift b/Tests/SwiftSyntaxMacroExpansionTest/DeclarationMacroTests.swift index 72a6d24d67c..787f89290df 100644 --- a/Tests/SwiftSyntaxMacroExpansionTest/DeclarationMacroTests.swift +++ b/Tests/SwiftSyntaxMacroExpansionTest/DeclarationMacroTests.swift @@ -389,4 +389,22 @@ final class DeclarationMacroTests: XCTestCase { ) } + func testEmpty() { + struct TestMacro: DeclarationMacro { + static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + return [] + } + } + + assertMacroExpansion( + "#test", + expandedSource: "", + macros: [ + "test": TestMacro.self + ] + ) + } } diff --git a/Tests/SwiftSyntaxMacroExpansionTest/ExtensionMacroTests.swift b/Tests/SwiftSyntaxMacroExpansionTest/ExtensionMacroTests.swift index 167e6fda676..28ffebae0e0 100644 --- a/Tests/SwiftSyntaxMacroExpansionTest/ExtensionMacroTests.swift +++ b/Tests/SwiftSyntaxMacroExpansionTest/ExtensionMacroTests.swift @@ -106,4 +106,26 @@ final class ExtensionMacroTests: XCTestCase { indentationWidth: indentationWidth ) } + + func testEmpty() { + struct TestMacro: ExtensionMacro { + static func expansion( + of node: AttributeSyntax, + attachedTo declaration: some DeclGroupSyntax, + providingExtensionsOf type: some TypeSyntaxProtocol, + conformingTo protocols: [TypeSyntax], + in context: some MacroExpansionContext + ) throws -> [ExtensionDeclSyntax] { + return [] + } + } + + assertMacroExpansion( + "@Test struct Foo {}", + expandedSource: "struct Foo {}", + macros: [ + "Test": TestMacro.self + ] + ) + } } diff --git a/Tests/SwiftSyntaxMacroExpansionTest/MemberAttributeMacroTests.swift b/Tests/SwiftSyntaxMacroExpansionTest/MemberAttributeMacroTests.swift index 223419b7453..32a48cabd88 100644 --- a/Tests/SwiftSyntaxMacroExpansionTest/MemberAttributeMacroTests.swift +++ b/Tests/SwiftSyntaxMacroExpansionTest/MemberAttributeMacroTests.swift @@ -354,4 +354,48 @@ final class MemberAttributeMacroTests: XCTestCase { ) } + func testEmpty() { + struct TestMacro: MemberAttributeMacro { + static func expansion( + of node: AttributeSyntax, + attachedTo declaration: some DeclGroupSyntax, + providingAttributesFor member: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [AttributeSyntax] { + return [] + } + } + + assertMacroExpansion( + """ + @Test + struct Foo { + var x: Int + } + """, + expandedSource: """ + struct Foo { + var x: Int + } + """, + macros: [ + "Test": TestMacro.self + ] + ) + + assertMacroExpansion( + """ + @Test + struct Foo { + } + """, + expandedSource: """ + struct Foo { + } + """, + macros: [ + "Test": TestMacro.self + ] + ) + } } diff --git a/Tests/SwiftSyntaxMacroExpansionTest/MemberMacroTests.swift b/Tests/SwiftSyntaxMacroExpansionTest/MemberMacroTests.swift index 91b3bf8bad6..a281cc69744 100644 --- a/Tests/SwiftSyntaxMacroExpansionTest/MemberMacroTests.swift +++ b/Tests/SwiftSyntaxMacroExpansionTest/MemberMacroTests.swift @@ -255,4 +255,48 @@ final class MemberMacroTests: XCTestCase { ) } + func testEmpty() { + struct TestMacro: MemberMacro { + static func expansion( + of node: AttributeSyntax, + providingMembersOf declaration: some DeclGroupSyntax, + conformingTo protocols: [TypeSyntax], + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + return [] + } + } + + assertMacroExpansion( + """ + @Test + struct Foo { + var x: Int + } + """, + expandedSource: """ + struct Foo { + var x: Int + } + """, + macros: [ + "Test": TestMacro.self + ] + ) + + assertMacroExpansion( + """ + @Test + struct Foo { + } + """, + expandedSource: """ + struct Foo { + } + """, + macros: [ + "Test": TestMacro.self + ] + ) + } } diff --git a/Tests/SwiftSyntaxMacroExpansionTest/PeerMacroTests.swift b/Tests/SwiftSyntaxMacroExpansionTest/PeerMacroTests.swift index b92fdcdf232..b7f2e9647f5 100644 --- a/Tests/SwiftSyntaxMacroExpansionTest/PeerMacroTests.swift +++ b/Tests/SwiftSyntaxMacroExpansionTest/PeerMacroTests.swift @@ -173,4 +173,24 @@ final class PeerMacroTests: XCTestCase { macros: ["Test": TestMacro.self] ) } + + func testEmpty() { + struct TestMacro: PeerMacro { + static func expansion( + of node: AttributeSyntax, + providingPeersOf declaration: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + return [] + } + } + + assertMacroExpansion( + "@Test var x: Int", + expandedSource: "var x: Int", + macros: [ + "Test": TestMacro.self + ] + ) + } }