Skip to content

Commit

Permalink
Rule registry now gets rules instances in lazy manner
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Oct 12, 2022
1 parent 9bf5694 commit b1b0dc9
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 91 deletions.
8 changes: 3 additions & 5 deletions conf/config.neon
Expand Up @@ -1027,9 +1027,6 @@ services:
-
class: PHPStan\Rules\Properties\PropertyReflectionFinder

-
class: PHPStan\Rules\RegistryFactory

-
class: PHPStan\Rules\RuleLevelHelper
arguments:
Expand Down Expand Up @@ -1891,8 +1888,9 @@ services:
autowired: false

registry:
class: PHPStan\Rules\Registry
factory: @PHPStan\Rules\RegistryFactory::create
class: PHPStan\Rules\LazyRegistry
autowired:
- PHPStan\Rules\Registry

stubPhpDocProvider:
class: PHPStan\PhpDoc\StubPhpDocProvider
Expand Down
47 changes: 41 additions & 6 deletions phpstan-baseline.neon
Expand Up @@ -303,19 +303,54 @@ parameters:
path: src/Reflection/SignatureMap/Php8SignatureMapProvider.php

-
message: "#^Method PHPStan\\\\Rules\\\\Registry\\:\\:__construct\\(\\) has parameter \\$rules with generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#"
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\\.$#"
count: 1
path: src/Rules/Registry.php
path: src/Rules/DirectRegistry.php

-
message: "#^Property PHPStan\\\\Rules\\\\Registry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
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\\.$#"
count: 1
path: src/Rules/Registry.php
path: src/Rules/DirectRegistry.php

-
message: "#^Property PHPStan\\\\Rules\\\\Registry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
message: "#^Method PHPStan\\\\Rules\\\\DirectRegistry\\:\\:__construct\\(\\) has parameter \\$rules with generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#"
count: 1
path: src/Rules/Registry.php
path: src/Rules/DirectRegistry.php

-
message: "#^Property PHPStan\\\\Rules\\\\DirectRegistry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
count: 1
path: src/Rules/DirectRegistry.php

-
message: "#^Property PHPStan\\\\Rules\\\\DirectRegistry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
count: 1
path: src/Rules/DirectRegistry.php

-
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\\.$#"
count: 1
path: src/Rules/LazyRegistry.php

-
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\\.$#"
count: 1
path: src/Rules/LazyRegistry.php

-
message: "#^Method PHPStan\\\\Rules\\\\LazyRegistry\\:\\:getRulesFromContainer\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
count: 1
path: src/Rules/LazyRegistry.php

-
message: "#^Property PHPStan\\\\Rules\\\\LazyRegistry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
count: 1
path: src/Rules/LazyRegistry.php

-
message: "#^Property PHPStan\\\\Rules\\\\LazyRegistry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#"
count: 1
path: src/Rules/LazyRegistry.php

-
message: "#^Anonymous function has an unused use \\$container\\.$#"
Expand Down
4 changes: 2 additions & 2 deletions src/DependencyInjection/ConditionalTagsExtension.php
Expand Up @@ -10,7 +10,7 @@
use PHPStan\Collectors\RegistryFactory as CollectorRegistryFactory;
use PHPStan\Parser\RichParser;
use PHPStan\PhpDoc\TypeNodeResolverExtension;
use PHPStan\Rules\RegistryFactory as RuleRegistryFactory;
use PHPStan\Rules\LazyRegistry;
use PHPStan\ShouldNotHappenException;
use function array_reduce;
use function count;
Expand All @@ -30,7 +30,7 @@ public function getConfigSchema(): Nette\Schema\Schema
BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG => $bool,
BrokerFactory::DYNAMIC_FUNCTION_RETURN_TYPE_EXTENSION_TAG => $bool,
BrokerFactory::OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG => $bool,
RuleRegistryFactory::RULE_TAG => $bool,
LazyRegistry::RULE_TAG => $bool,
TypeNodeResolverExtension::EXTENSION_TAG => $bool,
TypeSpecifierFactory::FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG => $bool,
TypeSpecifierFactory::METHOD_TYPE_SPECIFYING_EXTENSION_TAG => $bool,
Expand Down
4 changes: 2 additions & 2 deletions src/DependencyInjection/RulesExtension.php
Expand Up @@ -5,7 +5,7 @@
use Nette\DI\CompilerExtension;
use Nette\Schema\Expect;
use Nette\Schema\Schema;
use PHPStan\Rules\RegistryFactory;
use PHPStan\Rules\LazyRegistry;

