Add support for conditionally compiled protocol members#137
Add support for conditionally compiled protocol members#137graycampbell merged 15 commits intomainfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #137 +/- ##
==========================================
+ Coverage 69.76% 73.34% +3.58%
==========================================
Files 73 73
Lines 3678 3846 +168
==========================================
+ Hits 2566 2821 +255
+ Misses 1112 1025 -87 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
IfConfigDeclSyntax support for conditional compilation in protocolsIfConfigDeclSyntax support for conditional compilation
graycampbell
left a comment
There was a problem hiding this comment.
Some comments/suggestions from my first pass through this
a0fc588 to
dce8d14
Compare
| var seenNames: Set<String> = [] | ||
| let uniqueAssociatedTypes = associatedTypeDeclarations.filter { decl in |
There was a problem hiding this comment.
| var seenNames: Set<String> = [] | |
| let uniqueAssociatedTypes = associatedTypeDeclarations.filter { decl in | |
| var seenNames = Set<String>() | |
| let uniqueAssociatedTypes = associatedTypeDeclarations.filter { | |
| seenNames.insert($0.name.text).inserted | |
| } |
Q: Does order matter? If not then Set(associatedTypeDeclarations) will work
graycampbell
left a comment
There was a problem hiding this comment.
There's a hole in how all of this is implemented at the moment. See my comment below about the mock's generic parameter constraints.
Protocols with #if/#elseif/#else/#endif blocks now have their members correctly mocked with the conditional compilation structure preserved. This includes support for methods, properties, initializers, and associated types within conditional blocks. Closes #136 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…sted conditionals - Move ifConfig processing inline in mockMemberBlock to match structure of other declaration types - Add unit tests for OR conditions (#if DEBUG || TESTFLIGHT) - Add unit tests for nested #if conditionals Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract mockMemberBlockItems helper that works on MemberBlockItemListSyntax - mockMemberBlock delegates to shared helper - mockIfConfigDeclaration uses shared helper directly - Remove mockIfConfigClause entirely (-46 lines) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a protocol defines the same associated type with different constraints across #if branches (e.g., Item: Equatable in DEBUG vs Item: Hashable otherwise), generate a mock class without constraints plus conditional extensions that conform with the appropriate constraints for each branch. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ed associatedType
0a1efbf to
835b842
Compare
graycampbell
left a comment
There was a problem hiding this comment.
There are still some issues with this implementation:
1) Nested #if blocks are not detected
conflictingConditionalClauses only checks for AssociatedTypeDeclSyntax that are direct children of each IfConfigDeclSyntax clause.
If a clause contains another #if (i.e. a nested IfConfigDeclSyntax), this finds zero associated types and returns nil, so conditional conformance is not triggered.
Example:
protocol SomeCollection {
#if DEBUG
#if os(iOS)
associatedtype Item: Hashable
#else
associatedtype Item: Equatable
#endif
#else
#if os(iOS)
associatedtype Item: Sendable
#else
associatedtype Item: Codable
#endif
#endif
}Here, the outer #if clauses only contain another #if, so no associated types are detected at that level.
2) Associated type generic where clauses are missed
whereClause(from:) only extracts constraints from the associated type’s inheritance clause and ignores the associated type’s own genericWhereClause.
For example:
protocol SomeCollection {
#if os(iOS)
associatedtype Base: RandomAccessCollection & Equatable where Base.Element: Equatable
#elseif os(macOS)
associatedtype Base: RandomAccessCollection & Hashable where Base.Element: Hashable
#else
associatedtype Base: RandomAccessCollection & Codable where Base.Element: Codable
#endif
}In this scenario, the generated extensions that provide conditional conformance won't include the generic where clauses from the associate type declarations, so conditional conformance will be incomplete.
IfConfigDeclSyntax support for conditional compilation
📝 Summary
Protocols with
#if/#elseif/#else/#endifblocks now have their members correctly mocked with the conditional compilation structure preserved. This includes support for methods, properties, initializers, and associated types within conditional blocks.What changed
Known limitations / follow-ups
These cases are intentionally not handled yet and will require a more holistic approach in a future PR:
These deferred cases all require branch-combination logic and are planned to be addressed together in a follow-up. An issue (#139) has been created to track these edge cases.
🛠️ Type of Change
🧪 How Has This Been Tested?
🔗 Related PRs or Issues
Closes #136
✅ Checklist
SwiftFormat