// The Swift Programming Language // https://docs.swift.org/swift-book import SwiftSyntax import SwiftSyntaxBuilder import SwiftSyntaxMacros import SwiftDiagnostics import Foundation // 宏实现:自动生成 Codable 协议的实现 public struct AutoCodableMacro: MemberMacro { public static func expansion( of node: AttributeSyntax, providingMembersOf declaration: some DeclGroupSyntax, in context: some MacroExpansionContext ) throws -> [DeclSyntax] { // 仅支持类和结构体 guard let typeDecl: DeclGroupSyntax = declaration.as(ClassDeclSyntax.self) ?? declaration.as(StructDeclSyntax.self) else { context.diagnose( Diagnostic( node: node, message: AutoCodableMacroError.onlyClassesAndStructs ) ) return [] } // 提取所有存储属性 let properties: [(name: String, type: String)] = typeDecl.memberBlock.members.compactMap { member -> (name: String, type: String)? in // 1. 检查是否是变量声明 guard let variableDecl = member.decl.as(VariableDeclSyntax.self) else { return nil } // 2. 确保只处理单个属性的声明 guard variableDecl.bindings.count == 1, let binding = variableDecl.bindings.first else { return nil } // 3. 提取属性名称 guard let identifierPattern = binding.pattern.as(IdentifierPatternSyntax.self) else { return nil } let name = identifierPattern.identifier.text // 4. 提取属性类型 guard let typeAnnotation = binding.typeAnnotation else { return nil } let type = typeAnnotation.type.description.trimmingCharacters(in: .whitespacesAndNewlines) return (name: name, type: type) } if properties.isEmpty { context.diagnose( Diagnostic( node: node, message: AutoCodableMacroError.noStoredProperties ) ) } // 生成 CodingKeys 枚举 let codingKeys = try EnumDeclSyntax("enum CodingKeys: String, CodingKey") { for property in properties { DeclSyntax("case \(raw: property.name)") } } // 生成 init(from:) 方法 let bodyBuilder: SyntaxNodeString = declaration is ClassDeclSyntax ? "required init(from decoder: Decoder) throws" : "init(from decoder: Decoder) throws" let initFrom = try InitializerDeclSyntax(bodyBuilder) { CodeBlockItemListSyntax { "let container = try decoder.container(keyedBy: CodingKeys.self)" for property in properties { """ if let value = try? container.decode(\(raw: property.type).self, forKey: .\(raw: property.name)) { self.\(raw: property.name) = value } """ } } } // 生成 encode(to:) 方法 let encodeTo = try FunctionDeclSyntax("func encode(to encoder: Encoder) throws") { CodeBlockItemListSyntax { "var container = encoder.container(keyedBy: CodingKeys.self)" for property in properties { "try container.encode(\(raw: property.name), forKey: .\(raw: property.name))" } } } return [ DeclSyntax(codingKeys), DeclSyntax(initFrom), DeclSyntax(encodeTo) ] } } // 错误提示定义 enum AutoCodableMacroError: DiagnosticMessage { case onlyClassesAndStructs case noStoredProperties var message: String { switch self { case .onlyClassesAndStructs: "AutoCodable can only be applied to classes and structs" case .noStoredProperties: "Type has no stored properties; Codable implementation will be empty" } } var diagnosticID: MessageID { .init(domain: "Codable", id: "\(self)") } var severity: DiagnosticSeverity { .error } }