Repository navigation
Commit eb913d8
committed
[Config] Only registered rules count as active rules
findByContract() returns every instance the container has cached that implements
the contract. A rule that another service takes as a constructor dependency is
built and cached like any other object, so it comes back as an active rule even
though no config ever registered it.
Five services take an autowired "@PARAM RectorInterface[]": RectorNodeTraverser,
ConfigInitializer, OnlyRuleResolver, DeprecatedRulesReporter and
ComposerBasedCommand. Entropy resolves an array parameter through
findByContract() (Container::resolve(), ParameterTypesResolver), so this is not
a test-only concern -- bin/rector applies the rule:
bin/rector process <dir> --dry-run --clear-cache --config <that config>
- return 'marker';
+ return 'rewritten by an unregistered rule';
Applied rules:
* UnregisteredMarkerRector
AbstractRectorTestCase::setUp() reads the same list for refreshPhpRectors().
Narrowing in RectorConfig::findByContract() covers all of them, because they all
go through it. Filtering in the test case alone would have left bin/rector as it
is and made the test stricter than the product.
The registered set is already tracked: rule() records into
$registeredRectorClasses, and every registration path funnels through rule() --
rules(), ruleWithConfiguration(), and ruleWithConfigurationComposerVersionBound(),
which returns before rule() when the package constraint is not satisfied. The
filter can therefore only remove rules nobody registered; it cannot activate one
the composer-package filter excluded. warmUpInstanceServices() builds every
registered class of the contract first, so the filtered result is exactly the
registered set, whatever the container happened to build earlier.
Contracts that are not rule contracts are returned untouched, and so is a wider
one: findByContract(NodeVisitor::class) still sees unregistered rules. That
keeps registerDecoratingNodeVisitor() working, which registers through
singleton() rather than rule().
One behaviour change reaches users. A rule class registered through
RectorConfigBuilder::registerService() goes to singleton() directly, past
rule(), and is no longer active. That method carries no RectorInterface
assertion, so a config out there may rely on it. Before 2.6.4 it behaved the
same way, because rule() set the tag and singleton() did not.
The emptiness assertion in AbstractRectorTestCase now asks through NodeVisitor
instead of RectorInterface. Read through the rule contract it could no longer
fail: resetRuleConfigurations() empties the registered list two lines earlier,
so the answer would be "empty" without looking at what forgetRectorsRules()
actually left behind. The wider contract still sees a surviving rule instance,
which is what the assertion is there to catch -- a stale instance is handed back
by Container::make() before the afterResolving() callback runs, so the next test
class registering the same rule would run it with the previous class's
configuration.
Before 2.6.4 this decision was made by tagged(RectorInterface::class), an
explicit tag list filled by rule(). Registration decided what was active; since
the container swap, existence does. This restores the former behaviour.
The test goes to tests/Config/RectorConfigTest.php, at the seam the fix sits on:
a rule is registered, its constructor dependency is another rule, and only the
registered one comes back as active. A fixture test under tests/Issues would
have gone through AbstractRectorTestCase and stayed green if the filter moved
back into the test case.
Found while fixing ssch/typo3-rector for 2.6.4, where ValidateAttributeDecorator
takes StringClassNameToClassConstantRector in its constructor: the Extbase test
resolved two active rules against one registered.
Assisted-by: claude-code:claude-fable-5
Agent-Session: https://claude.ai/code/session_019wx8ueHuqUidp5yybDQ2CN
Agent-Host: 0493f0
Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>1 parent c1c61c4 commit eb913d8
5 files changed
Lines changed: 133 additions & 2 deletions
File tree
- src
- Config
- Testing/PHPUnit
- tests/Config
- Source
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
568 | 568 | | |
569 | 569 | | |
570 | 570 | | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
571 | 603 | | |
572 | 604 | | |
573 | 605 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
100 | 101 | | |
101 | 102 | | |
102 | 103 | | |
103 | | - | |
104 | | - | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
105 | 113 | | |
106 | 114 | | |
107 | 115 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| 18 | + | |
| 19 | + | |
17 | 20 | | |
18 | 21 | | |
19 | 22 | | |
| |||
89 | 92 | | |
90 | 93 | | |
91 | 94 | | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
92 | 112 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
0 commit comments