|
12 | 12 |
|
13 | 13 | #if compiler(>=6) |
14 | 14 | import SwiftBasicFormat |
| 15 | +import SwiftDiagnostics |
| 16 | +import SwiftIfConfig |
15 | 17 | public import SwiftSyntax |
16 | 18 | @_spi(MacroExpansion) @_spi(ExperimentalLanguageFeatures) public import SwiftSyntaxMacros |
17 | 19 | #else |
18 | 20 | import SwiftBasicFormat |
| 21 | +import SwiftDiagnostics |
| 22 | +import SwiftIfConfig |
19 | 23 | import SwiftSyntax |
20 | 24 | @_spi(MacroExpansion) @_spi(ExperimentalLanguageFeatures) import SwiftSyntaxMacros |
21 | 25 | #endif |
@@ -394,6 +398,38 @@ public func expandAttachedMacroWithoutCollapsing<Context: MacroExpansionContext> |
394 | 398 | providingBodyFor: declToPass, |
395 | 399 | in: context |
396 | 400 | ) |
| 401 | + } else if let varDecl = node.as(VariableDeclSyntax.self), |
| 402 | + varDecl.bindings.count == 1, |
| 403 | + let binding = varDecl.bindings.first, |
| 404 | + let accessorBlock = binding.accessorBlock, |
| 405 | + case .getter(let stmts) = accessorBlock.accessors |
| 406 | + { |
| 407 | + // Create an implicit `AccessorDeclSyntax` to use for the macro expansion |
| 408 | + // of this computed var decl |
| 409 | + let getterDecl = AccessorDeclSyntax( |
| 410 | + accessorSpecifier: .keyword(.get, presence: .missing), |
| 411 | + body: CodeBlockSyntax( |
| 412 | + leftBrace: accessorBlock.leftBrace, |
| 413 | + statements: stmts, |
| 414 | + rightBrace: accessorBlock.rightBrace |
| 415 | + ) |
| 416 | + ) |
| 417 | + |
| 418 | + // Insert the enclosing `PatternBindingSyntax`'s var decl context |
| 419 | + // into the lexical context |
| 420 | + var context: MacroExpansionContext = context |
| 421 | + if let varDeclLexicalContext = binding.asMacroLexicalContext() { |
| 422 | + context = PrependLexicalContextWrapperContext( |
| 423 | + prependLexicalContext: [varDeclLexicalContext], |
| 424 | + wrapping: context |
| 425 | + ) |
| 426 | + } |
| 427 | + |
| 428 | + body = try attachedMacro.expansion( |
| 429 | + of: attributeNode, |
| 430 | + providingBodyFor: getterDecl, |
| 431 | + in: context |
| 432 | + ) |
397 | 433 | } else { |
398 | 434 | // Compiler error: declaration must have a body. |
399 | 435 | throw MacroExpansionError.declarationHasNoBody |
@@ -635,3 +671,39 @@ public func collapse<Node: SyntaxProtocol>( |
635 | 671 |
|
636 | 672 | return collapsed |
637 | 673 | } |
| 674 | + |
| 675 | +/// Wrapper context that prepends additional `lexicalContext` |
| 676 | +/// to an existing `MacroExpansionContext` |
| 677 | +final class PrependLexicalContextWrapperContext: MacroExpansionContext { |
| 678 | + init(prependLexicalContext: [Syntax], wrapping wrappedContext: MacroExpansionContext) { |
| 679 | + self.prependLexicalContext = prependLexicalContext |
| 680 | + self.wrappedContext = wrappedContext |
| 681 | + } |
| 682 | + |
| 683 | + let prependLexicalContext: [Syntax] |
| 684 | + let wrappedContext: MacroExpansionContext |
| 685 | + |
| 686 | + var lexicalContext: [Syntax] { |
| 687 | + prependLexicalContext + wrappedContext.lexicalContext |
| 688 | + } |
| 689 | + |
| 690 | + func makeUniqueName(_ name: String) -> TokenSyntax { |
| 691 | + wrappedContext.makeUniqueName(name) |
| 692 | + } |
| 693 | + |
| 694 | + func diagnose(_ diagnostic: Diagnostic) { |
| 695 | + wrappedContext.diagnose(diagnostic) |
| 696 | + } |
| 697 | + |
| 698 | + func location( |
| 699 | + of node: some SyntaxProtocol, |
| 700 | + at position: PositionInSyntaxNode, |
| 701 | + filePathMode: SourceLocationFilePathMode |
| 702 | + ) -> AbstractSourceLocation? { |
| 703 | + wrappedContext.location(of: node, at: position, filePathMode: filePathMode) |
| 704 | + } |
| 705 | + |
| 706 | + var buildConfiguration: (any BuildConfiguration)? { |
| 707 | + wrappedContext.buildConfiguration |
| 708 | + } |
| 709 | +} |
0 commit comments