fix: terminate overlapping-fields rule on cyclic fragment spreads#741
fix: terminate overlapping-fields rule on cyclic fragment spreads#741mennatnaga wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds per-validation-pass memoization to OverlappingFieldsCanBeMergedRule to avoid re-walking fragment spreads for identical (fieldsInfo, fragmentName, areMutuallyExclusive) triples; updates collectConflictsBetweenFieldsAndFragment to consult the memo before recursing and adds a test ensuring termination on cyclic fragment spreads. ChangesCyclic Fragment Recursion Prevention
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
rules_overlapping_fields_can_be_merged.go (1)
221-233:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep the original field set when recursing into nested spreads.
Step E here should continue comparing the caller’s
fieldsInfoagainst deeper fragment spreads, but Line 233 switches the left-hand side tofieldsInfo2. That misses conflicts like{ x: a, ...A },fragment A on T { ...B },fragment B on T { x: b }, because the second step comparesAvsBinstead of the original selection set vsB.Suggested fix
for _, fragmentName2 := range fieldsInfo2.fragmentNames { - conflicts = rule.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive, fieldsInfo2, fragmentName2) + conflicts = rule.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive, fieldsInfo, fragmentName2) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rules_overlapping_fields_can_be_merged.go` around lines 221 - 233, The recursion into nested fragment spreads uses the wrong left-hand side: when iterating fragmentName2 from fieldsInfo2.fragmentNames you must continue comparing the original caller's fieldsInfo against the deeper fragment, not fieldsInfo2; change the call to rule.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive, fieldsInfo, fragmentName2) so the original fieldsInfo is preserved while recursing through fragmentNames (leave collectConflictsBetween and the loop intact).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rules_overlapping_fields_can_be_merged_test.go`:
- Around line 909-922: The test currently calls testutil.ExpectPassesRule inside
a spawned goroutine (using the done channel and select), which can invoke
t.Fatal from a non-test goroutine; instead, run no assertions in the worker
goroutine — have it execute the rule logic and send back a result (e.g. an error
or boolean) over a result channel; then in the main test goroutine (after the
select or receiving from the channel) call testutil.ExpectPassesRule or
t.Fatal/t.Fatalf based on that result. Update the goroutine to only perform
non-fatal work and send a result, and move any calls to
testutil.ExpectPassesRule/t.Fatal into the main test goroutine that owns t; keep
references to the done channel, the goroutine, the select/time.After timeout,
and the ExpectPassesRule call so you modify the correct code paths.
---
Outside diff comments:
In `@rules_overlapping_fields_can_be_merged.go`:
- Around line 221-233: The recursion into nested fragment spreads uses the wrong
left-hand side: when iterating fragmentName2 from fieldsInfo2.fragmentNames you
must continue comparing the original caller's fieldsInfo against the deeper
fragment, not fieldsInfo2; change the call to
rule.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive,
fieldsInfo, fragmentName2) so the original fieldsInfo is preserved while
recursing through fragmentNames (leave collectConflictsBetween and the loop
intact).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 31faf011-3642-4851-b2cc-77d633878143
📒 Files selected for processing (2)
rules_overlapping_fields_can_be_merged.gorules_overlapping_fields_can_be_merged_test.go
The overlapping-fields validator infinitely recurses on cyclic fragment spreads.
How to reproduce
Before this patch: runtime: goroutine stack exceeds 1000000000-byte limit; fatal error: stack overflow inside collectConflictsBetweenFieldsAndFragment at rules_overlapping_fields_can_be_merged.go:209.
After: validation returns Cannot spread fragment "A" within itself via B. from NoFragmentCyclesRule.
Root cause
collectConflictsBetweenFieldsAndFragment recurses through nested spreads without memoization. Its sibling collectConflictsBetweenFragments already has the equivalent guard via rule.comparedSet; this one was missing it.
Changes
Test
TestValidate_OverlappingFieldsCanBeMerged_CyclicFragmentTerminates runs the rule inside a goroutine with a 2s deadline. Fails on the unpatched code (the goroutine never finishes), passes after the fix.
Existing OverlappingFields* tests still pass.
Closes
#742
Summary by CodeRabbit
Bug Fixes
Tests