@@ -9,13 +9,21 @@ import SwiftSyntaxMacros
99
1010public 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