From ab9368169633b6f81e56845849f007e7b533aea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ba=CC=A8k?= Date: Wed, 20 Sep 2023 09:48:54 +0200 Subject: [PATCH 1/6] Move `FuncUniqueMacro` from `ExamplePlugin` to `MacroExamples` target --- .../Declaration/FuncUniqueMacro.swift | 32 +++++++++++++++++ .../MacroExamples/Implementation/Plugin.swift | 1 + .../Interface/DeclarationMacros.swift | 16 +++++++++ .../DeclarationMacrosPlayground.swift | 21 +++++++++++ .../MacroExamples/Playground/main.swift | 2 +- .../Declaration/FuncUniqueMacroTests.swift | 36 +++++++++++++++++++ 6 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 Examples/Sources/MacroExamples/Implementation/Declaration/FuncUniqueMacro.swift create mode 100644 Examples/Sources/MacroExamples/Interface/DeclarationMacros.swift create mode 100644 Examples/Sources/MacroExamples/Playground/DeclarationMacrosPlayground.swift create mode 100644 Examples/Tests/MacroExamples/Implementation/Declaration/FuncUniqueMacroTests.swift diff --git a/Examples/Sources/MacroExamples/Implementation/Declaration/FuncUniqueMacro.swift b/Examples/Sources/MacroExamples/Implementation/Declaration/FuncUniqueMacro.swift new file mode 100644 index 00000000000..9f495c98470 --- /dev/null +++ b/Examples/Sources/MacroExamples/Implementation/Declaration/FuncUniqueMacro.swift @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 SwiftSyntaxBuilder +import SwiftSyntaxMacros + +/// Func With unique name. +public enum FuncUniqueMacro: DeclarationMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + let name = context.makeUniqueName("unique") + return [ + """ + class MyClass { + func \(name)() {} + } + """ + ] + } +} diff --git a/Examples/Sources/MacroExamples/Implementation/Plugin.swift b/Examples/Sources/MacroExamples/Implementation/Plugin.swift index f798d8285a9..d626ccfa7e9 100644 --- a/Examples/Sources/MacroExamples/Implementation/Plugin.swift +++ b/Examples/Sources/MacroExamples/Implementation/Plugin.swift @@ -35,6 +35,7 @@ struct MyPlugin: CompilerPlugin { OptionSetMacro.self, NewTypeMacro.self, URLMacro.self, + FuncUniqueMacro.self, ] } #endif diff --git a/Examples/Sources/MacroExamples/Interface/DeclarationMacros.swift b/Examples/Sources/MacroExamples/Interface/DeclarationMacros.swift new file mode 100644 index 00000000000..edc7d48d79b --- /dev/null +++ b/Examples/Sources/MacroExamples/Interface/DeclarationMacros.swift @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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: - Func Unique + +@freestanding(declaration, names: named(MyClass)) +public macro FuncUnique() = #externalMacro(module: "MacroExamplesImplementation", type: "FuncUniqueMacro") diff --git a/Examples/Sources/MacroExamples/Playground/DeclarationMacrosPlayground.swift b/Examples/Sources/MacroExamples/Playground/DeclarationMacrosPlayground.swift new file mode 100644 index 00000000000..56d7b57900b --- /dev/null +++ b/Examples/Sources/MacroExamples/Playground/DeclarationMacrosPlayground.swift @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 MacroExamplesInterface + +// MARK: - Func Unique + +#FuncUnique + +func runFuncUniqueMacroPlayground() { + print("My Class Declaration with unique method: ", MyClass()) +} diff --git a/Examples/Sources/MacroExamples/Playground/main.swift b/Examples/Sources/MacroExamples/Playground/main.swift index 3a6de158f84..90b8f1e3dbd 100644 --- a/Examples/Sources/MacroExamples/Playground/main.swift +++ b/Examples/Sources/MacroExamples/Playground/main.swift @@ -24,7 +24,7 @@ runObservableMacroPlayground() // MARK: - Declaration Macros -// TODO: Add example of declaration macro +runFuncUniqueMacroPlayground() // MARK: - Expression Macros diff --git a/Examples/Tests/MacroExamples/Implementation/Declaration/FuncUniqueMacroTests.swift b/Examples/Tests/MacroExamples/Implementation/Declaration/FuncUniqueMacroTests.swift new file mode 100644 index 00000000000..216a867ef77 --- /dev/null +++ b/Examples/Tests/MacroExamples/Implementation/Declaration/FuncUniqueMacroTests.swift @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 FuncUniqueMacroTests: XCTestCase { + private let macros = ["FuncUnique": FuncUniqueMacro.self] + + func testExpansionCreatesDeclarationWithUniqueFunction() { + assertMacroExpansion( + """ + #FuncUnique() + """, + expandedSource: #""" + class MyClass { + func __macro_local_6uniquefMu_() { + } + } + """#, + macros: macros, + indentationWidth: .spaces(2) + ) + } +} From 69b68ca9a142070c63f755778ca875d220c48b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ba=CC=A8k?= Date: Wed, 20 Sep 2023 12:24:36 +0200 Subject: [PATCH 2/6] Move `PeerValueWithSuffixNameMacro` from `ExamplePlugin` to `MacroExamples` target --- .../Peer/PeerValueWithSuffixNameMacro.swift | 28 +++++++ .../MacroExamples/Implementation/Plugin.swift | 1 + .../MacroExamples/Interface/PeerMacros.swift | 5 ++ .../Playground/PeerMacrosPlayground.swift | 11 +++ .../PeerValueWithSuffixNameMacroTests.swift | 74 +++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 Examples/Sources/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacro.swift create mode 100644 Examples/Tests/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacroTests.swift diff --git a/Examples/Sources/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacro.swift b/Examples/Sources/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacro.swift new file mode 100644 index 00000000000..1e0aa915c25 --- /dev/null +++ b/Examples/Sources/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacro.swift @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 + +/// Peer 'var' with the name suffixed with '_peer'. +public enum PeerValueWithSuffixNameMacro: PeerMacro { + public static func expansion( + of node: AttributeSyntax, + providingPeersOf declaration: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + guard let identified = declaration.asProtocol(NamedDeclSyntax.self) else { + return [] + } + return ["var \(raw: identified.name.text)_peer: Int { 1 }"] + } +} diff --git a/Examples/Sources/MacroExamples/Implementation/Plugin.swift b/Examples/Sources/MacroExamples/Implementation/Plugin.swift index d626ccfa7e9..7fddf9d97e9 100644 --- a/Examples/Sources/MacroExamples/Implementation/Plugin.swift +++ b/Examples/Sources/MacroExamples/Implementation/Plugin.swift @@ -36,6 +36,7 @@ struct MyPlugin: CompilerPlugin { NewTypeMacro.self, URLMacro.self, FuncUniqueMacro.self, + PeerValueWithSuffixNameMacro.self, ] } #endif diff --git a/Examples/Sources/MacroExamples/Interface/PeerMacros.swift b/Examples/Sources/MacroExamples/Interface/PeerMacros.swift index b16c8039410..6d59cdc806c 100644 --- a/Examples/Sources/MacroExamples/Interface/PeerMacros.swift +++ b/Examples/Sources/MacroExamples/Interface/PeerMacros.swift @@ -22,3 +22,8 @@ public macro AddAsync() = #externalMacro(module: "MacroExamplesImplementation", /// handler. @attached(peer, names: overloaded) public macro AddCompletionHandler() = #externalMacro(module: "MacroExamplesImplementation", type: "AddCompletionHandlerMacro") + +// MARK: - Peer Value With Suffix Name + +@attached(peer, names: suffixed(_peer)) +public macro PeerValueWithSuffixName() = #externalMacro(module: "MacroExamplesImplementation", type: "PeerValueWithSuffixNameMacro") diff --git a/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift b/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift index 9030e7859c0..a4b88c66e35 100644 --- a/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift +++ b/Examples/Sources/MacroExamples/Playground/PeerMacrosPlayground.swift @@ -46,4 +46,15 @@ func runPeerMacrosPlayground() { MyClass().f(a: 1, for: "hello", 3.14159) { result in print("Eventually received \(result + "!")") } + + // MARK: - Peer Value With Suffix Name + + @PeerValueWithSuffixName + actor Counter { + var value = 0 + } + + let counter = Counter() + + // print("Peer value with suffix name for \(Counter.self): \(String(describing: Counter_peer))") } diff --git a/Examples/Tests/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacroTests.swift b/Examples/Tests/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacroTests.swift new file mode 100644 index 00000000000..e0aa172688b --- /dev/null +++ b/Examples/Tests/MacroExamples/Implementation/Peer/PeerValueWithSuffixNameMacroTests.swift @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 PeerValueWithSuffixNameMacroTests: XCTestCase { + private let macros = ["PeerValueWithSuffixName": PeerValueWithSuffixNameMacro.self] + + func testExpansionAddsPeerValueToPrivateActor() { + assertMacroExpansion( + """ + @PeerValueWithSuffixName + private actor Counter { + var value = 0 + } + """, + expandedSource: """ + private actor Counter { + var value = 0 + } + + var Counter_peer: Int { + 1 + } + """, + macros: macros, + indentationWidth: .spaces(2) + ) + } + + func testExpansionAddsPeerValueToFunction() { + assertMacroExpansion( + """ + @PeerValueWithSuffixName + func someFunction() {} + """, + expandedSource: """ + func someFunction() {} + + var someFunction_peer: Int { + 1 + } + """, + macros: macros, + indentationWidth: .spaces(2) + ) + } + + func testExpansionIgnoresVariables() { + assertMacroExpansion( + """ + @PeerValueWithSuffixName + var someVariable: Int + """, + expandedSource: """ + var someVariable: Int + """, + macros: macros, + indentationWidth: .spaces(2) + ) + } +} From cb105c1df087b3850258ec1509b2821c7dd08ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ba=CC=A8k?= Date: Wed, 20 Sep 2023 12:42:03 +0200 Subject: [PATCH 3/6] Move `MemberDeprecatedMacro` from `ExamplePlugin` to `MacroExamples` target --- .../MemberDeprecatedMacro.swift | 26 +++++++++ .../MacroExamples/Implementation/Plugin.swift | 1 + .../Interface/MemberAttributeMacros.swift | 5 ++ .../MemberAttributeMacrosPlayground.swift | 20 +++++++ .../MemberDeprecatedMacroTests.swift | 53 +++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 Examples/Sources/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacro.swift create mode 100644 Examples/Tests/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacroTests.swift diff --git a/Examples/Sources/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacro.swift b/Examples/Sources/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacro.swift new file mode 100644 index 00000000000..27f7418cbc7 --- /dev/null +++ b/Examples/Sources/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacro.swift @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 + +/// Add '@available(*, deprecated)' to members. +public enum MemberDeprecatedMacro: MemberAttributeMacro { + public static func expansion( + of node: AttributeSyntax, + attachedTo declaration: some DeclGroupSyntax, + providingAttributesFor member: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [AttributeSyntax] { + return ["@available(*, deprecated)"] + } +} diff --git a/Examples/Sources/MacroExamples/Implementation/Plugin.swift b/Examples/Sources/MacroExamples/Implementation/Plugin.swift index 7fddf9d97e9..e4750bb6daa 100644 --- a/Examples/Sources/MacroExamples/Implementation/Plugin.swift +++ b/Examples/Sources/MacroExamples/Implementation/Plugin.swift @@ -37,6 +37,7 @@ struct MyPlugin: CompilerPlugin { URLMacro.self, FuncUniqueMacro.self, PeerValueWithSuffixNameMacro.self, + MemberDeprecatedMacro.self, ] } #endif diff --git a/Examples/Sources/MacroExamples/Interface/MemberAttributeMacros.swift b/Examples/Sources/MacroExamples/Interface/MemberAttributeMacros.swift index ebaf056499d..bdfe4a64372 100644 --- a/Examples/Sources/MacroExamples/Interface/MemberAttributeMacros.swift +++ b/Examples/Sources/MacroExamples/Interface/MemberAttributeMacros.swift @@ -10,6 +10,11 @@ // //===----------------------------------------------------------------------===// +// MARK: - Member Deprecated + +@attached(memberAttribute) +public macro memberDeprecated() = #externalMacro(module: "MacroExamplesImplementation", type: "MemberDeprecatedMacro") + // MARK: - Wrap Stored Properties /// Apply the specified attribute to each of the stored properties within the diff --git a/Examples/Sources/MacroExamples/Playground/MemberAttributeMacrosPlayground.swift b/Examples/Sources/MacroExamples/Playground/MemberAttributeMacrosPlayground.swift index 11ff1d3458e..e61ca95dde4 100644 --- a/Examples/Sources/MacroExamples/Playground/MemberAttributeMacrosPlayground.swift +++ b/Examples/Sources/MacroExamples/Playground/MemberAttributeMacrosPlayground.swift @@ -10,9 +10,29 @@ // //===----------------------------------------------------------------------===// +import Foundation import MacroExamplesInterface func runMemberAttributeMacrosPlayground() { + // MARK: - Member Deprecated + + @memberDeprecated + struct SomeStruct { + typealias MacroName = String + + var oldProperty: Int = 420 + + func oldMethod() { + print("This is an old method.") + } + } + + let someStruct = SomeStruct() + + _ = SomeStruct.MacroName("name") + _ = someStruct.oldProperty + someStruct.oldMethod() + // MARK: - Wrap Stored Properties // Use the "wrapStoredProperties" macro to deprecate all of the stored diff --git a/Examples/Tests/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacroTests.swift b/Examples/Tests/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacroTests.swift new file mode 100644 index 00000000000..2b7d6e69446 --- /dev/null +++ b/Examples/Tests/MacroExamples/Implementation/MemberAttribute/MemberDeprecatedMacroTests.swift @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 MemberDeprecatedMacroTests: XCTestCase { + private let macros = ["memberDeprecated": MemberDeprecatedMacro.self] + + func testExpansionMarksMembersAsDeprecated() { + assertMacroExpansion( + """ + @memberDeprecated + public struct SomeStruct { + typealias MacroName = String + + public var oldProperty: Int = 420 + + func oldMethod() { + print("This is an old method.") + } + } + """, + expandedSource: """ + public struct SomeStruct { + @available(*, deprecated) + typealias MacroName = String + @available(*, deprecated) + + public var oldProperty: Int = 420 + @available(*, deprecated) + + func oldMethod() { + print("This is an old method.") + } + } + """, + macros: macros, + indentationWidth: .spaces(2) + ) + } +} From 2ae060c802d36bb1b22b1ed5f4dbec69a024e488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ba=CC=A8k?= Date: Wed, 20 Sep 2023 13:30:18 +0200 Subject: [PATCH 4/6] Move `EquatableExtensionMacro` from `ExamplePlugin` to `MacroExamples` target --- .../Extension/EquatableExtensionMacro.swift | 28 ++++++++++++ .../MacroExamples/Implementation/Plugin.swift | 1 + .../Interface/ExtensionMacros.swift | 16 +++++++ .../ExtensionMacrosPlayground.swift | 27 ++++++++++++ .../MacroExamples/Playground/main.swift | 2 +- .../EquatableExtensionMacroTests.swift | 43 +++++++++++++++++++ 6 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 Examples/Sources/MacroExamples/Implementation/Extension/EquatableExtensionMacro.swift create mode 100644 Examples/Sources/MacroExamples/Interface/ExtensionMacros.swift create mode 100644 Examples/Sources/MacroExamples/Playground/ExtensionMacrosPlayground.swift create mode 100644 Examples/Tests/MacroExamples/Implementation/Extension/EquatableExtensionMacroTests.swift diff --git a/Examples/Sources/MacroExamples/Implementation/Extension/EquatableExtensionMacro.swift b/Examples/Sources/MacroExamples/Implementation/Extension/EquatableExtensionMacro.swift new file mode 100644 index 00000000000..f13cf986a1f --- /dev/null +++ b/Examples/Sources/MacroExamples/Implementation/Extension/EquatableExtensionMacro.swift @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 enum EquatableExtensionMacro: ExtensionMacro { + public static func expansion( + of node: AttributeSyntax, + attachedTo declaration: some DeclGroupSyntax, + providingExtensionsOf type: some TypeSyntaxProtocol, + conformingTo protocols: [TypeSyntax], + in context: some MacroExpansionContext + ) throws -> [ExtensionDeclSyntax] { + let equatableExtension = try ExtensionDeclSyntax("extension \(type.trimmed): Equatable {}") + + return [equatableExtension] + } +} diff --git a/Examples/Sources/MacroExamples/Implementation/Plugin.swift b/Examples/Sources/MacroExamples/Implementation/Plugin.swift index e4750bb6daa..5c93cdfbe15 100644 --- a/Examples/Sources/MacroExamples/Implementation/Plugin.swift +++ b/Examples/Sources/MacroExamples/Implementation/Plugin.swift @@ -38,6 +38,7 @@ struct MyPlugin: CompilerPlugin { FuncUniqueMacro.self, PeerValueWithSuffixNameMacro.self, MemberDeprecatedMacro.self, + EquatableExtensionMacro.self, ] } #endif diff --git a/Examples/Sources/MacroExamples/Interface/ExtensionMacros.swift b/Examples/Sources/MacroExamples/Interface/ExtensionMacros.swift new file mode 100644 index 00000000000..73f5c8e05a5 --- /dev/null +++ b/Examples/Sources/MacroExamples/Interface/ExtensionMacros.swift @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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: - Equatable Extension + +@attached(extension, conformances: Equatable) +public macro equatable() = #externalMacro(module: "MacroExamplesImplementation", type: "EquatableExtensionMacro") diff --git a/Examples/Sources/MacroExamples/Playground/ExtensionMacrosPlayground.swift b/Examples/Sources/MacroExamples/Playground/ExtensionMacrosPlayground.swift new file mode 100644 index 00000000000..272ff6be723 --- /dev/null +++ b/Examples/Sources/MacroExamples/Playground/ExtensionMacrosPlayground.swift @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 MacroExamplesInterface + +// MARK: - Equatable Extension + +@equatable +struct Pet { + let name: String +} + +func runEquatableExtensionMacroPlayground() { + let cat = Pet(name: "Tom") + let mouse = Pet(name: "Jerry") + + print("Has the cat \(cat) the same name as the mouse \(mouse)?", cat == mouse ? "Yes." : "No.") +} diff --git a/Examples/Sources/MacroExamples/Playground/main.swift b/Examples/Sources/MacroExamples/Playground/main.swift index 90b8f1e3dbd..410907a4ebd 100644 --- a/Examples/Sources/MacroExamples/Playground/main.swift +++ b/Examples/Sources/MacroExamples/Playground/main.swift @@ -32,7 +32,7 @@ runExpressionMacrosPlayground() // MARK: - Extension Macros -// TODO: Add example of extension macro +runEquatableExtensionMacroPlayground() // MARK: - Member Attribute Macros diff --git a/Examples/Tests/MacroExamples/Implementation/Extension/EquatableExtensionMacroTests.swift b/Examples/Tests/MacroExamples/Implementation/Extension/EquatableExtensionMacroTests.swift new file mode 100644 index 00000000000..9a3053f9322 --- /dev/null +++ b/Examples/Tests/MacroExamples/Implementation/Extension/EquatableExtensionMacroTests.swift @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 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 EquatableExtensionMacroTests: XCTestCase { + private let macros = ["equatable": EquatableExtensionMacro.self] + + func testExpansionAddsExtensionWithEquatableConformance() { + assertMacroExpansion( + """ + @equatable + final public class Message { + let text: String + let sender: String + } + """, + expandedSource: """ + final public class Message { + let text: String + let sender: String + } + + extension Message: Equatable { + } + """, + macros: macros, + indentationWidth: .spaces(2) + ) + } +} From 18fe285154058bc1de6f9f581231ad7acfd5226c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ba=CC=A8k?= Date: Wed, 20 Sep 2023 14:18:12 +0200 Subject: [PATCH 5/6] Remove `ExamplePlugin` target --- Examples/Package.swift | 10 -- .../Sources/ExamplePlugin/ExamplePlugin.swift | 17 -- Examples/Sources/ExamplePlugin/Macros.swift | 145 ------------------ 3 files changed, 172 deletions(-) delete mode 100644 Examples/Sources/ExamplePlugin/ExamplePlugin.swift delete mode 100644 Examples/Sources/ExamplePlugin/Macros.swift diff --git a/Examples/Package.swift b/Examples/Package.swift index 5e25cbb86fc..02a0518cc03 100644 --- a/Examples/Package.swift +++ b/Examples/Package.swift @@ -11,7 +11,6 @@ let package = Package( products: [ .executable(name: "AddOneToIntegerLiterals", targets: ["AddOneToIntegerLiterals"]), .executable(name: "CodeGenerationUsingSwiftSyntaxBuilder", targets: ["CodeGenerationUsingSwiftSyntaxBuilder"]), - .executable(name: "ExamplePlugin", targets: ["ExamplePlugin"]), ], dependencies: [ .package(path: "../") @@ -30,15 +29,6 @@ let package = Package( .product(name: "SwiftSyntaxBuilder", package: "swift-syntax") ] ), - .executableTarget( - name: "ExamplePlugin", - dependencies: [ - .product(name: "SwiftCompilerPlugin", package: "swift-syntax"), - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), - .product(name: "SwiftDiagnostics", package: "swift-syntax"), - ] - ), .macro( name: "MacroExamplesImplementation", dependencies: [ diff --git a/Examples/Sources/ExamplePlugin/ExamplePlugin.swift b/Examples/Sources/ExamplePlugin/ExamplePlugin.swift deleted file mode 100644 index 9eab0b9b94b..00000000000 --- a/Examples/Sources/ExamplePlugin/ExamplePlugin.swift +++ /dev/null @@ -1,17 +0,0 @@ -import SwiftCompilerPlugin -import SwiftSyntaxMacros - -@main -struct ThePlugin: CompilerPlugin { - var providingMacros: [Macro.Type] = [ - EchoExpressionMacro.self, - FuncUniqueMacro.self, - MetadataMacro.self, - PeerValueWithSuffixNameMacro.self, - MemberDeprecatedMacro.self, - EquatableConformanceMacro.self, - SendableExtensionMacro.self, - DidSetPrintMacro.self, - PrintAnyMacro.self, - ] -} diff --git a/Examples/Sources/ExamplePlugin/Macros.swift b/Examples/Sources/ExamplePlugin/Macros.swift deleted file mode 100644 index 35e9b6baaff..00000000000 --- a/Examples/Sources/ExamplePlugin/Macros.swift +++ /dev/null @@ -1,145 +0,0 @@ -import SwiftSyntax -import SwiftSyntaxBuilder -import SwiftSyntaxMacros - -/// Returns the first argument prepending a comment '/* echo */'. -struct EchoExpressionMacro: ExpressionMacro { - static func expansion< - Node: FreestandingMacroExpansionSyntax, - Context: MacroExpansionContext - >( - of node: Node, - in context: Context - ) throws -> ExprSyntax { - let expr: ExprSyntax = node.arguments.first!.expression - return expr.with(\.leadingTrivia, [.blockComment("/* echo */")]) - } -} - -/// Func With unique name. -struct FuncUniqueMacro: DeclarationMacro { - static func expansion( - of node: some FreestandingMacroExpansionSyntax, - in context: some MacroExpansionContext - ) throws -> [DeclSyntax] { - let name = context.makeUniqueName("unique") - return ["func \(name)() {}"] - } -} - -/// Add a static property `__metadata__`. -struct MetadataMacro: MemberMacro { - static func expansion< - Declaration: DeclGroupSyntax, - Context: MacroExpansionContext - >( - of node: SwiftSyntax.AttributeSyntax, - providingMembersOf declaration: Declaration, - in context: Context - ) throws -> [DeclSyntax] { - guard let type = declaration.asProtocol(NamedDeclSyntax.self) else { - return [] - } - let typeName = type.name.trimmedDescription - return [ - """ - static var __metadata__: [String: String] { ["name": "\(raw: typeName)"] } - """ - ] - } -} - -/// Peer 'var' with the name suffixed with '_peer'. -struct PeerValueWithSuffixNameMacro: PeerMacro { - static func expansion( - of node: AttributeSyntax, - providingPeersOf declaration: some DeclSyntaxProtocol, - in context: some MacroExpansionContext - ) throws -> [DeclSyntax] { - guard let identified = declaration.asProtocol(NamedDeclSyntax.self) else { - return [] - } - return ["var \(raw: identified.name.text)_peer: Int { 1 }"] - } -} - -/// Add '@available(*, deprecated)' to members. -struct MemberDeprecatedMacro: MemberAttributeMacro { - static func expansion( - of node: SwiftSyntax.AttributeSyntax, - attachedTo declaration: some SwiftSyntax.DeclGroupSyntax, - providingAttributesFor member: some SwiftSyntax.DeclSyntaxProtocol, - in context: some SwiftSyntaxMacros.MacroExpansionContext - ) throws -> [SwiftSyntax.AttributeSyntax] { - return ["@available(*, deprecated)"] - } -} - -/// Add 'Equatable' conformance. -struct EquatableConformanceMacro: ExtensionMacro { - static func expansion( - of node: AttributeSyntax, - attachedTo declaration: some DeclGroupSyntax, - providingExtensionsOf type: some TypeSyntaxProtocol, - conformingTo protocols: [TypeSyntax], - in context: some MacroExpansionContext - ) throws -> [ExtensionDeclSyntax] { - let ext: DeclSyntax = "extension \(type.trimmed): Equatable {}" - return [ext.cast(ExtensionDeclSyntax.self)] - } -} - -public struct SendableExtensionMacro: ExtensionMacro { - public static func expansion( - of node: AttributeSyntax, - attachedTo: some DeclGroupSyntax, - providingExtensionsOf type: some TypeSyntaxProtocol, - conformingTo protocols: [TypeSyntax], - in context: some MacroExpansionContext - ) throws -> [ExtensionDeclSyntax] { - if protocols.isEmpty { - return [] - } - - let sendableExtension: DeclSyntax = - """ - extension \(type.trimmed): Sendable {} - """ - - guard let extensionDecl = sendableExtension.as(ExtensionDeclSyntax.self) else { - return [] - } - - return [extensionDecl] - } -} - -/// Add 'didSet' printing the new value. -struct DidSetPrintMacro: AccessorMacro { - static func expansion( - of node: AttributeSyntax, - providingAccessorsOf declaration: some DeclSyntaxProtocol, - in context: some MacroExpansionContext - ) throws -> [AccessorDeclSyntax] { - guard - let identifier = declaration.as(VariableDeclSyntax.self)?.bindings.first?.pattern.as(IdentifierPatternSyntax.self)?.identifier - else { - return [] - } - - return ["didSet { print(\(identifier)) }"] - } -} - -/// 'print()'. -struct PrintAnyMacro: CodeItemMacro { - static func expansion( - of node: some FreestandingMacroExpansionSyntax, - in context: some MacroExpansionContext - ) throws -> [CodeBlockItemSyntax] { - guard let expr = node.arguments.first?.expression else { - return [] - } - return ["print(\(expr))"] - } -} From 0c044f7fc5fa01c1c20f4e2d31d6a6f51f96a5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Ba=CC=A8k?= Date: Thu, 21 Sep 2023 22:46:32 +0200 Subject: [PATCH 6/6] Sort providing macros collection alphabetically --- .../MacroExamples/Implementation/Plugin.swift | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Examples/Sources/MacroExamples/Implementation/Plugin.swift b/Examples/Sources/MacroExamples/Implementation/Plugin.swift index 5c93cdfbe15..a123cc05b6c 100644 --- a/Examples/Sources/MacroExamples/Implementation/Plugin.swift +++ b/Examples/Sources/MacroExamples/Implementation/Plugin.swift @@ -17,28 +17,28 @@ import SwiftSyntaxMacros @main struct MyPlugin: CompilerPlugin { let providingMacros: [Macro.Type] = [ - StringifyMacro.self, + AddAsyncMacro.self, AddBlocker.self, - WarningMacro.self, - FontLiteralMacro.self, - WrapStoredPropertiesMacro.self, - DictionaryStorageMacro.self, - DictionaryStoragePropertyMacro.self, - ObservableMacro.self, - ObservablePropertyMacro.self, AddCompletionHandlerMacro.self, - AddAsyncMacro.self, CaseDetectionMacro.self, - MetaEnumMacro.self, CodableKey.self, CustomCodable.self, - OptionSetMacro.self, - NewTypeMacro.self, - URLMacro.self, + DictionaryStorageMacro.self, + DictionaryStoragePropertyMacro.self, + EquatableExtensionMacro.self, + FontLiteralMacro.self, FuncUniqueMacro.self, - PeerValueWithSuffixNameMacro.self, MemberDeprecatedMacro.self, - EquatableExtensionMacro.self, + MetaEnumMacro.self, + NewTypeMacro.self, + ObservableMacro.self, + ObservablePropertyMacro.self, + OptionSetMacro.self, + PeerValueWithSuffixNameMacro.self, + StringifyMacro.self, + URLMacro.self, + WarningMacro.self, + WrapStoredPropertiesMacro.self, ] } #endif