diff --git a/src/Reporting/UnusedSkipResolver.php b/src/Reporting/UnusedSkipResolver.php index 2c52ce10570..0c0274bd16d 100644 --- a/src/Reporting/UnusedSkipResolver.php +++ b/src/Reporting/UnusedSkipResolver.php @@ -33,26 +33,45 @@ public function __construct( */ public function resolve(ProcessResult $processResult): array { - if (! SimpleParameterProvider::provideBoolParameter(Option::REPORT_UNUSED_SKIPS, false)) { + if ($this->shouldSkipReporting()) { return []; } + $usedSkips = $processResult->getUsedSkips(); + + return [ + ...$this->resolveUnusedRuleScopedSkips($usedSkips), + ...$this->resolveUnusedGlobalSkips($usedSkips), + ]; + } + + private function shouldSkipReporting(): bool + { + if (! SimpleParameterProvider::provideBoolParameter(Option::REPORT_UNUSED_SKIPS, false)) { + return true; + } + // a narrowed run (cli paths, "--only" or "--only-suffix") only touches part of the codebase, // so skips outside that scope look falsely unused - reporting them would be noise if (SimpleParameterProvider::provideBoolParameter(Option::IS_RUN_NARROWED, false)) { - return []; + return true; } // a cached run only re-processes changed files, so skips on cached files never get a chance // to match and would all look falsely unused - reporting them would be noise - if (SimpleParameterProvider::provideBoolParameter(Option::IS_CACHED_RUN, false)) { - return []; - } + return SimpleParameterProvider::provideBoolParameter(Option::IS_CACHED_RUN, false); + } - // map of rule => (trackable skip path => relative display path); skips are tracked at - // runtime by their path, but rule-scoped ones are printed grouped under their rule so the - // user knows exactly what to remove. Skip-everywhere rule skips (null path) are forgotten - // from the container at boot, so they never reach the skipper and cannot be tracked. + /** + * Map of rule => (trackable skip path => relative display path); skips are tracked at + * runtime by their path, but rule-scoped ones are printed grouped under their rule so the + * user knows exactly what to remove. Skip-everywhere rule skips (null path) are forgotten + * from the container at boot, so they never reach the skipper and cannot be tracked. + * + * @return array> + */ + private function resolveRelativePathsByClass(): array + { $relativePathsByClass = []; foreach ($this->skippedClassResolver->resolve() as $rectorClass => $paths) { if ($paths === null) { @@ -65,9 +84,17 @@ public function resolve(ProcessResult $processResult): array } } - // global mask paths like "*/some/*" are hard to spot and report false positives, skip them + return $relativePathsByClass; + } + + /** + * @return array + */ + private function resolveGlobalRelativePaths(): array + { $globalRelativePaths = []; foreach ($this->skippedPathsResolver->resolve() as $globalPath) { + // global mask paths like "*/some/*" are hard to spot and report false positives, skip them if (str_contains($globalPath, '*')) { continue; } @@ -75,12 +102,19 @@ public function resolve(ProcessResult $processResult): array $globalRelativePaths[$globalPath] = $this->filePathHelper->relativePath($globalPath); } - $usedSkips = $processResult->getUsedSkips(); + return $globalRelativePaths; + } + /** + * @param string[] $usedSkips + * @return string[] + */ + private function resolveUnusedRuleScopedSkips(array $usedSkips): array + { $unusedSkips = []; // group unused rule-scoped paths under their rule, matching the "->withSkip()" config shape - foreach ($relativePathsByClass as $rectorClass => $relativePaths) { + foreach ($this->resolveRelativePathsByClass() as $rectorClass => $relativePaths) { $unusedRelativePaths = []; foreach ($relativePaths as $path => $relativePath) { if (! in_array($path, $usedSkips, true)) { @@ -96,7 +130,17 @@ public function resolve(ProcessResult $processResult): array $unusedSkips[] = $rectorClass . ':' . "\n * " . implode("\n * ", $unusedRelativePaths); } - foreach ($globalRelativePaths as $path => $relativePath) { + return $unusedSkips; + } + + /** + * @param string[] $usedSkips + * @return string[] + */ + private function resolveUnusedGlobalSkips(array $usedSkips): array + { + $unusedSkips = []; + foreach ($this->resolveGlobalRelativePaths() as $path => $relativePath) { if (! in_array($path, $usedSkips, true)) { $unusedSkips[] = $relativePath; }