Skip to content

Add an accessor macro example #2565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import SwiftSyntax
import SwiftSyntaxMacros

public struct EnvironmentValueMacro: AccessorMacro {
public static func expansion(
of node: AttributeSyntax,
providingAccessorsOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [AccessorDeclSyntax] {
guard
case let .argumentList(arguments) = node.arguments,
let argument = arguments.first
else { return [] }

return [
"""
get { self[\(argument.expression)] }
""",
"""
set { self[\(argument.expression)] = newValue }
""",
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct MyPlugin: CompilerPlugin {
DefaultFatalErrorImplementationMacro.self,
DictionaryStorageMacro.self,
DictionaryStoragePropertyMacro.self,
EnvironmentValueMacro.self,
EquatableExtensionMacro.self,
FontLiteralMacro.self,
FuncUniqueMacro.self,
Expand Down
24 changes: 24 additions & 0 deletions Examples/Sources/MacroExamples/Interface/AccessorMacros.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#if canImport(SwiftUI)

import SwiftUI
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example won’t compile on Linux and Windows if it depends on SwiftUI.

We’ve got two options here: Either wrap the macro in #if canImport(SwiftUI) or change it so it doesn’t depend on SwiftUI. Which one would you prefer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for proposing two options!
I'll choose the #if canImport(SwiftUI) option this time 🙏

b795cd8


// MARK: - EnvironmentValue Accessor

/// Adds getter / setter to an attached environment value with specified EnvironmentKey
@attached(accessor)
public macro EnvironmentValue(for key: any EnvironmentKey.Type) =
#externalMacro(module: "MacroExamplesImplementation", type: "EnvironmentValueMacro")

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

// MARK: - EnvironmentValue Accessor

import MacroExamplesInterface

#if canImport(SwiftUI)

import SwiftUI

private struct MyEnvironmentKey: EnvironmentKey {
static let defaultValue: String = "Default value"
}

extension EnvironmentValues {
@EnvironmentValue(for: MyEnvironmentKey.self)
var myCustomValue: String
}

func runEnvironmentValueAccessorMacroPlayground() {
var environmentValues = EnvironmentValues()
print("Default myCustomValue: \(environmentValues.myCustomValue)")
environmentValues.myCustomValue = "New value"
print("New myCustomValue: \(environmentValues.myCustomValue)")
}

#endif
8 changes: 8 additions & 0 deletions Examples/Sources/MacroExamples/Playground/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ runMemberMacrosPlayground()
// MARK: - Peer Macros

runPeerMacrosPlayground()

// MARK: - Accessor Macros

#if canImport(SwiftUI)

runEnvironmentValueAccessorMacroPlayground()

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import MacroExamplesImplementation
import SwiftSyntaxMacros
import SwiftSyntaxMacrosTestSupport
import XCTest

final class EnvironmentValueMacroMacroTests: XCTestCase {
private let macros = ["EnvironmentValue": EnvironmentValueMacro.self]

func testEnvironmentValue() {
assertMacroExpansion(
"""
extension EnvironmentValues {
@EnvironmentValue(for: MyEnvironmentKey.self)
var myCustomValue: String
}
""",
expandedSource: """
extension EnvironmentValues {
var myCustomValue: String {
get {
self[MyEnvironmentKey.self]
}
set {
self[MyEnvironmentKey.self] = newValue
}
}
}
""",
macros: macros
)
}
}