Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions conf/config.level0.neon
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,8 @@ conditionalTags:
phpstan.restrictedClassNameUsageExtension: %featureToggles.internalTag%
PHPStan\Rules\InternalTag\RestrictedInternalFunctionUsageExtension:
phpstan.restrictedFunctionUsageExtension: %featureToggles.internalTag%
PHPStan\Rules\Classes\NewStaticInAbstractClassStaticMethodRule:
phpstan.rules.rule: %featureToggles.newStaticInAbstractClassStaticMethod%

services:
-
class: PHPStan\Rules\Classes\NewStaticInAbstractClassStaticMethodRule

-
class: PHPStan\Rules\InternalTag\RestrictedInternalClassConstantUsageExtension

Expand Down
8 changes: 0 additions & 8 deletions conf/config.level1.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,3 @@ parameters:
autowiredAttributeServices:
# registers rules with #[RegisteredRule] attribute
level: 1

conditionalTags:
PHPStan\Rules\Variables\AssignToByRefExprFromForeachRule:
phpstan.rules.rule: %featureToggles.assignToByRefForeachExpr%

services:
-
class: PHPStan\Rules\Variables\AssignToByRefExprFromForeachRule
10 changes: 0 additions & 10 deletions conf/config.level2.neon
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,10 @@ conditionalTags:
phpstan.restrictedPropertyUsageExtension: %featureToggles.internalTag%
PHPStan\Rules\InternalTag\RestrictedInternalMethodUsageExtension:
phpstan.restrictedMethodUsageExtension: %featureToggles.internalTag%
PHPStan\Rules\Constants\ValueAssignedToDefineRule:
phpstan.rules.rule: %featureToggles.checkDynamicConstantNameValues%
PHPStan\Rules\Constants\ValueAssignedToGlobalConstantRule:
phpstan.rules.rule: %featureToggles.checkDynamicConstantNameValues%

services:
-
class: PHPStan\Rules\InternalTag\RestrictedInternalPropertyUsageExtension

-
class: PHPStan\Rules\InternalTag\RestrictedInternalMethodUsageExtension

-
class: PHPStan\Rules\Constants\ValueAssignedToDefineRule

-
class: PHPStan\Rules\Constants\ValueAssignedToGlobalConstantRule
42 changes: 0 additions & 42 deletions conf/config.level4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,5 @@ autowiredAttributeServices:
# registers rules with #[RegisteredRule] and #[RegisteredCollector] attributes
level: 4

conditionalTags:
PHPStan\Rules\Exceptions\TooWideFunctionThrowTypeRule:
phpstan.rules.rule: %exceptions.check.tooWideThrowType%
PHPStan\Rules\Exceptions\TooWideMethodThrowTypeRule:
phpstan.rules.rule: %exceptions.check.tooWideThrowType%
PHPStan\Rules\Exceptions\TooWidePropertyHookThrowTypeRule:
phpstan.rules.rule: %exceptions.check.tooWideThrowType%
PHPStan\Rules\Keywords\UnusedLabelRule:
phpstan.rules.rule: %featureToggles.unusedLabel%
PHPStan\Rules\Comparison\ImpossibleInArrayHaystackFiniteTypesRule:
phpstan.rules.rule: %featureToggles.finiteTypesInHaystack%
PHPStan\Rules\Comparison\SwitchConditionRule:
phpstan.rules.rule: %featureToggles.switchConditionAlwaysFalse%

parameters:
checkAdvancedIsset: true

services:
-
class: PHPStan\Rules\Exceptions\TooWideFunctionThrowTypeRule

-
class: PHPStan\Rules\Exceptions\TooWideMethodThrowTypeRule
arguments:
checkProtectedAndPublicMethods: %checkTooWideThrowTypesInProtectedAndPublicMethods%
tooWideImplicitThrows: %exceptions.check.tooWideImplicitThrowType%

-
class: PHPStan\Rules\Exceptions\TooWidePropertyHookThrowTypeRule
arguments:
checkProtectedAndPublicMethods: %checkTooWideThrowTypesInProtectedAndPublicMethods%

-
class: PHPStan\Rules\Keywords\UnusedLabelRule

-
class: PHPStan\Rules\Comparison\ImpossibleInArrayHaystackFiniteTypesRule
arguments:
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%

-
class: PHPStan\Rules\Comparison\SwitchConditionRule
arguments:
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
18 changes: 0 additions & 18 deletions conf/config.level5.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,6 @@ parameters:
checkFunctionArgumentTypes: true
checkArgumentsPassedByReference: true

conditionalTags:
PHPStan\Rules\Functions\ParameterCastableToNumberRule:
phpstan.rules.rule: %featureToggles.checkParameterCastableToNumberFunctions%
PHPStan\Rules\Functions\PrintfParameterTypeRule:
phpstan.rules.rule: %featureToggles.checkPrintfParameterTypes%
PHPStan\Rules\DateIntervalInstantiationRule:
phpstan.rules.rule: %featureToggles.checkDateIntervalConstructor%

