Skip to content

Commit b1b0dc9

Browse files
committed
Rule registry now gets rules instances in lazy manner
1 parent 9bf5694 commit b1b0dc9

13 files changed

+195
-91
lines changed

conf/config.neon

+3-5
Original file line numberDiff line numberDiff line change
@@ -1027,9 +1027,6 @@ services:
10271027
-
10281028
class: PHPStan\Rules\Properties\PropertyReflectionFinder
10291029

1030-
-
1031-
class: PHPStan\Rules\RegistryFactory
1032-
10331030
-
10341031
class: PHPStan\Rules\RuleLevelHelper
10351032
arguments:
@@ -1891,8 +1888,9 @@ services:
18911888
autowired: false
18921889

18931890
registry:
1894-
class: PHPStan\Rules\Registry
1895-
factory: @PHPStan\Rules\RegistryFactory::create
1891+
class: PHPStan\Rules\LazyRegistry
1892+
autowired:
1893+
- PHPStan\Rules\Registry
18961894

18971895
stubPhpDocProvider:
18981896
class: PHPStan\PhpDoc\StubPhpDocProvider

phpstan-baseline.neon

+41-6
Original file line numberDiff line numberDiff line change
@@ -303,19 +303,54 @@ parameters:
303303
path: src/Reflection/SignatureMap/Php8SignatureMapProvider.php
304304

305305
-
306-
message: "#^Method PHPStan\\\\Rules\\\\Registry\\:\\:__construct\\(\\) has parameter \\$rules with generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#"
306+
message: "#^Function class_implements\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#"
307307
count: 1
308-
path: src/Rules/Registry.php
308+
path: src/Rules/DirectRegistry.php
309309

310310
-
311-
message: "#^Property PHPStan\\\\Rules\\\\Registry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
311+
message: "#^Function class_parents\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#"
312312
count: 1
313-
path: src/Rules/Registry.php
313+
path: src/Rules/DirectRegistry.php
314314

315315
-
316-
message: "#^Property PHPStan\\\\Rules\\\\Registry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
316+
message: "#^Method PHPStan\\\\Rules\\\\DirectRegistry\\:\\:__construct\\(\\) has parameter \\$rules with generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#"
317317
count: 1
318-
path: src/Rules/Registry.php
318+
path: src/Rules/DirectRegistry.php
319+
320+
-
321+
message: "#^Property PHPStan\\\\Rules\\\\DirectRegistry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
322+
count: 1
323+
path: src/Rules/DirectRegistry.php
324+
325+
-
326+
message: "#^Property PHPStan\\\\Rules\\\\DirectRegistry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
327+
count: 1
328+
path: src/Rules/DirectRegistry.php
329+
330+
-
331+
message: "#^Function class_implements\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#"
332+
count: 1
333+
path: src/Rules/LazyRegistry.php
334+
335+
-
336+
message: "#^Function class_parents\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#"
337+
count: 1
338+
path: src/Rules/LazyRegistry.php
339+
340+
-
341+
message: "#^Method PHPStan\\\\Rules\\\\LazyRegistry\\:\\:getRulesFromContainer\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
342+
count: 1
343+
path: src/Rules/LazyRegistry.php
344+
345+
-
346+
message: "#^Property PHPStan\\\\Rules\\\\LazyRegistry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
347+
count: 1
348+
path: src/Rules/LazyRegistry.php
349+
350+
-
351+
message: "#^Property PHPStan\\\\Rules\\\\LazyRegistry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
352+
count: 1
353+
path: src/Rules/LazyRegistry.php
319354

320355
-
321356
message: "#^Anonymous function has an unused use \\$container\\.$#"

src/DependencyInjection/ConditionalTagsExtension.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use PHPStan\Collectors\RegistryFactory as CollectorRegistryFactory;
1111
use PHPStan\Parser\RichParser;
1212
use PHPStan\PhpDoc\TypeNodeResolverExtension;
13-
use PHPStan\Rules\RegistryFactory as RuleRegistryFactory;
13+
use PHPStan\Rules\LazyRegistry;
1414
use PHPStan\ShouldNotHappenException;
1515
use function array_reduce;
1616
use function count;
@@ -30,7 +30,7 @@ public function getConfigSchema(): Nette\Schema\Schema
3030
BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG => $bool,
3131
BrokerFactory::DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG => $bool,
3232
BrokerFactory::OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG => $bool,
33-
RuleRegistryFactory::RULE_TAG => $bool,
33+
LazyRegistry::RULE_TAG => $bool,
3434
TypeNodeResolverExtension::EXTENSION_TAG => $bool,
3535
TypeSpecifierFactory::FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG => $bool,
3636
TypeSpecifierFactory::METHOD_TYPE_SPECIFYING_EXTENSION_TAG => $bool,

