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))) ) } ) ) } ) ) } )
关键修改点
- 用
AccessorDeclSyntax创建get访问器,明确指定kind: .keyword(.get) - 将返回表达式放入
CodeBlockSyntax的statements中,作为访问器的实现体 - 把访问器实例放入
AccessorDeclListSyntax,再传入AccessorBlockSyntax的accessors参数
这样生成的代码就能正确包含属性的访问器块,完全符合预期的Mock类结构。
内容的提问来源于stack exchange,提问作者AndreiVataselu
相关产品推荐
相关产品推荐