autowiredAttributeServices:
# registers rules with #[RegisteredRule] attribute
level: 5

services:
-
class: PHPStan\Rules\Functions\ParameterCastableToNumberRule
-
class: PHPStan\Rules\Functions\PrintfParameterTypeRule
arguments:
checkStrictPrintfPlaceholderTypes: %checkStrictPrintfPlaceholderTypes%
-
class: PHPStan\Rules\DateIntervalInstantiationRule
29 changes: 0 additions & 29 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -260,36 +260,7 @@ parameters:
autowiredAttributeServices:
level: null

conditionalTags:
PHPStan\Rules\Exceptions\MissingCheckedExceptionInFunctionThrowsRule:
phpstan.rules.rule: %exceptions.check.missingCheckedExceptionInThrows%
PHPStan\Rules\Exceptions\MissingCheckedExceptionInMethodThrowsRule:
phpstan.rules.rule: %exceptions.check.missingCheckedExceptionInThrows%
PHPStan\Rules\Exceptions\MissingCheckedExceptionInPropertyHookThrowsRule:
phpstan.rules.rule: %exceptions.check.missingCheckedExceptionInThrows%
PHPStan\Rules\Properties\UninitializedPropertyRule:
phpstan.rules.rule: %checkUninitializedProperties%
PHPStan\Rules\Exceptions\MethodThrowTypeCovarianceRule:
phpstan.rules.rule: %exceptions.check.throwTypeCovariance%

services:
-
class: PHPStan\Rules\Exceptions\MissingCheckedExceptionInFunctionThrowsRule

-
class: PHPStan\Rules\Exceptions\MissingCheckedExceptionInMethodThrowsRule

-
class: PHPStan\Rules\Exceptions\MissingCheckedExceptionInPropertyHookThrowsRule

-
class: PHPStan\Rules\Properties\UninitializedPropertyRule

-
class: PHPStan\Rules\Exceptions\MethodThrowTypeCovarianceRule
arguments:
implicitThrows: %exceptions.implicitThrows%

# autowired services are now registered with the help of attributes
# like #[PHPStan\DependencyInjection\AutowiredService] or #[PHPStan\DependencyInjection\GenerateFactory]

Expand Down
59 changes: 55 additions & 4 deletions src/DependencyInjection/AutowiredAttributeServicesExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
use function explode;
use function implode;
use function is_array;
use function is_bool;
use function preg_match;
use function preg_split;
use function sprintf;
use function strcasecmp;
Expand All @@ -38,6 +40,9 @@
final class AutowiredAttributeServicesExtension extends CompilerExtension
{

/** @var list<array{ServiceDefinition, string, string}> */
private array $conditionalTags = [];

#[Override]
public function getConfigSchema(): Schema
{
Expand Down Expand Up @@ -133,9 +138,9 @@ public function loadConfiguration(): void

$definition = $builder->addDefinition(null)
->setFactory($class->name)
->setAutowired($class->name)
->addTag(LazyRegistry::RULE_TAG);
->setAutowired($class->name);

$this->tag($definition, LazyRegistry::RULE_TAG, $attribute->enabledBy);
self::processConstructorParameters($builder, $class->name, $definition, $constructorParameters);
}

Expand All @@ -147,13 +152,59 @@ public function loadConfiguration(): void

$definition = $builder->addDefinition(null)
->setFactory($class->name)
->setAutowired($class->name)
->addTag(RegistryFactory::COLLECTOR_TAG);
->setAutowired($class->name);

$this->tag($definition, RegistryFactory::COLLECTOR_TAG, $attribute->enabledBy);
self::processConstructorParameters($builder, $class->name, $definition, $constructorParameters);
}
}

private function tag(ServiceDefinition $definition, string $tag, ?string $enabledBy): void
{
if ($enabledBy === null) {
$definition->addTag($tag);

return;
}

$this->conditionalTags[] = [$definition, $tag, $enabledBy];
}

#[Override]
public function beforeCompile(): void
{
$builder = $this->getContainerBuilder();
foreach ($this->conditionalTags as [$definition, $tag, $enabledBy]) {
if (!self::resolveCondition($builder, $enabledBy)) {
continue;
}

$definition->addTag($tag);
}
}

private static function resolveCondition(ContainerBuilder $builder, string $enabledBy): bool
{
if (preg_match('#^%([\w.-]+)%$#D', $enabledBy, $matches) !== 1) {
throw new ShouldNotHappenException(sprintf('enabledBy must be a parameter reference, %s given.', $enabledBy));
}

$parameter = $builder->parameters;
foreach (explode('.', $matches[1]) as $key) {
if (!is_array($parameter) || !array_key_exists($key, $parameter)) {
throw new ShouldNotHappenException(sprintf("Missing parameter '%s'.", $matches[1]));
}

$parameter = $parameter[$key];
}

if (!is_bool($parameter)) {
throw new ShouldNotHappenException(sprintf('Parameter %s referenced by enabledBy must be bool.', $enabledBy));
}

return $parameter;
}