src/DependencyInjection/RulesExtension.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Nette\DI\CompilerExtension;
66
use Nette\Schema\Expect;
77
use Nette\Schema\Schema;
8-
use PHPStan\Rules\RegistryFactory;
8+
use PHPStan\Rules\LazyRegistry;
99

1010
class RulesExtension extends CompilerExtension
1111
{
@@ -25,7 +25,7 @@ public function loadConfiguration(): void
2525
$builder->addDefinition($this->prefix((string) $key))
2626
->setFactory($rule)
2727
->setAutowired($rule)
28-
->addTag(RegistryFactory::RULE_TAG);
28+
->addTag(LazyRegistry::RULE_TAG);
2929
}
3030
}
3131

src/PhpDoc/StubValidator.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use PHPStan\Rules\Classes\ExistingClassesInInterfaceExtendsRule;
2020
use PHPStan\Rules\Classes\ExistingClassInClassExtendsRule;
2121
use PHPStan\Rules\Classes\ExistingClassInTraitUseRule;
22+
use PHPStan\Rules\DirectRegistry as DirectRuleRegistry;
2223
use PHPStan\Rules\FunctionDefinitionCheck;
2324
use PHPStan\Rules\Functions\MissingFunctionParameterTypehintRule;
2425
use PHPStan\Rules\Functions\MissingFunctionReturnTypehintRule;
@@ -185,7 +186,7 @@ private function getRuleRegistry(Container $container): RuleRegistry
185186
new MissingPropertyTypehintRule($missingTypehintCheck),
186187
];
187188

188-
return new RuleRegistry($rules);
189+
return new DirectRuleRegistry($rules);
189190
}
190191

191192
private function getCollectorRegistry(Container $container): CollectorRegistry

src/Rules/DirectRegistry.php

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use PhpParser\Node;
6+
use function class_implements;
7+
use function class_parents;
8+
9+
class DirectRegistry implements Registry
10+
{
11+
12+
/** @var Rule[][] */
13+
private array $rules = [];
14+
15+
/** @var Rule[][] */
16+
private array $cache = [];
17+
18+
/**
19+
* @param Rule[] $rules
20+
*/
21+
public function __construct(array $rules)
22+
{
23+
foreach ($rules as $rule) {
24+
$this->rules[$rule->getNodeType()][] = $rule;
25+
}
26+
}
27+
28+
/**
29+
* @template TNodeType of Node
30+
* @phpstan-param class-string<TNodeType> $nodeType
31+
* @param Node $nodeType
32+
* @phpstan-return array<Rule<TNodeType>>
33+
* @return Rule[]
34+
*/
35+
public function getRules(string $nodeType): array
36+
{
37+
if (!isset($this->cache[$nodeType])) {
38+
$parentNodeTypes = [$nodeType] + class_parents($nodeType) + class_implements($nodeType);
39+
40+
$rules = [];
41+
foreach ($parentNodeTypes as $parentNodeType) {
42+
foreach ($this->rules[$parentNodeType] ?? [] as $rule) {
43+
$rules[] = $rule;
44+
}
45+
}
46+
47+
$this->cache[$nodeType] = $rules;
48+
}
49+
50+
/**
51+
* @phpstan-var array<Rule<TNodeType>> $selectedRules
52+
* @var Rule[] $selectedRules
53+
*/
54+
$selectedRules = $this->cache[$nodeType];
55+
56+
return $selectedRules;
57+
}
58+
59+
}

src/Rules/LazyRegistry.php

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules;
4+
5+
use PhpParser\Node;
6+
use PHPStan\DependencyInjection\Container;
7+
use function class_implements;
8+
use function class_parents;
9+
10+
class LazyRegistry implements Registry
11+
{
12+
13+
public const RULE_TAG = 'phpstan.rules.rule';
14+
15+
/** @var Rule[][]|null */
16+
private ?array $rules = null;
17+
18+
/** @var Rule[][] */
19+
private array $cache = [];
20+
21+
public function __construct(private Container $container)
22+
{
23+
}
24+
25+
/**
26+
* @template TNodeType of Node
27+
* @phpstan-param class-string<TNodeType> $nodeType
28+
* @param Node $nodeType
29+
* @phpstan-return array<Rule<TNodeType>>
30+
* @return Rule[]
31+
*/
32+
public function getRules(string $nodeType): array
33+
{
34+
if (!isset($this->cache[$nodeType])) {
35+
$parentNodeTypes = [$nodeType] + class_parents($nodeType) + class_implements($nodeType);
36+
37+
$rules = [];
38+
$rulesFromContainer = $this->getRulesFromContainer();
39+
foreach ($parentNodeTypes as $parentNodeType) {
40+
foreach ($rulesFromContainer[$parentNodeType] ?? [] as $rule) {
41+
$rules[] = $rule;
42+
}
43+
}
44+
45+
$this->cache[$nodeType] = $rules;
46+
}
47+
48+
/**
49+
* @phpstan-var array<Rule<TNodeType>> $selectedRules
50+
* @var Rule[] $selectedRules
51+
*/
52+
$selectedRules = $this->cache[$nodeType];
53+
54+
return $selectedRules;
55+
}
56+
57+
/**
58+
* @return Rule[][]
59+
*/
60+
private function getRulesFromContainer(): array
61+
{
62+
if ($this->rules !== null) {
63+
return $this->rules;
64+
}
65+
66+
$rules = [];
67+
foreach ($this->container->getServicesByTag(self::RULE_TAG) as $rule) {
68+
$rules[$rule->getNodeType()][] = $rule;
69+
}
70+
71+
return $this->rules = $rules;
72+
}
73+
74+
}