class RulesExtension extends CompilerExtension
{
Expand All @@ -25,7 +25,7 @@ public function loadConfiguration(): void
$builder->addDefinition($this->prefix((string) $key))
->setFactory($rule)
->setAutowired($rule)
->addTag(RegistryFactory::RULE_TAG);
->addTag(LazyRegistry::RULE_TAG);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/PhpDoc/StubValidator.php
Expand Up @@ -19,6 +19,7 @@
use PHPStan\Rules\Classes\ExistingClassesInInterfaceExtendsRule;
use PHPStan\Rules\Classes\ExistingClassInClassExtendsRule;
use PHPStan\Rules\Classes\ExistingClassInTraitUseRule;
use PHPStan\Rules\DirectRegistry as DirectRuleRegistry;
use PHPStan\Rules\FunctionDefinitionCheck;
use PHPStan\Rules\Functions\MissingFunctionParameterTypehintRule;
use PHPStan\Rules\Functions\MissingFunctionReturnTypehintRule;
Expand Down Expand Up @@ -185,7 +186,7 @@ private function getRuleRegistry(Container $container): RuleRegistry
new MissingPropertyTypehintRule($missingTypehintCheck),
];

return new RuleRegistry($rules);
return new DirectRuleRegistry($rules);
}

private function getCollectorRegistry(Container $container): CollectorRegistry
Expand Down
59 changes: 59 additions & 0 deletions src/Rules/DirectRegistry.php
@@ -0,0 +1,59 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules;

use PhpParser\Node;
use function class_implements;
use function class_parents;

class DirectRegistry implements Registry
{

/** @var Rule[][] */
private array $rules = [];

/** @var Rule[][] */
private array $cache = [];

/**
* @param Rule[] $rules
*/
public function __construct(array $rules)
{
foreach ($rules as $rule) {
$this->rules[$rule->getNodeType()][] = $rule;
}
}

/**
* @template TNodeType of Node
* @phpstan-param class-string<TNodeType> $nodeType
* @param Node $nodeType
* @phpstan-return array<Rule<TNodeType>>
* @return Rule[]
*/
public function getRules(string $nodeType): array
{
if (!isset($this->cache[$nodeType])) {
$parentNodeTypes = [$nodeType] + class_parents($nodeType) + class_implements($nodeType);

$rules = [];
foreach ($parentNodeTypes as $parentNodeType) {
foreach ($this->rules[$parentNodeType] ?? [] as $rule) {
$rules[] = $rule;
}
}

$this->cache[$nodeType] = $rules;
}

/**
* @phpstan-var array<Rule<TNodeType>> $selectedRules
* @var Rule[] $selectedRules
*/
$selectedRules = $this->cache[$nodeType];

return $selectedRules;
}

}
74 changes: 74 additions & 0 deletions src/Rules/LazyRegistry.php
@@ -0,0 +1,74 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules;

use PhpParser\Node;
use PHPStan\DependencyInjection\Container;
use function class_implements;
use function class_parents;

