From 310815a826ba9024520d251c88749c4e1512a664 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 20 Jun 2026 11:11:40 +0200 Subject: [PATCH 1/2] [reporting] Add reportUnusedSkips() to report skips that never matched Adds a ->reportUnusedSkips() config option, similar to PHPStan's reportUnusedIgnores. Tracks which ->withSkip() elements actually matched during a run via a shared UsedSkipCollector, then warns about path and rule-with-path skips that never matched and can be removed. Used skips are aggregated across parallel workers through the process bridge and carried on ProcessResult. Skip-everywhere rule skips are forgotten from the container at boot, so they are not trackable at runtime and are excluded from the report. --- .github/workflows/e2e.yaml | 8 +- e2e/parallel-unused-skips/.gitignore | 1 + e2e/parallel-unused-skips/composer.json | 5 + .../custom/config/rector.php | 23 +++++ .../expected-output.diff | 6 ++ e2e/parallel-unused-skips/src/SomeClass.php | 14 +++ src/Application/ApplicationFileProcessor.php | 4 +- src/Config/RectorConfig.php | 5 + src/Configuration/Option.php | 6 ++ src/Configuration/RectorConfigBuilder.php | 17 ++++ src/Console/Command/ProcessCommand.php | 1 + src/Console/Command/WorkerCommand.php | 1 + .../LazyContainerFactory.php | 4 + .../Application/ParallelFileProcessor.php | 14 ++- src/Parallel/ValueObject/Bridge.php | 2 + src/Reporting/MissConfigurationReporter.php | 38 ++++++++ src/Skipper/Skipper/PathSkipper.php | 13 ++- src/Skipper/Skipper/SkipSkipper.php | 5 +- src/Skipper/Skipper/UsedSkipCollector.php | 32 +++++++ src/ValueObject/ProcessResult.php | 13 ++- .../MissConfigurationReporterTest.php | 91 +++++++++++++++++++ .../Skipper/Skipper/UsedSkipCollectorTest.php | 68 ++++++++++++++ 22 files changed, 362 insertions(+), 9 deletions(-) create mode 100644 e2e/parallel-unused-skips/.gitignore create mode 100644 e2e/parallel-unused-skips/composer.json create mode 100644 e2e/parallel-unused-skips/custom/config/rector.php create mode 100644 e2e/parallel-unused-skips/expected-output.diff create mode 100644 e2e/parallel-unused-skips/src/SomeClass.php create mode 100644 src/Skipper/Skipper/UsedSkipCollector.php create mode 100644 tests/Reporting/MissConfigurationReporterTest.php create mode 100644 tests/Skipper/Skipper/UsedSkipCollectorTest.php diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index be970e32f7d..342fe2f7e97 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -40,6 +40,7 @@ jobs: - 'e2e/only-option-quote-single-bsdouble' - 'e2e/only-option-quote-single-equalnone' - 'e2e/parallel-custom-config' + - 'e2e/parallel-unused-skips' - 'e2e/parallel-reflection-resolver' - 'e2e/parallel with space' - 'e2e/print-new-node' @@ -72,6 +73,11 @@ jobs: working-directory: ${{ matrix.directory }} if: ${{ matrix.directory == 'e2e/parallel-custom-config' }} + # tests parallel aggregation of used skips for ->reportUnusedSkips() + - run: php ../e2eTestRunner.php --config custom/config/rector.php + working-directory: ${{ matrix.directory }} + if: ${{ matrix.directory == 'e2e/parallel-unused-skips' }} + - run: php ../e2eTestRunner.php working-directory: ${{ matrix.directory }} - if: ${{ matrix.directory != 'e2e/parallel-custom-config' }} + if: ${{ matrix.directory != 'e2e/parallel-custom-config' && matrix.directory != 'e2e/parallel-unused-skips' }} diff --git a/e2e/parallel-unused-skips/.gitignore b/e2e/parallel-unused-skips/.gitignore new file mode 100644 index 00000000000..61ead86667c --- /dev/null +++ b/e2e/parallel-unused-skips/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/e2e/parallel-unused-skips/composer.json b/e2e/parallel-unused-skips/composer.json new file mode 100644 index 00000000000..8b5ca727be7 --- /dev/null +++ b/e2e/parallel-unused-skips/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "^8.1" + } +} diff --git a/e2e/parallel-unused-skips/custom/config/rector.php b/e2e/parallel-unused-skips/custom/config/rector.php new file mode 100644 index 00000000000..015e4de8c8e --- /dev/null +++ b/e2e/parallel-unused-skips/custom/config/rector.php @@ -0,0 +1,23 @@ +parallel(); + + $rectorConfig->paths([__DIR__ . '/../../src/']); + + $rectorConfig->rule(SimplifyUselessVariableRector::class); + + $rectorConfig->reportUnusedSkips(); + + // matched in the worker - must be excluded from the unused report (proves parallel aggregation) + // plus a glob that never matches - must be reported as unused + $rectorConfig->skip([ + SimplifyUselessVariableRector::class => ['*/src/*'], + '*/NonexistentUnused/*', + ]); +}; diff --git a/e2e/parallel-unused-skips/expected-output.diff b/e2e/parallel-unused-skips/expected-output.diff new file mode 100644 index 00000000000..de57957a29e --- /dev/null +++ b/e2e/parallel-unused-skips/expected-output.diff @@ -0,0 +1,6 @@ +[OK] Rector is done! + + [WARNING] This skip is unused, it never matched any element. You can remove it + from "->withSkip()" + + * */NonexistentUnused/* diff --git a/e2e/parallel-unused-skips/src/SomeClass.php b/e2e/parallel-unused-skips/src/SomeClass.php new file mode 100644 index 00000000000..1b9ae643d07 --- /dev/null +++ b/e2e/parallel-unused-skips/src/SomeClass.php @@ -0,0 +1,14 @@ +usedSkipCollector->provide()); } private function processFile(File $file, Configuration $configuration): FileProcessResult diff --git a/src/Config/RectorConfig.php b/src/Config/RectorConfig.php index 82a05485e0d..83d8a40206f 100644 --- a/src/Config/RectorConfig.php +++ b/src/Config/RectorConfig.php @@ -438,6 +438,11 @@ public function reportingRealPath(bool $absolute = true): void SimpleParameterProvider::setParameter(Option::ABSOLUTE_FILE_PATH, $absolute); } + public function reportUnusedSkips(bool $report = true): void + { + SimpleParameterProvider::setParameter(Option::REPORT_UNUSED_SKIPS, $report); + } + public function editorUrl(string $editorUrl): void { SimpleParameterProvider::setParameter(Option::EDITOR_URL, $editorUrl); diff --git a/src/Configuration/Option.php b/src/Configuration/Option.php index a0021391dbc..f5a756a78c1 100644 --- a/src/Configuration/Option.php +++ b/src/Configuration/Option.php @@ -103,6 +103,12 @@ final class Option */ public const string SKIP = 'skip'; + /** + * @internal Use @see \Rector\Config\RectorConfig::reportUnusedSkips() instead + * @var string + */ + public const string REPORT_UNUSED_SKIPS = 'report_unused_skips'; + /** * @internal Use RectorConfig::fileExtensions() instead */ diff --git a/src/Configuration/RectorConfigBuilder.php b/src/Configuration/RectorConfigBuilder.php index 0fadacd0134..b5fbc68f136 100644 --- a/src/Configuration/RectorConfigBuilder.php +++ b/src/Configuration/RectorConfigBuilder.php @@ -174,6 +174,8 @@ final class RectorConfigBuilder private ?bool $reportingRealPath = null; + private ?bool $reportUnusedSkips = null; + /** * @var string[] */ @@ -394,6 +396,10 @@ public function __invoke(RectorConfig $rectorConfig): void $rectorConfig->reportingRealPath($this->reportingRealPath); } + if ($this->reportUnusedSkips !== null) { + $rectorConfig->reportUnusedSkips($this->reportUnusedSkips); + } + if ($this->editorUrl !== null) { $rectorConfig->editorUrl($this->editorUrl); } @@ -1314,6 +1320,17 @@ public function withRealPathReporting(bool $absolutePath = true): self return $this; } + /** + * Report skips configured via withSkip() that never matched anything during the run, + * so they can be safely removed. + */ + public function reportUnusedSkips(bool $report = true): self + { + $this->reportUnusedSkips = $report; + + return $this; + } + public function withEditorUrl(string $editorUrl): self { $this->editorUrl = $editorUrl; diff --git a/src/Console/Command/ProcessCommand.php b/src/Console/Command/ProcessCommand.php index 42c3256d6aa..511b536cea6 100644 --- a/src/Console/Command/ProcessCommand.php +++ b/src/Console/Command/ProcessCommand.php @@ -186,6 +186,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->deprecatedRulesReporter->reportDeprecatedRectorUnsupportedMethods(); $this->missConfigurationReporter->reportSkippedNeverRegisteredRules(); + $this->missConfigurationReporter->reportUnusedSkips($processResult); return $this->resolveReturnCode($processResult, $configuration); } diff --git a/src/Console/Command/WorkerCommand.php b/src/Console/Command/WorkerCommand.php index b86320a9cd8..ef2a8b251be 100644 --- a/src/Console/Command/WorkerCommand.php +++ b/src/Console/Command/WorkerCommand.php @@ -166,6 +166,7 @@ private function runWorker( Bridge::SYSTEM_ERRORS => $processResult->getSystemErrors(), Bridge::SYSTEM_ERRORS_COUNT => count($processResult->getSystemErrors()), Bridge::TOTAL_CHANGED => $processResult->getTotalChanged(), + Bridge::USED_SKIPS => $processResult->getUsedSkips(), ], ]); }); diff --git a/src/DependencyInjection/LazyContainerFactory.php b/src/DependencyInjection/LazyContainerFactory.php index 04d7da27c22..6c780f20e70 100644 --- a/src/DependencyInjection/LazyContainerFactory.php +++ b/src/DependencyInjection/LazyContainerFactory.php @@ -177,6 +177,7 @@ use Rector\Rector\AbstractRector; use Rector\Reporting\DeprecatedRulesReporter; use Rector\Skipper\Skipper\Skipper; +use Rector\Skipper\Skipper\UsedSkipCollector; use Rector\StaticTypeMapper\Contract\PhpDocParser\PhpDocTypeMapperInterface; use Rector\StaticTypeMapper\Contract\PhpParser\PhpParserNodeMapperInterface; use Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper; @@ -453,6 +454,9 @@ public function create(): RectorConfig $rectorConfig->singleton(FileProcessor::class); $rectorConfig->singleton(PostFileProcessor::class); + // shared state: collects used skips across skipper voters and the file processor + $rectorConfig->singleton(UsedSkipCollector::class); + $rectorConfig->when(RectorNodeTraverser::class) ->needs('$rectors') ->giveTagged(RectorInterface::class); diff --git a/src/Parallel/Application/ParallelFileProcessor.php b/src/Parallel/Application/ParallelFileProcessor.php index a1c8d3e0696..27d59b3a46d 100644 --- a/src/Parallel/Application/ParallelFileProcessor.php +++ b/src/Parallel/Application/ParallelFileProcessor.php @@ -75,6 +75,9 @@ public function process( /** @var SystemError[] $systemErrors */ $systemErrors = []; + /** @var array $usedSkips */ + $usedSkips = []; + $tcpServer = new TcpServer('127.0.0.1:0', $streamSelectLoop); $this->processPool = new ProcessPool($tcpServer); @@ -143,6 +146,7 @@ public function process( $processSpawner = function () use ( &$systemErrors, &$fileDiffs, + &$usedSkips, &$jobs, $postFileCallback, &$systemErrorsCount, @@ -176,6 +180,7 @@ function (array $json) use ( $parallelProcess, &$systemErrors, &$fileDiffs, + &$usedSkips, &$jobs, $postFileCallback, &$systemErrorsCount, @@ -190,10 +195,15 @@ function (array $json) use ( * system_errors: mixed[], * file_diffs: array, * files_count: int, - * system_errors_count: int + * system_errors_count: int, + * used_skips: string[] * } $json */ $totalChanged += $json[Bridge::TOTAL_CHANGED]; + foreach ($json[Bridge::USED_SKIPS] as $usedSkip) { + $usedSkips[$usedSkip] = true; + } + // decode arrays to objects foreach ($json[Bridge::SYSTEM_ERRORS] as $jsonError) { if (is_string($jsonError)) { @@ -276,6 +286,6 @@ function ($exitCode, string $stdErr) use (&$systemErrors, $processIdentifier): v )); } - return new ProcessResult($systemErrors, $fileDiffs, $totalChanged); + return new ProcessResult($systemErrors, $fileDiffs, $totalChanged, array_keys($usedSkips)); } } diff --git a/src/Parallel/ValueObject/Bridge.php b/src/Parallel/ValueObject/Bridge.php index 0d581733025..55bda4fba95 100644 --- a/src/Parallel/ValueObject/Bridge.php +++ b/src/Parallel/ValueObject/Bridge.php @@ -20,4 +20,6 @@ final class Bridge public const string FILES_COUNT = 'files_count'; public const string TOTAL_CHANGED = 'total_changed'; + + public const string USED_SKIPS = 'used_skips'; } diff --git a/src/Reporting/MissConfigurationReporter.php b/src/Reporting/MissConfigurationReporter.php index 208220c3c7e..2b241daba67 100644 --- a/src/Reporting/MissConfigurationReporter.php +++ b/src/Reporting/MissConfigurationReporter.php @@ -8,6 +8,9 @@ use Rector\Configuration\Parameter\SimpleParameterProvider; use Rector\Configuration\VendorMissAnalyseGuard; use Rector\PostRector\Contract\Rector\PostRectorInterface; +use Rector\Skipper\SkipCriteriaResolver\SkippedClassResolver; +use Rector\Skipper\SkipCriteriaResolver\SkippedPathsResolver; +use Rector\ValueObject\ProcessResult; use Symfony\Component\Console\Style\SymfonyStyle; final readonly class MissConfigurationReporter @@ -15,9 +18,44 @@ public function __construct( private SymfonyStyle $symfonyStyle, private VendorMissAnalyseGuard $vendorMissAnalyseGuard, + private SkippedClassResolver $skippedClassResolver, + private SkippedPathsResolver $skippedPathsResolver, ) { } + /** + * Reports skips configured via "->withSkip()" that never matched any element during the run. + * Enabled with "->reportUnusedSkips()". + */ + public function reportUnusedSkips(ProcessResult $processResult): void + { + if (! SimpleParameterProvider::provideBoolParameter(Option::REPORT_UNUSED_SKIPS, false)) { + return; + } + + // only path-scoped class skips are trackable at runtime; skip-everywhere rule skips + // (null path) are forgotten from the container at boot, so they never reach the skipper + $pathScopedClassSkips = array_keys(array_filter( + $this->skippedClassResolver->resolve(), + static fn (?array $paths): bool => $paths !== null + )); + + $configuredSkips = [...$pathScopedClassSkips, ...$this->skippedPathsResolver->resolve()]; + + $unusedSkips = array_values(array_diff($configuredSkips, $processResult->getUsedSkips())); + if ($unusedSkips === []) { + return; + } + + $this->symfonyStyle->warning(sprintf( + '%s never matched any element. You can remove %s from "->withSkip()"', + count($unusedSkips) > 1 ? 'These skips are unused, they' : 'This skip is unused, it', + count($unusedSkips) > 1 ? 'them' : 'it' + )); + + $this->symfonyStyle->listing($unusedSkips); + } + public function reportSkippedNeverRegisteredRules(): void { $registeredRules = SimpleParameterProvider::provideArrayParameter(Option::REGISTERED_RECTOR_RULES); diff --git a/src/Skipper/Skipper/PathSkipper.php b/src/Skipper/Skipper/PathSkipper.php index e48ef8a6180..7d1d68d2b71 100644 --- a/src/Skipper/Skipper/PathSkipper.php +++ b/src/Skipper/Skipper/PathSkipper.php @@ -11,13 +11,20 @@ { public function __construct( private FileInfoMatcher $fileInfoMatcher, - private SkippedPathsResolver $skippedPathsResolver + private SkippedPathsResolver $skippedPathsResolver, + private UsedSkipCollector $usedSkipCollector ) { } public function shouldSkip(string $filePath): bool { - $skippedPaths = $this->skippedPathsResolver->resolve(); - return $this->fileInfoMatcher->doesFileInfoMatchPatterns($filePath, $skippedPaths); + foreach ($this->skippedPathsResolver->resolve() as $skippedPath) { + if ($this->fileInfoMatcher->doesFileInfoMatchPatterns($filePath, [$skippedPath])) { + $this->usedSkipCollector->markUsed($skippedPath); + return true; + } + } + + return false; } } diff --git a/src/Skipper/Skipper/SkipSkipper.php b/src/Skipper/Skipper/SkipSkipper.php index 0c382e35b9b..69233fdbc9a 100644 --- a/src/Skipper/Skipper/SkipSkipper.php +++ b/src/Skipper/Skipper/SkipSkipper.php @@ -9,7 +9,8 @@ final readonly class SkipSkipper { public function __construct( - private FileInfoMatcher $fileInfoMatcher + private FileInfoMatcher $fileInfoMatcher, + private UsedSkipCollector $usedSkipCollector ) { } @@ -25,10 +26,12 @@ public function doesMatchSkip(object | string $checker, string $filePath, array // skip everywhere if (! is_array($skippedFiles)) { + $this->usedSkipCollector->markUsed($skippedClass); return true; } if ($this->fileInfoMatcher->doesFileInfoMatchPatterns($filePath, $skippedFiles)) { + $this->usedSkipCollector->markUsed($skippedClass); return true; } } diff --git a/src/Skipper/Skipper/UsedSkipCollector.php b/src/Skipper/Skipper/UsedSkipCollector.php new file mode 100644 index 00000000000..27c3abef42d --- /dev/null +++ b/src/Skipper/Skipper/UsedSkipCollector.php @@ -0,0 +1,32 @@ + + */ + private array $usedSkips = []; + + public function markUsed(string $skip): void + { + $this->usedSkips[$skip] = true; + } + + /** + * @return string[] + */ + public function provide(): array + { + return array_keys($this->usedSkips); + } +} diff --git a/src/ValueObject/ProcessResult.php b/src/ValueObject/ProcessResult.php index 4d2c60a7875..7d5a785184e 100644 --- a/src/ValueObject/ProcessResult.php +++ b/src/ValueObject/ProcessResult.php @@ -14,14 +14,17 @@ final class ProcessResult /** * @param SystemError[] $systemErrors * @param FileDiff[] $fileDiffs + * @param string[] $usedSkips */ public function __construct( private array $systemErrors, private readonly array $fileDiffs, - private readonly int $totalChanged + private readonly int $totalChanged, + private readonly array $usedSkips = [] ) { Assert::allIsInstanceOf($systemErrors, SystemError::class); Assert::allIsInstanceOf($fileDiffs, FileDiff::class); + Assert::allString($usedSkips); } /** @@ -59,6 +62,14 @@ public function getTotalChanged(): int return $this->totalChanged; } + /** + * @return string[] + */ + public function getUsedSkips(): array + { + return $this->usedSkips; + } + /** * @return array, int> */ diff --git a/tests/Reporting/MissConfigurationReporterTest.php b/tests/Reporting/MissConfigurationReporterTest.php new file mode 100644 index 00000000000..ad35d454ef6 --- /dev/null +++ b/tests/Reporting/MissConfigurationReporterTest.php @@ -0,0 +1,91 @@ +bufferedOutput = new BufferedOutput(); + $symfonyStyle = new SymfonyStyle(new ArrayInput([]), $this->bufferedOutput); + + $this->missConfigurationReporter = new MissConfigurationReporter( + $symfonyStyle, + new VendorMissAnalyseGuard(), + $this->make(SkippedClassResolver::class), + $this->make(SkippedPathsResolver::class), + ); + + SimpleParameterProvider::setParameter(Option::SKIP, [ + // skip-everywhere rule skip - forgotten at boot, not trackable, must be excluded + ThreeMan::class, + // path-scoped class skip, never matched - must be reported + FifthElement::class => ['*/some/*'], + // path-scoped class skip, matched - must not be reported + AnotherClassToSkip::class => ['*/other/*'], + // glob path skip, never matched - must be reported + self::UNUSED_GLOB, + ]); + } + + protected function tearDown(): void + { + SimpleParameterProvider::setParameter(Option::SKIP, []); + SimpleParameterProvider::setParameter(Option::REPORT_UNUSED_SKIPS, false); + } + + public function testReportsOnlyTrackableUnusedSkips(): void + { + SimpleParameterProvider::setParameter(Option::REPORT_UNUSED_SKIPS, true); + + $processResult = new ProcessResult([], [], 0, [AnotherClassToSkip::class]); + $this->missConfigurationReporter->reportUnusedSkips($processResult); + + $output = $this->bufferedOutput->fetch(); + + // unused, trackable skips are reported + $this->assertStringContainsString('FifthElement', $output); + $this->assertStringContainsString('UnusedGlobMarker', $output); + + // skip-everywhere rule skip is excluded (not trackable at runtime) + $this->assertStringNotContainsString('ThreeMan', $output); + + // matched skip is excluded + $this->assertStringNotContainsString('AnotherClassToSkip', $output); + } + + public function testReportsNothingWhenDisabled(): void + { + SimpleParameterProvider::setParameter(Option::REPORT_UNUSED_SKIPS, false); + + $processResult = new ProcessResult([], [], 0, []); + $this->missConfigurationReporter->reportUnusedSkips($processResult); + + $this->assertSame('', $this->bufferedOutput->fetch()); + } +} diff --git a/tests/Skipper/Skipper/UsedSkipCollectorTest.php b/tests/Skipper/Skipper/UsedSkipCollectorTest.php new file mode 100644 index 00000000000..d43afa91123 --- /dev/null +++ b/tests/Skipper/Skipper/UsedSkipCollectorTest.php @@ -0,0 +1,68 @@ +skipper = $this->make(Skipper::class); + $this->usedSkipCollector = $this->make(UsedSkipCollector::class); + } + + protected function tearDown(): void + { + SimpleParameterProvider::setParameter(Option::SKIP, []); + } + + public function testCollectsOnlyMatchedSkips(): void + { + $this->skipper->shouldSkipFilePath('tests/Skipper/Skipper/Fixture/SomeSkippedPath/any.txt'); + $this->skipper->shouldSkipElement(FifthElement::class); + + $usedSkips = $this->usedSkipCollector->provide(); + + // matched skips are collected + $this->assertContains(FifthElement::class, $usedSkips); + $this->assertNotEmpty(array_filter( + $usedSkips, + static fn (string $usedSkip): bool => str_ends_with($usedSkip, 'SomeSkippedPath') + )); + + // unmatched skip is never collected + $this->assertNotContains(self::UNUSED_SKIP_MARKER, $usedSkips); + } +} From af72534b07914003a714206471d796a64e21f98e Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 20 Jun 2026 11:25:59 +0200 Subject: [PATCH 2/2] fixup! [reporting] Add reportUnusedSkips() to report skips that never matched --- src/Reporting/MissConfigurationReporter.php | 3 +++ tests/Reporting/MissConfigurationReporterTest.php | 2 +- tests/Skipper/Skipper/UsedSkipCollectorTest.php | 4 +--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Reporting/MissConfigurationReporter.php b/src/Reporting/MissConfigurationReporter.php index 2b241daba67..42deb136fdc 100644 --- a/src/Reporting/MissConfigurationReporter.php +++ b/src/Reporting/MissConfigurationReporter.php @@ -13,6 +13,9 @@ use Rector\ValueObject\ProcessResult; use Symfony\Component\Console\Style\SymfonyStyle; +/** + * @see \Rector\Tests\Reporting\MissConfigurationReporterTest + */ final readonly class MissConfigurationReporter { public function __construct( diff --git a/tests/Reporting/MissConfigurationReporterTest.php b/tests/Reporting/MissConfigurationReporterTest.php index ad35d454ef6..155460810c1 100644 --- a/tests/Reporting/MissConfigurationReporterTest.php +++ b/tests/Reporting/MissConfigurationReporterTest.php @@ -21,7 +21,7 @@ final class MissConfigurationReporterTest extends AbstractLazyTestCase { - private const UNUSED_GLOB = '*/UnusedGlobMarker/*'; + private const string UNUSED_GLOB = '*/UnusedGlobMarker/*'; private BufferedOutput $bufferedOutput; diff --git a/tests/Skipper/Skipper/UsedSkipCollectorTest.php b/tests/Skipper/Skipper/UsedSkipCollectorTest.php index d43afa91123..dc201c1d7f5 100644 --- a/tests/Skipper/Skipper/UsedSkipCollectorTest.php +++ b/tests/Skipper/Skipper/UsedSkipCollectorTest.php @@ -15,10 +15,8 @@ final class UsedSkipCollectorTest extends AbstractLazyTestCase { /** * Uniquely named on purpose, so the shared collector is never polluted by another test. - * - * @var string */ - private const UNUSED_SKIP_MARKER = '*/UniqueUnusedSkipMarker/*'; + private const string UNUSED_SKIP_MARKER = '*/UniqueUnusedSkipMarker/*'; private Skipper $skipper;