Skip to content

Commit cdebb6d

Browse files
committed
fix: swift 5.9+ version compile error
1 parent c1f5aff commit cdebb6d

1 file changed

Lines changed: 94 additions & 2 deletions

File tree

Sources/KarrotListKitMacros/AddComponentModifierMacro.swift

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,21 @@ import SwiftSyntaxMacros
99

1010
public struct AddComponentModifierMacro: PeerMacro {
1111
public static func expansion(
12-
of _: SwiftSyntax.AttributeSyntax,
12+
of node: AttributeSyntax,
1313
providingPeersOf declaration: some DeclSyntaxProtocol,
1414
in context: some MacroExpansionContext
1515
) throws -> [DeclSyntax] {
16+
var lexicalContext: [Syntax] {
17+
#if canImport(SwiftSyntax600)
18+
context.lexicalContext
19+
#else
20+
declaration.allMacroLexicalContexts()
21+
#endif
22+
}
23+
1624
// struct 선언인지 확인
1725
guard
18-
let structDecl = context.lexicalContext.compactMap({ $0.as(StructDeclSyntax.self) }).first
26+
let structDecl = lexicalContext.compactMap({ $0.as(StructDeclSyntax.self) }).first
1927
else {
2028
throw KarrotListKitMacroError(message: "@AddComponentModifier can only be applied to structs")
2129
}
@@ -100,3 +108,87 @@ public struct AddComponentModifierMacro: PeerMacro {
100108
return structAccessLevel.name.text + " "
101109
}
102110
}
111+
112+
#if !canImport(SwiftSyntax600)
113+
extension SyntaxProtocol {
114+
/// If this syntax node acts as a lexical context from the perspective
115+
/// of a macro, return a new syntax node based on this node that strips all
116+
/// information that isn't supposed to be exposed as a lexical context, such
117+
/// as function bodies or the members of types/extensions.
118+
///
119+
/// Returns `nil` for any syntax node that isn't a lexical context.
120+
public func asMacroLexicalContext() -> Syntax? {
121+
switch Syntax(self).asProtocol(SyntaxProtocol.self) {
122+
// Functions have their body removed.
123+
case var function as WithOptionalCodeBlockSyntax & SyntaxProtocol:
124+
function = function.detached
125+
function.body = nil
126+
return Syntax(function) as Syntax
127+
128+
// Closures have their body removed.
129+
case var closure as ClosureExprSyntax:
130+
closure = closure.detached
131+
closure.statements = CodeBlockItemListSyntax()
132+
return Syntax(closure)
133+
134+
// Nominal types and extensions have their member list cleared out.
135+
case var typeOrExtension as HasTrailingMemberDeclBlock & SyntaxProtocol:
136+
typeOrExtension = typeOrExtension.detached
137+
typeOrExtension.memberBlock = MemberBlockSyntax(members: MemberBlockItemListSyntax())
138+
return Syntax(typeOrExtension) as Syntax
139+
140+
// Subscripts have their accessors removed.
141+
case var subscriptDecl as SubscriptDeclSyntax:
142+
subscriptDecl = subscriptDecl.detached
143+
subscriptDecl.accessorBlock = nil
144+
return Syntax(subscriptDecl)
145+
146+
// Enum cases are fine as-is.
147+
case is EnumCaseElementSyntax:
148+
return Syntax(self.detached)
149+
150+
// Pattern bindings have their accessors and initializer removed.
151+
case var patternBinding as PatternBindingSyntax:
152+
patternBinding = patternBinding.detached
153+
patternBinding.accessorBlock = nil
154+
patternBinding.initializer = nil
155+
return Syntax(patternBinding)
156+
157+
// Freestanding macros are fine as-is because if any arguments change
158+
// the whole macro would have to be re-evaluated.
159+
case let freestandingMacro as FreestandingMacroExpansionSyntax:
160+
return Syntax(freestandingMacro.detached) as Syntax
161+
162+
default:
163+
return nil
164+
}
165+
}
166+
167+
/// Return an array of enclosing lexical contexts for the purpose of macros,
168+
/// from the innermost enclosing lexical context (first in the array) to the
169+
/// outermost. If this syntax node itself is a lexical context, it will be
170+
/// the innermost lexical context.
171+
///
172+
/// - Parameter enclosingSyntax: provides a parent node when the operation
173+
/// has reached the outermost syntax node (i.e., it has no parent), allowing
174+
/// the caller to provide a new syntax node that can continue the walk
175+
/// to collect additional lexical contexts, e.g., from outer macro
176+
/// expansions.
177+
/// - Returns: the array of enclosing lexical contexts.
178+
public func allMacroLexicalContexts(
179+
enclosingSyntax: (Syntax) -> Syntax? = { _ in nil }
180+
) -> [Syntax] {
181+
var parentContexts: [Syntax] = []
182+
var currentNode = Syntax(self)
183+
while let parentNode = currentNode.parent ?? enclosingSyntax(currentNode) {
184+
if let parentContext = parentNode.asMacroLexicalContext() {
185+
parentContexts.append(parentContext)
186+
}
187+
188+
currentNode = parentNode
189+
}
190+
191+
return parentContexts
192+
}
193+
}
194+
#endif

0 commit comments

Comments
 (0)