/**
* @param class-string $className
* @param array<lowercase-string, non-empty-list<TargetMethodParameter<AutowiredParameter>>> $constructorParameters
Expand Down
6 changes: 5 additions & 1 deletion src/DependencyInjection/RegisteredCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
/**
* Registers a collector in the DI container on the set rule level.
*
* Pass enabledBy a `%parameter%` reference to make the registration depend on
* configuration, the way a `conditionalTags` entry would. The collector is only
* tagged when the parameter is truthy.
*
* Works thanks to https://github.com/ondrejmirtes/composer-attribute-collector
* and AutowiredAttributeServicesExtension.
*/
#[Attribute(flags: Attribute::TARGET_CLASS)]
final class RegisteredCollector
{

public function __construct(public int $level)
public function __construct(public int $level, public ?string $enabledBy = null)
{
}

Expand Down
6 changes: 5 additions & 1 deletion src/DependencyInjection/RegisteredRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
/**
* Registers a rule in the DI container on the set rule level.
*
* Pass enabledBy a `%parameter%` reference to make the registration depend on
* configuration, the way a `conditionalTags` entry would. The rule is only
* tagged when the parameter is truthy.
*
* Works thanks to https://github.com/ondrejmirtes/composer-attribute-collector
* and AutowiredAttributeServicesExtension.
*/
#[Attribute(flags: Attribute::TARGET_CLASS)]
final class RegisteredRule
{

public function __construct(public int $level)
public function __construct(public int $level, public ?string $enabledBy = null)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Reflection\Php\PhpMethodFromParserNodeReflection;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
Expand All @@ -13,6 +14,7 @@
/**
* @implements Rule<Node\Expr\New_>
*/
#[RegisteredRule(level: 0, enabledBy: '%featureToggles.newStaticInAbstractClassStaticMethod%')]
final class NewStaticInAbstractClassStaticMethodRule implements Rule
{

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\AutowiredParameter;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Reflection\InitializerExprTypeResolver;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Rules\Rule;
Expand All @@ -30,6 +32,7 @@
*
* @implements Rule<FuncCall>
*/
#[RegisteredRule(level: 4, enabledBy: '%featureToggles.finiteTypesInHaystack%')]
final class ImpossibleInArrayHaystackFiniteTypesRule implements Rule
{

Expand All @@ -42,6 +45,7 @@ final class ImpossibleInArrayHaystackFiniteTypesRule implements Rule

public function __construct(
private InitializerExprTypeResolver $initializerExprTypeResolver,
#[AutowiredParameter(ref: '%treatPhpDocTypesAsCertain%')]
private bool $treatPhpDocTypesAsCertain,
)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Rules/Comparison/SwitchConditionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use PHPStan\Analyser\CollectedDataEmitter;
use PHPStan\Analyser\NodeCallbackInvoker;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\AutowiredParameter;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Node\Printer\ExprPrinter;
use PHPStan\Node\SwitchConditionNode;
use PHPStan\Php\PhpVersion;
Expand All @@ -20,6 +22,7 @@
/**
* @implements Rule<SwitchConditionNode>
*/
#[RegisteredRule(level: 4, enabledBy: '%featureToggles.switchConditionAlwaysFalse%')]
final class SwitchConditionRule implements Rule
{

Expand All @@ -29,6 +32,7 @@ public function __construct(
private ConstantConditionInTraitHelper $constantConditionInTraitHelper,
private ExprPrinter $exprPrinter,
private PhpVersion $phpVersion,
#[AutowiredParameter(ref: '%treatPhpDocTypesAsCertain%')]
private bool $treatPhpDocTypesAsCertain,
)
{
Expand Down
2 changes: 2 additions & 0 deletions src/Rules/Constants/ValueAssignedToDefineRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PhpParser\Node\Expr\FuncCall;
use PHPStan\Analyser\ConstantResolver;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
Expand All @@ -16,6 +17,7 @@
/**
* @implements Rule<FuncCall>
*/
#[RegisteredRule(level: 2, enabledBy: '%featureToggles.checkDynamicConstantNameValues%')]
final class ValueAssignedToDefineRule implements Rule
{

Expand Down
2 changes: 2 additions & 0 deletions src/Rules/Constants/ValueAssignedToGlobalConstantRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PhpParser\Node;
use PHPStan\Analyser\ConstantResolver;
use PHPStan\Analyser\Scope;
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
Expand All @@ -13,6 +14,7 @@
/**
* @implements Rule<Node\Stmt\Const_>
*/
#[RegisteredRule(level: 2, enabledBy: '%featureToggles.checkDynamicConstantNameValues%')]
final class ValueAssignedToGlobalConstantRule implements Rule
{

Expand Down
Loading
Loading