基本上,我有一个宏,它被给定了一些协议,我想输出如下内容作为PeerMacro:

输入:

protocol MyProtocol {
    func myFunction(value1: Int, value2: String)
}

输出:

class MyProtocolMock: MyProtocol {
    enum Call {
        case myFunction(Int, String)
    }
    func myFunction(value1: Int, value2: String) {
        calls.append(.myFunction(value1, value2))
    }
}

我有它的大部分工作,我得到了以下一点:

func make(from function: FunctionDeclSyntax) throws -> FunctionDeclSyntax {
    FunctionDeclSyntax(name: function.name, signature: function.signature) {
        // how to extract the function param names and add here as enum associated values?
        "calls.append(.\(function.name)())"
    }
}

对于更多上下文,来自参数的function: FunctionDeclSyntax来自使用proto.memberBlock.members.compactMap { $0.decl.as(FunctionDeclSyntax.self) }ProtocolDeclSyntax,并且协议来自从PeerMacro的根调用declaration.as(ProtocolDeclSyntax.self)

如何从函数params初始化枚举中的相关值?

推荐答案

在函数声明中,参数要么有一个名称,要么有两个名称(参数标签和内部名称).如果存在第二个名称,我们应该在函数体中使用该第二个名称.然后,您所需要知道的就是您需要创建的AST node 的类型.你可以用Swift AST Explorer个就知道了.

static func make(from function: FunctionDeclSyntax) -> FunctionDeclSyntax {
    FunctionDeclSyntax(name: function.name, signature: function.signature) {
        let labeledParameters = LabeledExprListSyntax {
            for param in function.signature.parameterClause.parameters {
                if let secondName = param.secondName {
                    LabeledExprSyntax(expression: DeclReferenceExprSyntax(baseName: secondName))
                } else {
                    LabeledExprSyntax(expression: DeclReferenceExprSyntax(baseName: param.firstName))
                }
            }
        }
        "calls.append(.\(function.name)(\(labeledParameters))"
    }
}

这假设Call枚举的相关值总是没有参数标签,即case myFunction(Int, String)而不是case myFunction(value1: Int, value2: String)

这种模拟方法适用于函数返回Void并且其参数类型都是类/ struct /枚举之类的"简单类型"的情况.如果其中一个函数具有非转义闭包,则这将不起作用.如果该函数是泛型的,这也不会起作用.

Swift相关问答推荐

是否有一个Kotlin等价的Swift s @ AddendableReport注释'

RealityKit如何获得两个相对大小相同的ModelEntity?

Swift:iVar + Equatable上的协议约束

我可以为UIMenu设定一个固定的订单吗?

同时具有每个文本的标识符的文本组的可扩展性标识符

ToolbarItem 包含在动画中但不应该包含在动画中

我如何在 swift 中的 viewdidload 之前进行委托?

在Swift中如何用变量计算0.9的立方

Swift 数组拆分成重叠的块

使用 swift 的 Firebase 身份验证

如何制作进度加载动画?

确定路径是否相交的有效方法

响应 UITextField (UIViewRepresentable) 中的特定按键

对齐时如何避免图像尺寸缩小

SwiftUI 中的计时器崩溃屏幕

Xcode 13.3 将函数调用更改为属性访问

在 ViewController 的 UICollectionView 中拉取刷新

在 Xcode 中自动实现 Swift 协议方法

如何实现 Swift 的 Comparable 协议?

Swift 3.0 的 stringByReplacingOccurencesOfString()