Skip to content

Skip RectorCheaperGuardsFirstRule when anchor is not hoist-safe - #281

Merged
TomasVotruba merged 1 commit into
mainfrom
cheaper-guards-skip-unsafe-anchor
Aug 29, 2026
Merged

Skip RectorCheaperGuardsFirstRule when anchor is not hoist-safe#281
TomasVotruba merged 1 commit into
mainfrom
cheaper-guards-skip-unsafe-anchor

Conversation

@TomasVotruba

Copy link
Copy Markdown
Member

RectorCheaperGuardsFirstRule (added in 14.13.0) produced false positives on rules where the cheap guard cannot be hoisted above the expensive call:

  • an anchor block that writes attributes for the very nodes the guard would bail out on (e.g. DowngradeSubstrFalsyRector marking IS_FALSY_UNCASTABLE on non-substr call args);
  • a bare call statement whose closure mutates a variable by reference, which the guard then reads (e.g. TypeWillReturnCallableArrowFunctionRector with $hasChanged).

Fix: only flag when the anchor is genuinely hoist-safe - either an assignment that just captures the expensive value, or a pure bail guard whose condition holds the expensive call. Anything else is skipped.

Adds two skip fixtures reproducing both patterns; the true-positive fixture still reports. Verified against the real rector-downgrade-php and rector-phpunit files: both pass with no ignore needed.

Only flag a cheap guard for hoisting when the expensive-call anchor merely
captures the value (assignment) or bails on it (pure bail guard). An anchor with
its own side effects - an attribute-writing block, or a bare call statement that
mutates a variable by-reference inside a closure - is unsafe to hoist past, since
the nodes the guard bails out on would lose that side effect. Fixes false
positives on DowngradeSubstrFalsyRector and TypeWillReturnCallableArrowFunctionRector.

Claude-Session: https://claude.ai/code/session_01Na4eYvNqa2pdhZrBXbegrv
@TomasVotruba
TomasVotruba merged commit 31b31b0 into main Aug 29, 2026
8 checks passed
@TomasVotruba
TomasVotruba deleted the cheaper-guards-skip-unsafe-anchor branch August 29, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant