Skip to content

Commit 47c846c

Browse files
committed
Don’t add any accessors if accessor macro returned an empty array
If an accessor macro returns an empty array, MacroSystem was failing with internal error messages because it tried ot parse an `AccessorBlockSyntax` from an empty string. To fix this, check if the expanded source is empty before trying to parse the `AccessorBlockSyntax`.
1 parent 7bb5231 commit 47c846c

File tree

2 files changed

+228
-1
lines changed

2 files changed

+228
-1
lines changed

Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ private func expandAccessorMacroWithoutExistingAccessors(
259259
conformanceList: nil,
260260
in: context,
261261
indentationWidth: indentationWidth
262-
)
262+
),
263+
!expanded.isEmpty
263264
else {
264265
return nil
265266
}

Tests/SwiftSyntaxMacroExpansionTest/MacroSystemTests.swift

+226
Original file line numberDiff line numberDiff line change
@@ -2088,4 +2088,230 @@ final class MacroSystemTests: XCTestCase {
20882088
macros: ["Test": DiagnoseFirstArgument.self]
20892089
)
20902090
}
2091+
2092+
func testEmptyAccessorMacro() {
2093+
struct TestMacro: AccessorMacro {
2094+
static func expansion(
2095+
of node: AttributeSyntax,
2096+
providingAccessorsOf declaration: some DeclSyntaxProtocol,
2097+
in context: some MacroExpansionContext
2098+
) throws -> [AccessorDeclSyntax] {
2099+
return []
2100+
}
2101+
}
2102+
2103+
// The compiler will reject this with
2104+
// 'Expansion of macro 'Test()' did not produce a non-observing accessor'
2105+
// We consider this a semantic error because swift-syntax doesn't have
2106+
// knowledge about which accessors are observing and which ones aren't.
2107+
assertMacroExpansion(
2108+
"@Test var x: Int",
2109+
expandedSource: "var x: Int",
2110+
macros: ["Test": TestMacro.self]
2111+
)
2112+
2113+
assertMacroExpansion(
2114+
"@Test var x: Int { 1 }",
2115+
expandedSource: "var x: Int { 1 }",
2116+
macros: ["Test": TestMacro.self]
2117+
)
2118+
}
2119+
2120+
func testEmitErrorFromAccessorMacro() {
2121+
struct TestMacro: AccessorMacro {
2122+
static func expansion(
2123+
of node: AttributeSyntax,
2124+
providingAccessorsOf declaration: some DeclSyntaxProtocol,
2125+
in context: some MacroExpansionContext
2126+
) throws -> [AccessorDeclSyntax] {
2127+
context.diagnose(Diagnostic(node: node, message: MacroExpansionErrorMessage("test")))
2128+
return []
2129+
}
2130+
}
2131+
2132+
assertMacroExpansion(
2133+
"@Test var x: Int",
2134+
expandedSource: "var x: Int",
2135+
diagnostics: [
2136+
DiagnosticSpec(message: "test", line: 1, column: 1)
2137+
],
2138+
macros: ["Test": TestMacro.self]
2139+
)
2140+
2141+
assertMacroExpansion(
2142+
"@Test var x: Int { 1 }",
2143+
expandedSource: "var x: Int { 1 }",
2144+
diagnostics: [DiagnosticSpec(message: "test", line: 1, column: 1)],
2145+
macros: ["Test": TestMacro.self]
2146+
)
2147+
}
2148+
2149+
func testEmptyCodeItemMacro() {
2150+
struct TestMacro: CodeItemMacro {
2151+
static func expansion(
2152+
of node: some FreestandingMacroExpansionSyntax,
2153+
in context: some MacroExpansionContext
2154+
) throws -> [CodeBlockItemSyntax] {
2155+
return []
2156+
}
2157+
}
2158+
2159+
assertMacroExpansion(
2160+
"#test",
2161+
expandedSource: "",
2162+
macros: [
2163+
"test": TestMacro.self
2164+
]
2165+
)
2166+
}
2167+
2168+
func testEmptyDeclarationMacro() {
2169+
struct TestMacro: DeclarationMacro {
2170+
static func expansion(
2171+
of node: some FreestandingMacroExpansionSyntax,
2172+
in context: some MacroExpansionContext
2173+
) throws -> [DeclSyntax] {
2174+
return []
2175+
}
2176+
}
2177+
2178+
assertMacroExpansion(
2179+
"#test",
2180+
expandedSource: "",
2181+
macros: [
2182+
"test": TestMacro.self
2183+
]
2184+
)
2185+
}
2186+
2187+
func testEmptyExtensionMacro() {
2188+
struct TestMacro: ExtensionMacro {
2189+
static func expansion(
2190+
of node: AttributeSyntax,
2191+
attachedTo declaration: some DeclGroupSyntax,
2192+
providingExtensionsOf type: some TypeSyntaxProtocol,
2193+
conformingTo protocols: [TypeSyntax],
2194+
in context: some MacroExpansionContext
2195+
) throws -> [ExtensionDeclSyntax] {
2196+
return []
2197+
}
2198+
}
2199+
2200+
assertMacroExpansion(
2201+
"@Test struct Foo {}",
2202+
expandedSource: "struct Foo {}",
2203+
macros: [
2204+
"Test": TestMacro.self
2205+
]
2206+
)
2207+
}
2208+
2209+
func testEmptyMemberAttributeMacro() {
2210+
struct TestMacro: MemberAttributeMacro {
2211+
static func expansion(
2212+
of node: AttributeSyntax,
2213+
attachedTo declaration: some DeclGroupSyntax,
2214+
providingAttributesFor member: some DeclSyntaxProtocol,
2215+
in context: some MacroExpansionContext
2216+
) throws -> [AttributeSyntax] {
2217+
return []
2218+
}
2219+
}
2220+
2221+
assertMacroExpansion(
2222+
"""
2223+
@Test
2224+
struct Foo {
2225+
var x: Int
2226+
}
2227+
""",
2228+
expandedSource: """
2229+
struct Foo {
2230+
var x: Int
2231+
}
2232+
""",
2233+
macros: [
2234+
"Test": TestMacro.self
2235+
]
2236+
)
2237+
2238+
assertMacroExpansion(
2239+
"""
2240+
@Test
2241+
struct Foo {
2242+
}
2243+
""",
2244+
expandedSource: """
2245+
struct Foo {
2246+
}
2247+
""",
2248+
macros: [
2249+
"Test": TestMacro.self
2250+
]
2251+
)
2252+
}
2253+
2254+
func testEmptyMemberMacro() {
2255+
struct TestMacro: MemberMacro {
2256+
static func expansion(
2257+
of node: AttributeSyntax,
2258+
providingMembersOf declaration: some DeclGroupSyntax,
2259+
in context: some MacroExpansionContext
2260+
) throws -> [DeclSyntax] {
2261+
return []
2262+
}
2263+
}
2264+
2265+
assertMacroExpansion(
2266+
"""
2267+
@Test
2268+
struct Foo {
2269+
var x: Int
2270+
}
2271+
""",
2272+
expandedSource: """
2273+
struct Foo {
2274+
var x: Int
2275+
}
2276+
""",
2277+
macros: [
2278+
"Test": TestMacro.self
2279+
]
2280+
)
2281+
2282+
assertMacroExpansion(
2283+
"""
2284+
@Test
2285+
struct Foo {
2286+
}
2287+
""",
2288+
expandedSource: """
2289+
struct Foo {
2290+
}
2291+
""",
2292+
macros: [
2293+
"Test": TestMacro.self
2294+
]
2295+
)
2296+
}
2297+
2298+
func testEmptyPeerMacro() {
2299+
struct TestMacro: PeerMacro {
2300+
static func expansion(
2301+
of node: AttributeSyntax,
2302+
providingPeersOf declaration: some DeclSyntaxProtocol,
2303+
in context: some MacroExpansionContext
2304+
) throws -> [DeclSyntax] {
2305+
return []
2306+
}
2307+
}
2308+
2309+
assertMacroExpansion(
2310+
"@Test var x: Int",
2311+
expandedSource: "var x: Int",
2312+
macros: [
2313+
"Test": TestMacro.self
2314+
]
2315+
)
2316+
}
20912317
}

0 commit comments

Comments
 (0)