src/Rules/Registry.php

+2-42
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,17 @@
33
namespace PHPStan\Rules;
44

55
use PhpParser\Node;
6-
use function class_implements;
7-
use function class_parents;
86

9-
class Registry
7+
interface Registry
108
{
119

12-
/** @var Rule[][] */
13-
private array $rules = [];
14-
15-
/** @var Rule[][] */
16-
private array $cache = [];
17-
18-
/**
19-
* @param Rule[] $rules
20-
*/
21-
public function __construct(array $rules)
22-
{
23-
foreach ($rules as $rule) {
24-
$this->rules[$rule->getNodeType()][] = $rule;
25-
}
26-
}
27-
2810
/**
2911
* @template TNodeType of Node
3012
* @phpstan-param class-string<TNodeType> $nodeType
3113
* @param Node $nodeType
3214
* @phpstan-return array<Rule<TNodeType>>
3315
* @return Rule[]
3416
*/
35-
public function getRules(string $nodeType): array
36-
{
37-
if (!isset($this->cache[$nodeType])) {
38-
$parentNodeTypes = [$nodeType] + class_parents($nodeType) + class_implements($nodeType);
39-
40-
$rules = [];
41-
foreach ($parentNodeTypes as $parentNodeType) {
42-
foreach ($this->rules[$parentNodeType] ?? [] as $rule) {
43-
$rules[] = $rule;
44-
}
45-
}
46-
47-
$this->cache[$nodeType] = $rules;
48-
}
49-
50-
/**
51-
* @phpstan-var array<Rule<TNodeType>> $selectedRules
52-
* @var Rule[] $selectedRules
53-
*/
54-
$selectedRules = $this->cache[$nodeType];
55-
56-
return $selectedRules;
57-
}
17+
public function getRules(string $nodeType): array;
5818

5919
}

src/Rules/RegistryFactory.php

-23
This file was deleted.

src/Testing/RuleTestCase.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
2121
use PHPStan\PhpDoc\StubPhpDocProvider;
2222
use PHPStan\Reflection\InitializerExprTypeResolver;
23+
use PHPStan\Rules\DirectRegistry as DirectRuleRegistry;
2324
use PHPStan\Rules\Properties\DirectReadWritePropertiesExtensionProvider;
2425
use PHPStan\Rules\Properties\ReadWritePropertiesExtension;
2526
use PHPStan\Rules\Properties\ReadWritePropertiesExtensionProvider;
26-
use PHPStan\Rules\Registry as RuleRegistry;
2727
use PHPStan\Rules\Rule;
2828
use PHPStan\Type\FileTypeMapper;
2929
use function array_map;
@@ -69,7 +69,7 @@ protected function getTypeSpecifier(): TypeSpecifier
6969
private function getAnalyser(): Analyser
7070
{
7171
if ($this->analyser === null) {
72-
$ruleRegistry = new RuleRegistry([
72+
$ruleRegistry = new DirectRuleRegistry([
7373
$this->getRule(),
7474
]);
7575
$collectorRegistry = new CollectorRegistry($this->getCollectors());
@@ -138,7 +138,7 @@ public function analyse(array $files, array $expectedErrors): void
138138
$actualErrors = $analyserResult->getUnorderedErrors();
139139
$ruleErrorTransformer = new RuleErrorTransformer();
140140
if (count($analyserResult->getCollectedData()) > 0) {
141-
$ruleRegistry = new RuleRegistry([
141+
$ruleRegistry = new DirectRuleRegistry([
142142
$this->getRule(),
143143
]);
144144

0 commit comments

Comments
 (0)