Skip to content

[dx] Report rule-scoped skips that matched a file but never changed it - #8853

Merged
TomasVotruba merged 2 commits into
mainfrom
tv-verify-needed-skips
Oct 26, 2026
Merged

TomasVotruba merged 2 commits into
mainfrom
tv-verify-needed-skips

Conversation

@TomasVotruba

@TomasVotruba TomasVotruba commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Why

->reportUnusedSkips() so far only flags a skip whose path never matched any file. But a skip can also match a file while the rule would not have changed it anyway - a genuinely unnecessary skip. That precision used to come from the per-node clone-probe in AbstractRector::enterNode(), removed in #8560 for performance (it ran refactor() on a deep clone of every skipped node).

What

This restores the detection, paid once at end-of-run instead of per node:

  • Skipper records the real file paths skipped per rule-scoped path skip, but only when reportUnusedSkips() is on, so normal runs pay nothing.
  • A new NeededSkipVerifier re-runs each skipped file through the full rule set with skipping off (a transient flag on Skipper), and reads back which rules actually changed the file. A skipped rule that is not among them never prevented a change, so its skip is reported as unnecessary.
  • MissConfigurationReporter::reportUnnecessarySkips() prints them grouped under their rule, next to the existing never-matched report.

Scope and guards

  • The re-processing is forced to a dry-run Configuration, so it detects the change but never writes the skipped file - safe on apply runs too.
  • Re-running the full rule set (not the rule in isolation) keeps dependent rules correct: a rule that only fires after a sibling still counts as a real change.
  • Only per actually-skipped files, so it is immune to the false positives that disable the never-matched report on narrowed/cached runs.
  • Rule-scoped path skips only. Skip-everywhere and global path skips are not re-runnable this way.
  • A file that fails to re-parse is left out, so its skip is kept.

Capture happens in the main process, so coverage is single-process runs; parallel workers are a possible follow-up.

reportUnusedSkips() so far only flagged a skip whose path never matched
any file. A skip can also match a file while the rule would not have
changed it anyway - the clone-probe used to catch this per node, removed
for performance.

On a dry run, re-run each rule-scoped skip on its exact file with
skipping off; if the rule still does not change the file, report the
skip as unnecessary. Paid once per skipped file, only when reporting is
enabled.
@TomasVotruba TomasVotruba changed the title Report rule-scoped skips that matched a file but never changed it [dx] Report rule-scoped skips that matched a file but never changed it Oct 26, 2026
…runs

The verifier re-processes skipped files only to read which rules would
change them. Building its own dry-run Configuration keeps FileProcessor
from writing the skipped file, so the check is safe outside a dry run
too. Drop the dry-run gate in ProcessCommand.
@TomasVotruba
TomasVotruba merged commit 3bd9f03 into main Oct 26, 2026
50 checks passed
@TomasVotruba
TomasVotruba deleted the tv-verify-needed-skips branch October 26, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant