diff --git a/Sources/MacroTesting/AssertMacro.swift b/Sources/MacroTesting/AssertMacro.swift index ab0f6c7..cd4860b 100644 --- a/Sources/MacroTesting/AssertMacro.swift +++ b/Sources/MacroTesting/AssertMacro.swift @@ -203,7 +203,9 @@ public func assertMacro( #if canImport(SwiftSyntax600) var expandedSourceFile = origSourceFile.expand( macros: macros, - contextGenerator: { _ in context }, + contextGenerator: { syntax in + BasicMacroExpansionContext(sharingWith: context, lexicalContext: syntax.allMacroLexicalContexts()) + }, indentationWidth: indentationWidth ) #else diff --git a/Tests/MacroTestingTests/EntryMacroTests.swift b/Tests/MacroTestingTests/EntryMacroTests.swift new file mode 100644 index 0000000..96403f4 --- /dev/null +++ b/Tests/MacroTestingTests/EntryMacroTests.swift @@ -0,0 +1,52 @@ +import MacroTesting +import XCTest + +final class EntryMacroTests: BaseTestCase { + override func invokeTest() { + withMacroTesting( + macros: [ + EntryMacro.self, + ] + ) { + super.invokeTest() + } + } + + func testWithinEnvironmentValues() { + assertMacro { + """ + extension EnvironmentValues { + @Entry var x: String = "" + } + """ + } expansion: { + """ + extension EnvironmentValues { + var x: String { + get { + fatalError() + } + } + } + """ + } + } + + func testNotWithinEnvironmentValues() { + assertMacro { + """ + extension String { + @Entry var x: String = "" + } + """ + } diagnostics: { + """ + extension String { + @Entry var x: String = "" + ┬───── + ╰─ 🛑 '@Entry' macro can only attach to var declarations inside extensions of EnvironmentValues + } + """ + } + } +} diff --git a/Tests/MacroTestingTests/MacroExamples/EntryMacro.swift b/Tests/MacroTestingTests/MacroExamples/EntryMacro.swift new file mode 100644 index 0000000..3cb8486 --- /dev/null +++ b/Tests/MacroTestingTests/MacroExamples/EntryMacro.swift @@ -0,0 +1,25 @@ +import SwiftSyntax +import SwiftSyntaxMacros + +// Not complete, just enough to unit test lexical context. +public struct EntryMacro: AccessorMacro { + public static func expansion( + of node: AttributeSyntax, + providingAccessorsOf declaration: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [AccessorDeclSyntax] { + let isInEnvironmentValues = context.lexicalContext.contains { lexicalContext in + lexicalContext.as(ExtensionDeclSyntax.self)?.extendedType.trimmedDescription == "EnvironmentValues" + } + + guard isInEnvironmentValues else { + throw MacroExpansionErrorMessage("'@Entry' macro can only attach to var declarations inside extensions of EnvironmentValues") + } + + return [ + AccessorDeclSyntax(accessorSpecifier: .keyword(.get)) { + "fatalError()" + }, + ] + } +}