You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift宏问题:生成Mock类属性时未生成访问器块

Swift宏生成Mock属性时缺少访问器块的问题解决

问题场景

给协议添加@MyMock宏:

@MyMock
protocol SomeProtocolHere {
    var thisIsMyProperty: Bool { get } 
}

期望生成的Mock类:

class SomeProtocolHereMock: SomeProtocolHere {
    var thisIsMyPropertyMocked: Bool!
    var thisIsMyProperty: Bool { thisIsMyPropertyMocked }
}

实际生成的代码(缺少访问器块):

final class SomeProtocolHereMock: SomeProtocolHere {
    var somethingToReturnReturnValue: Bool!
    var somethingToReturn: Bool
}

用于生成属性的宏代码:

static func makeVariableMock(from variableDecl: VariableDeclSyntax) -> MemberBlockItemListSyntax {
    let returnValueVariableName = "\(variableDecl.name)ReturnValue"
    
    let mockedUnwrappedProperty = VariableDeclSyntax(
        modifiers:
            DeclModifierListSyntax {
                if variableDecl.isPublic {
                    DeclModifierSyntax(name: .keyword(.public))
                }
            },
        bindingSpecifier: .keyword(.var),
        bindings:
            PatternBindingListSyntax {
                PatternBindingSyntax(
                    pattern:
                        IdentifierPatternSyntax(identifier: .identifier(returnValueVariableName)),
                    typeAnnotation:
                        TypeAnnotationSyntax(type:
                                                ImplicitlyUnwrappedOptionalTypeSyntax(
                                                    wrappedType: IdentifierTypeSyntax(
                                                        name: TokenSyntax.identifier(variableDecl.type)))
                                                )
                )
                
            }
    )
    
    let originalVariable = VariableDeclSyntax(
        modifiers:
            DeclModifierListSyntax {
                if variableDecl.isPublic {
                    DeclModifierSyntax(name: .keyword(.public))
                }
            },
        bindingSpecifier: .keyword(.var),
        bindings:
            PatternBindingListSyntax {
                PatternBindingSyntax(
                    pattern:
                        IdentifierPatternSyntax(identifier: .identifier(variableDecl.name)),
                    typeAnnotation:
                        TypeAnnotationSyntax(type: IdentifierTypeSyntax(name: TokenSyntax.identifier(variableDecl.type))),
                    accessorBlock: AccessorBlockSyntax(
                        CodeBlockItemListSyntax {
                            CodeBlockItemSyntax(
                                item: .expr(ExprSyntax(fromProtocol: DeclReferenceExprSyntax(baseName: TokenSyntax.identifier(returnValueVariableName))))
                            )
                        }
                    ))
            }
    )
    
    return MemberBlockItemListSyntax {
        MemberBlockItemSyntax(decl: mockedUnwrappedProperty)
        MemberBlockItemSyntax(decl: originalVariable)
    }
}

问题原因

你创建AccessorBlockSyntax的方式错误,直接传入CodeBlockItemListSyntax不符合SwiftSyntax的结构要求。AccessorBlockSyntax需要包含具体的访问器声明(比如get访问器),而非直接放置表达式代码块。

修复方案

修改originalVariable中accessorBlock的创建逻辑,先构建get访问器,再将其放入AccessorBlockSyntax中:

let originalVariable = VariableDeclSyntax(
    modifiers:
        DeclModifierListSyntax {
            if variableDecl.isPublic {
                DeclModifierSyntax(name: .keyword(.public))
            }
        },
    bindingSpecifier: .keyword(.var),
    bindings:
        PatternBindingListSyntax {
            PatternBindingSyntax(
                pattern: IdentifierPatternSyntax(identifier: .identifier(variableDecl.name)),
                typeAnnotation: TypeAnnotationSyntax(type: IdentifierTypeSyntax(name: TokenSyntax.identifier(variableDecl.type))),
                accessorBlock: AccessorBlockSyntax(
                    accessors: AccessorDeclListSyntax {
                        AccessorDeclSyntax(
                            kind: .keyword(.get),
                            body: CodeBlockSyntax(
                                statements: CodeBlockItemListSyntax {
                                    CodeBlockItemSyntax(
                                        item: .expr(DeclReferenceExprSyntax(baseName: TokenSyntax.identifier(returnValueVariableName)))
                                    )
                                }
                            )
                        )
                    }
                )
            )
        }
)

关键修改点

  1. 用AccessorDeclSyntax创建get访问器,明确指定kind: .keyword(.get)
  2. 将返回表达式放入CodeBlockSyntax的statements中,作为访问器的实现体
  3. 把访问器实例放入AccessorDeclListSyntax,再传入AccessorBlockSyntax的accessors参数

这样生成的代码就能正确包含属性的访问器块,完全符合预期的Mock类结构。

内容的提问来源于stack exchange,提问作者AndreiVataselu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:36:02