Skip to content

Commit d6d0351

Browse files
committed
[dx] log rules registered in both withRules() and sets, keep them once to avoid duplications or invalid use
1 parent 008cae3 commit d6d0351

5 files changed

Lines changed: 71 additions & 30 deletions

File tree

config/set/php-polyfills.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@
1010
use Rector\Php80\Rector\NotIdentical\StrContainsRector;
1111
use Rector\Php80\Rector\Ternary\GetDebugTypeRector;
1212

13+
// @note longer rule registration must be used here, to separate from withRules() from root rector.php
14+
1315
// these rules can be used ahead of PHP version,
1416
// as long composer.json includes particular symfony/php-polyfill package
15-
return RectorConfig::configure()
16-
->withRules([
17+
return static function (RectorConfig $rectorConfig): void {
18+
$rectorConfig->rules([
1719
ArrayKeyFirstLastRector::class,
1820
IsCountableRector::class,
1921
GetDebugTypeRector::class,
2022
StrStartsWithRector::class,
2123
StrEndsWithRector::class,
2224
StrContainsRector::class,
2325
]);
26+
};

src/Configuration/Option.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,15 @@ final class Option
290290
* @internal To report overflow levels in ->with*Level() methods
291291
*/
292292
public const LEVEL_OVERFLOWS = 'level_overflows';
293+
294+
/**
295+
* @internal To avoid registering rules via ->withRules(), that are already loaded in sets,
296+
* and keep rector.php clean
297+
*/
298+
public const ROOT_STANDALONE_REGISTERED_RULES = 'root_standalone_registered_rules';
299+
300+
/**
301+
* @internal The other half of ROOT_STANDALONE_REGISTERED_RULES to compare
302+
*/
303+
public const SET_REGISTERED_RULES = 'set_registered_rules';
293304
}

src/Configuration/RectorConfigBuilder.php

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ public function __invoke(RectorConfig $rectorConfig): void
246246
$rectorConfig->sets($uniqueSets);
247247
}
248248

249+
// log rules from sets and compare them with explicit rules
250+
$setRegisteredRectorClasses = $rectorConfig->getRectorClasses();
251+
SimpleParameterProvider::addParameter(Option::SET_REGISTERED_RULES, $setRegisteredRectorClasses);
252+
249253
if ($this->paths !== []) {
250254
$rectorConfig->paths($this->paths);
251255
}
@@ -782,6 +786,9 @@ public function withRules(array $rules): self
782786
{
783787
$this->rules = array_merge($this->rules, $rules);
784788

789+
// log all explicitly registered rules
790+
SimpleParameterProvider::addParameter(Option::ROOT_STANDALONE_REGISTERED_RULES, $rules);
791+
785792
return $this;
786793
}
787794

