|
| 1 | +import SwiftSyntax |
| 2 | +import SwiftSyntaxBuilder |
| 3 | +import SwiftSyntaxMacros |
| 4 | +import Foundation |
| 5 | + |
| 6 | +public struct ConformToHashable: ExtensionMacro { |
| 7 | + public static func expansion(of node: SwiftSyntax.AttributeSyntax, |
| 8 | + attachedTo declaration: some SwiftSyntax.DeclGroupSyntax, |
| 9 | + providingExtensionsOf type: some SwiftSyntax.TypeSyntaxProtocol, |
| 10 | + conformingTo protocols: [SwiftSyntax.TypeSyntax], |
| 11 | + in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.ExtensionDeclSyntax] { |
| 12 | + guard [SwiftSyntax.SyntaxKind.classDecl].contains(declaration.kind) else { |
| 13 | + throw MacroDiagnostics.errorMacroUsage(message: "Can only be applied to a class type") |
| 14 | + } |
| 15 | + let equatableProtocol = InheritanceClauseSyntax(inheritedTypes: InheritedTypeListSyntax( |
| 16 | + arrayLiteral: InheritedTypeSyntax(type: TypeSyntax(stringLiteral: "Hashable"))) |
| 17 | + ) |
| 18 | + |
| 19 | + let mambers = declaration.memberBlock.members.compactMap { member in |
| 20 | + if let patternBinding = member.decl.as(VariableDeclSyntax.self)?.bindings |
| 21 | + .as(PatternBindingListSyntax.self)?.first?.as(PatternBindingSyntax.self), |
| 22 | + let identifier = patternBinding.pattern.as(IdentifierPatternSyntax.self)?.identifier, |
| 23 | + let type = patternBinding.typeAnnotation?.as(TypeAnnotationSyntax.self)?.type { |
| 24 | + if type.is(IdentifierTypeSyntax.self) { |
| 25 | + return "hasher.combine(\(identifier))" |
| 26 | + } |
| 27 | + if let wrappedType = type.as(OptionalTypeSyntax.self)?.wrappedType, |
| 28 | + wrappedType.is(IdentifierTypeSyntax.self) { |
| 29 | + return "hasher.combine(\(identifier))" |
| 30 | + } |
| 31 | + } |
| 32 | + return nil |
| 33 | + }.joined(separator: "\n ") |
| 34 | + |
| 35 | + let equtableFunction = """ |
| 36 | + func hash(into hasher: inout Hasher) { |
| 37 | + \(mambers) |
| 38 | + } |
| 39 | + """ |
| 40 | + |
| 41 | + let member = MemberBlockSyntax(members: MemberBlockItemListSyntax(stringLiteral: equtableFunction)) |
| 42 | + let extensionDecl = ExtensionDeclSyntax(extendedType: type, |
| 43 | + inheritanceClause: equatableProtocol, |
| 44 | + memberBlock: member) |
| 45 | + return [extensionDecl] |
| 46 | + } |
| 47 | +} |
0 commit comments