@@ -42,23 +42,36 @@ public function __construct(SkippedClassResolver $skippedClassResolver, SkippedP
4242 */
4343 public function resolve (ProcessResult $ processResult ): array
4444 {
45- if (!SimpleParameterProvider:: provideBoolParameter (Option:: REPORT_UNUSED_SKIPS , \false )) {
45+ if ($ this -> shouldSkipReporting ( )) {
4646 return [];
4747 }
48+ $ usedSkips = $ processResult ->getUsedSkips ();
49+ return array_merge ($ this ->resolveUnusedRuleScopedSkips ($ usedSkips ), $ this ->resolveUnusedGlobalSkips ($ usedSkips ));
50+ }
51+ private function shouldSkipReporting (): bool
52+ {
53+ if (!SimpleParameterProvider::provideBoolParameter (Option::REPORT_UNUSED_SKIPS , \false)) {
54+ return \true;
55+ }
4856 // a narrowed run (cli paths, "--only" or "--only-suffix") only touches part of the codebase,
4957 // so skips outside that scope look falsely unused - reporting them would be noise
5058 if (SimpleParameterProvider::provideBoolParameter (Option::IS_RUN_NARROWED , \false)) {
51- return [] ;
59+ return \true ;
5260 }
5361 // a cached run only re-processes changed files, so skips on cached files never get a chance
5462 // to match and would all look falsely unused - reporting them would be noise
55- if (SimpleParameterProvider::provideBoolParameter (Option::IS_CACHED_RUN , \false)) {
56- return [];
57- }
58- // map of rule => (trackable skip path => relative display path); skips are tracked at
59- // runtime by their path, but rule-scoped ones are printed grouped under their rule so the
60- // user knows exactly what to remove. Skip-everywhere rule skips (null path) are forgotten
61- // from the container at boot, so they never reach the skipper and cannot be tracked.
63+ return SimpleParameterProvider::provideBoolParameter (Option::IS_CACHED_RUN , \false);
64+ }
65+ /**
66+ * Map of rule => (trackable skip path => relative display path); skips are tracked at
67+ * runtime by their path, but rule-scoped ones are printed grouped under their rule so the
68+ * user knows exactly what to remove. Skip-everywhere rule skips (null path) are forgotten
69+ * from the container at boot, so they never reach the skipper and cannot be tracked.
70+ *
71+ * @return array<string, array<string, string>>
72+ */
73+ private function resolveRelativePathsByClass (): array
74+ {
6275 $ relativePathsByClass = [];
6376 foreach ($ this ->skippedClassResolver ->resolve () as $ rectorClass => $ paths ) {
6477 if ($ paths === null ) {
@@ -69,18 +82,32 @@ public function resolve(ProcessResult $processResult): array
6982 $ relativePathsByClass [$ rectorClass ][$ path ] = $ this ->filePathHelper ->relativePath ($ path );
7083 }
7184 }
72- // global mask paths like "*/some/*" are hard to spot and report false positives, skip them
85+ return $ relativePathsByClass ;
86+ }
87+ /**
88+ * @return array<string, string>
89+ */
90+ private function resolveGlobalRelativePaths (): array
91+ {
7392 $ globalRelativePaths = [];
7493 foreach ($ this ->skippedPathsResolver ->resolve () as $ globalPath ) {
94+ // global mask paths like "*/some/*" are hard to spot and report false positives, skip them
7595 if (strpos ($ globalPath , '* ' ) !== \false) {
7696 continue ;
7797 }
7898 $ globalRelativePaths [$ globalPath ] = $ this ->filePathHelper ->relativePath ($ globalPath );
7999 }
80- $ usedSkips = $ processResult ->getUsedSkips ();
100+ return $ globalRelativePaths ;
101+ }
102+ /**
103+ * @param string[] $usedSkips
104+ * @return string[]
105+ */
106+ private function resolveUnusedRuleScopedSkips (array $ usedSkips ): array
107+ {
81108 $ unusedSkips = [];
82109 // group unused rule-scoped paths under their rule, matching the "->withSkip()" config shape
83- foreach ($ relativePathsByClass as $ rectorClass => $ relativePaths ) {
110+ foreach ($ this -> resolveRelativePathsByClass () as $ rectorClass => $ relativePaths ) {
84111 $ unusedRelativePaths = [];
85112 foreach ($ relativePaths as $ path => $ relativePath ) {
86113 if (!in_array ($ path , $ usedSkips , \true)) {
@@ -93,7 +120,16 @@ public function resolve(ProcessResult $processResult): array
93120 // rule on its own line, with each unused path nested below it as a "->listing()" sub-item
94121 $ unusedSkips [] = $ rectorClass . ': ' . "\n * " . implode ("\n * " , $ unusedRelativePaths );
95122 }
96- foreach ($ globalRelativePaths as $ path => $ relativePath ) {
123+ return $ unusedSkips ;
124+ }
125+ /**
126+ * @param string[] $usedSkips
127+ * @return string[]
128+ */
129+ private function resolveUnusedGlobalSkips (array $ usedSkips ): array
130+ {
131+ $ unusedSkips = [];
132+ foreach ($ this ->resolveGlobalRelativePaths () as $ path => $ relativePath ) {
97133 if (!in_array ($ path , $ usedSkips , \true)) {
98134 $ unusedSkips [] = $ relativePath ;
99135 }
0 commit comments