Over time, the ->withSkip() list in your rector.php grows. Rules get removed, files get renamed or deleted, bugs get fixed - but the skips for them stay behind. These dead skips are easy to miss and hide what Rector would actually do.
Rector can report skips that never matched anything during a run, so you can safely remove them. This works just like PHPStan's "reporting unused ignores".
It is off by default. Enable it with ->reportUnusedSkips():
<?php
use Rector\Config\RectorConfig;
use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector;
return RectorConfig::configure()
->withRules([SimplifyUselessVariableRector::class])
->reportUnusedSkips()
->withSkip([
SimplifyUselessVariableRector::class => [
__DIR__ . '/src/Used.php', // matched → not reported
__DIR__ . '/src/NeverMatches.php', // never matched → reported
],
]);
Omit the call, or pass false to disable it explicitly:
return RectorConfig::configure()
->reportUnusedSkips(false);
After the run, any skip that never matched a file is printed as a warning, with the full rule => path so you know exactly what to delete:
[WARNING] This skip is unused, it never matched any element. You can remove it
from "->withSkip()"
* Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector => /src/NeverMatches.php
When you run with --output-format=json (typical for editor and CI integrations), unused skips are added under a new unused_skips key. The key only appears when reporting is enabled and something is actually unused, so the rest of the JSON schema stays untouched:
{
"totals": { "changed_files": 1, "errors": 0 },
"file_diffs": [ ],
"changed_files": [ "src/SomeClass.php" ],
"unused_skips": [
"Rector\\CodeQuality\\Rector\\FunctionLike\\SimplifyUselessVariableRector => /src/NeverMatches.php"
]
}
Rule::class => ['...']) and plain global paths are tracked.*/some/* are skipped from the report - they are hard to spot and prone to false positives. Rule-scoped masks are reported, since they are intentional.