Conversation
Only treat #if config blocks as conditional imports when they contain imports exclusively. This preserves existing import parsing while allowing the visitor to traverse blocks that contain @mockable protocols or other declarations.
sidepelican
left a comment
There was a problem hiding this comment.
Hmm, I think the containsOnlyImports approach is a bit tricky.
Ideally, I'd like to generate mocks while preserving the structure of the #if directive.
Without #if, isn't it just a coincidence that mock implementations can be used?
900f675 to
bd45f5f
Compare
|
Had to add a missing closing bracket - sorry about the delay.
I'll dive in and see about preserving the structure of the |
fummicc1
left a comment
There was a problem hiding this comment.
I'd prefer not to add ifConfigContext to Entity. Inside the very same top-level #if scope, ConditionalImportBlock already models the IfConfigDeclSyntax as a tree where each Clause owns its contents.
With this PR, entities inside the exact same AST node would instead be modeled as a flat list with back-references from Entity to its parent clause. Having two opposite ownership directions for the same #if construct is likely to become a maintenance hazard — and IfMacroModel (used for member-level #ifs inside types) also follows the same tree-ownership pattern, so this would be the only outlier in the codebase.
Could we instead add an entities property to ConditionalImportBlock.Clause (or introduce a unified ConditionalBlock that owns both imports and entities)?
Took a bit longer than expected, got caught up on TemplateRenderer, got some help and got it sorted. |
This PR fixes a regression where protocols (and other mockable entities) inside #if blocks were not being discovered for mock generation. The issue was introduced by changes in PR #328 that made the visitor treat all non-fileMacro #if blocks as conditional import
blocks, even when they contained declarations like protocols.
Problem
For non-fileMacro #if blocks, the visitor now always:
This is correct for import-only blocks, but incorrect for blocks containing declarations. In those cases, protocols, classes, and other declarations are never visited, so mockable entities are not discovered.
Solution
Unified handling of all #if blocks with context preservation:
Added IfConfigContext — A new struct that tracks which #if clause an entity was found in, storing the block offset, clause type (#if/#elseif/#else), and clause index.
Refactored #if block processing — A new processTopLevelIfConfig method iterates through all clauses in an #if block, collecting imports as conditional blocks while also discovering and tagging protocols/classes with their IfConfigContext.
Reconstructed #if directives in output — The template renderer groups entities by their IfConfigContext and wraps generated mocks in the same #if/#elseif/#else/#endif structure as the source protocols.