@@ -1135,29 +1142,17 @@ public function withDowngradeSets(
11351142

11361143
if ($php82) {
11371144
$this->sets[] = DowngradeLevelSetList::DOWN_TO_PHP_82;
1138-
}
1139-
1140-
if ($php81) {
1145+
} elseif ($php81) {
11411146
$this->sets[] = DowngradeLevelSetList::DOWN_TO_PHP_81;
1142-
}
1143-
1144-
if ($php80) {
1147+
} elseif ($php80) {
11451148
$this->sets[] = DowngradeLevelSetList::DOWN_TO_PHP_80;
1146-
}
1147-
1148-
if ($php74) {
1149+
} elseif ($php74) {
11491150
$this->sets[] = DowngradeLevelSetList::DOWN_TO_PHP_74;
1150-
}
1151-
1152-
if ($php73) {
1151+
} elseif ($php73) {
11531152
$this->sets[] = DowngradeLevelSetList::DOWN_TO_PHP_73;
1154-
}
1155-
1156-
if ($php72) {
1153+
} elseif ($php72) {
11571154
$this->sets[] = DowngradeLevelSetList::DOWN_TO_PHP_72;
1158-
}
1159-
1160-
if ($php71) {
1155+
} elseif ($php71) {
11611156
$this->sets[] = DowngradeLevelSetList::DOWN_TO_PHP_71;
11621157
}
11631158

src/Console/Command/ProcessCommand.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Rector\StaticReflection\DynamicSourceLocatorDecorator;
2323
use Rector\Util\MemoryLimiter;
2424
use Rector\ValueObject\Configuration;
25+
use Rector\ValueObject\Configuration\LevelOverflow;
2526
use Rector\ValueObject\ProcessResult;
2627
use Symfony\Component\Console\Application;
2728
use Symfony\Component\Console\Command\Command;
@@ -101,18 +102,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int
101102

102103
// 0. warn about too high levels
103104
foreach ($configuration->getLevelOverflows() as $levelOverflow) {
104-
$suggestedSetMethod = PHP_VERSION_ID >= 80000 ? sprintf(
105-
'->withPreparedSets(%s: true)',
106-
$levelOverflow->getSuggestedRuleset()
107-
) : sprintf('->withSets(SetList::%s)', $levelOverflow->getSuggestedSetListConstant());
105+
$this->reportLevelOverflow($levelOverflow);
106+
}
108107

108+
// 0. warn about rules registered in both withRules() and sets to avoid bloated rector.php configs
109+
$setAndRulesDuplicatedRegistrations = $configuration->getBothSetAndRulesDuplicatedRegistrations();
110+
if ($setAndRulesDuplicatedRegistrations !== []) {
109111
$this->symfonyStyle->warning(sprintf(
110-
'The "->%s()" level contains only %d rules, but you set level to %d.%sYou are using the full set now! Time to switch to more efficient "%s".',
111-
$levelOverflow->getConfigurationName(),
112-
$levelOverflow->getRuleCount(),
113-
$levelOverflow->getLevel(),
114-
PHP_EOL,
115-
$suggestedSetMethod,
112+
'These rules are registered in both sets and "withRules()". Remove them from "withRules()" to avoid duplications: %s* %s',
113+
PHP_EOL . PHP_EOL,
114+
implode(' * ', $setAndRulesDuplicatedRegistrations) . PHP_EOL
116115
));
117116
}
118117

@@ -225,4 +224,21 @@ private function reportLoadedComposerBasedSets(): void
225224
$this->symfonyStyle->writeln('[info] Sets loaded based on installed packages:');
226225
$this->symfonyStyle->listing($composerBasedSets);
227226
}
227+
228+
private function reportLevelOverflow(LevelOverflow $levelOverflow): void
229+
{
230+
$suggestedSetMethod = PHP_VERSION_ID >= 80000 ? sprintf(
231+
'->withPreparedSets(%s: true)',
232+
$levelOverflow->getSuggestedRuleset()
233+
) : sprintf('->withSets(SetList::%s)', $levelOverflow->getSuggestedSetListConstant());
234+
235+
$this->symfonyStyle->warning(sprintf(
236+
'The "->%s()" level contains only %d rules, but you set level to %d.%sYou are using the full set now! Time to switch to more efficient "%s".',
237+
$levelOverflow->getConfigurationName(),
238+
$levelOverflow->getRuleCount(),
239+
$levelOverflow->getLevel(),
240+
PHP_EOL,
241+
$suggestedSetMethod,
242+
));
243+
}
228244
}

src/ValueObject/Configuration.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace Rector\ValueObject;
66

77
use Rector\ChangesReporting\Output\ConsoleOutputFormatter;
8+
use Rector\Configuration\Option;
9+
use Rector\Configuration\Parameter\SimpleParameterProvider;
810
use Rector\ValueObject\Configuration\LevelOverflow;
911
use Webmozart\Assert\Assert;
1012

@@ -124,4 +126,18 @@ public function getLevelOverflows(): array
124126
{
125127
return $this->levelOverflows;
126128
}
129+
130+
/**
131+
* @return string[]
132+
*/
133+
public function getBothSetAndRulesDuplicatedRegistrations(): array
134+
{
135+
$rootStandaloneRegisteredRules = SimpleParameterProvider::provideArrayParameter(
136+
Option::ROOT_STANDALONE_REGISTERED_RULES
137+
);
138+
$setRegisteredRules = SimpleParameterProvider::provideArrayParameter(Option::SET_REGISTERED_RULES);
139+
140+
// @todo exclude duplitions
141+
return array_intersect($rootStandaloneRegisteredRules, $setRegisteredRules);
142+
}
127143
}

0 commit comments

Comments
 (0)