class LazyRegistry implements Registry
{

public const RULE_TAG = 'phpstan.rules.rule';

/** @var Rule[][]|null */
private ?array $rules = null;

/** @var Rule[][] */
private array $cache = [];

public function __construct(private Container $container)
{
}

/**
* @template TNodeType of Node
* @phpstan-param class-string<TNodeType> $nodeType
* @param Node $nodeType
* @phpstan-return array<Rule<TNodeType>>
* @return Rule[]
*/
public function getRules(string $nodeType): array
{
if (!isset($this->cache[$nodeType])) {
$parentNodeTypes = [$nodeType] + class_parents($nodeType) + class_implements($nodeType);

$rules = [];
$rulesFromContainer = $this->getRulesFromContainer();
foreach ($parentNodeTypes as $parentNodeType) {
foreach ($rulesFromContainer[$parentNodeType] ?? [] as $rule) {
$rules[] = $rule;
}
}

$this->cache[$nodeType] = $rules;
}

/**
* @phpstan-var array<Rule<TNodeType>> $selectedRules
* @var Rule[] $selectedRules
*/
$selectedRules = $this->cache[$nodeType];

return $selectedRules;
}

/**
* @return Rule[][]
*/
private function getRulesFromContainer(): array
{
if ($this->rules !== null) {
return $this->rules;
}

$rules = [];
foreach ($this->container->getServicesByTag(self::RULE_TAG) as $rule) {
$rules[$rule->getNodeType()][] = $rule;
}

return $this->rules = $rules;
}

}
44 changes: 2 additions & 42 deletions src/Rules/Registry.php
Expand Up @@ -3,57 +3,17 @@
namespace PHPStan\Rules;

use PhpParser\Node;
use function class_implements;
use function class_parents;

class Registry
interface Registry
{

/** @var Rule[][] */
private array $rules = [];

/** @var Rule[][] */
private array $cache = [];

/**
* @param Rule[] $rules
*/
public function __construct(array $rules)
{
foreach ($rules as $rule) {
$this->rules[$rule->getNodeType()][] = $rule;
}
}

/**
* @template TNodeType of Node
* @phpstan-param class-string<TNodeType> $nodeType
* @param Node $nodeType
* @phpstan-return array<Rule<TNodeType>>
* @return Rule[]
*/
public function getRules(string $nodeType): array
{
if (!isset($this->cache[$nodeType])) {
$parentNodeTypes = [$nodeType] + class_parents($nodeType) + class_implements($nodeType);

$rules = [];
foreach ($parentNodeTypes as $parentNodeType) {
foreach ($this->rules[$parentNodeType] ?? [] as $rule) {
$rules[] = $rule;
}
}

$this->cache[$nodeType] = $rules;
}

/**
* @phpstan-var array<Rule<TNodeType>> $selectedRules
* @var Rule[] $selectedRules
*/
$selectedRules = $this->cache[$nodeType];

return $selectedRules;
}
public function getRules(string $nodeType): array;

}
23 changes: 0 additions & 23 deletions src/Rules/RegistryFactory.php

This file was deleted.

6 changes: 3 additions & 3 deletions src/Testing/RuleTestCase.php
Expand Up @@ -20,10 +20,10 @@
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
use PHPStan\PhpDoc\StubPhpDocProvider;
use PHPStan\Reflection\InitializerExprTypeResolver;
use PHPStan\Rules\DirectRegistry as DirectRuleRegistry;
use PHPStan\Rules\Properties\DirectReadWritePropertiesExtensionProvider;
use PHPStan\Rules\Properties\ReadWritePropertiesExtension;
use PHPStan\Rules\Properties\ReadWritePropertiesExtensionProvider;
use PHPStan\Rules\Registry as RuleRegistry;
use PHPStan\Rules\Rule;
use PHPStan\Type\FileTypeMapper;
use function array_map;
Expand Down Expand Up @@ -69,7 +69,7 @@ protected function getTypeSpecifier(): TypeSpecifier
private function getAnalyser(): Analyser
{
if ($this->analyser === null) {
$ruleRegistry = new RuleRegistry([
$ruleRegistry = new DirectRuleRegistry([
$this->getRule(),
]);
$collectorRegistry = new CollectorRegistry($this->getCollectors());
Expand Down Expand Up @@ -138,7 +138,7 @@ public function analyse(array $files, array $expectedErrors): void
$actualErrors = $analyserResult->getUnorderedErrors();
$ruleErrorTransformer = new RuleErrorTransformer();
if (count($analyserResult->getCollectedData()) > 0) {
$ruleRegistry = new RuleRegistry([
$ruleRegistry = new DirectRuleRegistry([
$this->getRule(),
]);

Expand Down

0 comments on commit b1b0dc9

Please sign in to comment.