Skip to content

Commit

Permalink
Call acceptsWithReason via RuleLevelHelper
Browse files Browse the repository at this point in the history
  • Loading branch information
erickskrauch committed Jul 18, 2023
1 parent 176f0bc commit d3b9fd4
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 13 deletions.
2 changes: 2 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ parametersSchema:
])

services:
- class: ErickSkrauch\PHPStan\Yii2\Rule\YiiConfigHelper

- class: ErickSkrauch\PHPStan\Yii2\Reflection\ApplicationPropertiesClassReflectionExtension
tags: [phpstan.broker.propertiesClassReflectionExtension]

Expand Down
1 change: 1 addition & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ parameters:
yii2:
config_path: tests/assets/yii-config-valid.php
ignoreErrors:
- '#Calling PHPStan\\Rules\\RuleLevelHelper::acceptsWithReason\(\) is not covered.+#'
- '#Calling PHPStan\\Reflection\\Annotations\\AnnotationsPropertiesClassReflectionExtension\:\:(has|get)Property\(\) is not covered.+#'
- '#Creating new PHPStan\\Reflection\\Dummy\\DummyPropertyReflection is not covered.+#'
11 changes: 7 additions & 4 deletions src/Rule/CreateObjectRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ final class CreateObjectRule implements Rule {

private ReflectionProvider $reflectionProvider;

public function __construct(ReflectionProvider $reflectionProvider) {
private YiiConfigHelper $configHelper;

public function __construct(ReflectionProvider $reflectionProvider, YiiConfigHelper $configHelper) {
$this->reflectionProvider = $reflectionProvider;
$this->configHelper = $configHelper;
}

public function getNodeType(): string {
Expand Down Expand Up @@ -60,7 +63,7 @@ public function processNode(Node $node, Scope $scope): array {
if ($firstArgType->isConstantArray()->yes()) {
/** @var \PHPStan\Type\Constant\ConstantArrayType $config */
$config = $firstArgType->getConstantArrays()[0];
$classNameOrError = YiiConfig::findClass($config);
$classNameOrError = $this->configHelper->findClass($config);
if ($classNameOrError instanceof RuleError) {
return [$classNameOrError];
}
Expand All @@ -76,7 +79,7 @@ public function processNode(Node $node, Scope $scope): array {

$classReflection = $this->reflectionProvider->getClass($classNameOrError);

$errors = array_merge($errors, YiiConfig::validateArray($classReflection, $config, $scope));
$errors = array_merge($errors, $this->configHelper->validateArray($classReflection, $config, $scope));
} elseif ($firstArgType->isClassStringType()->yes()) {
$classNamesTypes = $firstArgType->getConstantStrings();
// At this moment I'll skip supporting of multiple classes at once
Expand Down Expand Up @@ -107,7 +110,7 @@ public function processNode(Node $node, Scope $scope): array {
$secondArgConstantArrays = $scope->getType($args[1]->value)->getConstantArrays();
if (count($secondArgConstantArrays) === 1) {
$argsConfig = $secondArgConstantArrays[0];
$errors = array_merge($errors, YiiConfig::validateConstructorArgs($classReflection, $argsConfig, $scope));
$errors = array_merge($errors, $this->configHelper->validateConstructorArgs($classReflection, $argsConfig, $scope));
}
}

Expand Down
24 changes: 16 additions & 8 deletions src/Rule/YiiConfig.php → src/Rule/YiiConfigHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,25 @@
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\VerbosityLevel;

final class YiiConfig {
final class YiiConfigHelper {

private RuleLevelHelper $ruleLevelHelper;

public function __construct(RuleLevelHelper $ruleLevelHelper) {
$this->ruleLevelHelper = $ruleLevelHelper;
}

/**
* @param ConstantArrayType $config
* @return string|\PHPStan\Rules\IdentifierRuleError
*/
public static function findClass(ConstantArrayType $config) {
public function findClass(ConstantArrayType $config) {
$class = $config->getOffsetValueType(new ConstantStringType('__class'));
if (count($class->getConstantStrings()) === 1) {
return $class->getConstantStrings()[0]->getValue();
Expand All @@ -37,7 +44,7 @@ public static function findClass(ConstantArrayType $config) {
/**
* @phpstan-return list<\PHPStan\Rules\IdentifierRuleError>
*/
public static function validateArray(ClassReflection $classReflection, ConstantArrayType $config, Scope $scope): array {
public function validateArray(ClassReflection $classReflection, ConstantArrayType $config, Scope $scope): array {
$errors = [];
/** @var ConstantIntegerType|ConstantStringType $key */
foreach ($config->getKeyTypes() as $i => $key) {
Expand Down Expand Up @@ -115,8 +122,8 @@ public static function validateArray(ClassReflection $classReflection, ConstantA
}

$target = $property->getWritableType();
$result = $target->acceptsWithReason($value, true);
if (!$result->yes()) {
$result = $this->ruleLevelHelper->acceptsWithReason($target, $value, $scope->isDeclareStrictTypes());
if (!$result->result) {
$level = VerbosityLevel::getRecommendedLevelByType($target, $value);
$errors[] = RuleErrorBuilder::message(sprintf(
'Property %s::$%s (%s) does not accept %s.',
Expand All @@ -137,7 +144,7 @@ public static function validateArray(ClassReflection $classReflection, ConstantA
/**
* @phpstan-return list<\PHPStan\Rules\IdentifierRuleError>
*/
public static function validateConstructorArgs(ClassReflection $classReflection, ConstantArrayType $config, Scope $scope): array {
public function validateConstructorArgs(ClassReflection $classReflection, ConstantArrayType $config, Scope $scope): array {
$constructorParams = ParametersAcceptorSelector::selectSingle($classReflection->getConstructor()->getVariants())->getParameters();
/** @var \PHPStan\Type\Type|null $firstKeyType */
$firstKeyType = null;
Expand Down Expand Up @@ -194,11 +201,12 @@ public static function validateConstructorArgs(ClassReflection $classReflection,
}
}

/** @var \PHPStan\Reflection\ParameterReflection $paramReflection */
// TODO: prevent direct pass of 'config' param to constructor args (\yii\base\Configurable)

$paramType = $paramReflection->getType();
$result = $paramType->acceptsWithReason($value, true);
if (!$result->yes()) {
$result = $this->ruleLevelHelper->acceptsWithReason($paramType, $value, $scope->isDeclareStrictTypes());
if (!$result->result) {
$level = VerbosityLevel::getRecommendedLevelByType($paramType, $value);
$errors[] = RuleErrorBuilder::message(sprintf(
'Parameter #%d %s of class %s constructor expects %s, %s given.',
Expand Down
6 changes: 5 additions & 1 deletion tests/Rule/CreateObjectRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace ErickSkrauch\PHPStan\Yii2\Tests\Rule;

use ErickSkrauch\PHPStan\Yii2\Rule\CreateObjectRule;
use ErickSkrauch\PHPStan\Yii2\Rule\YiiConfigHelper;
use ErickSkrauch\PHPStan\Yii2\Tests\ConfigTrait;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
Expand Down Expand Up @@ -53,7 +54,10 @@ public function testRule(): void {
}

protected function getRule(): Rule {
return new CreateObjectRule(self::createReflectionProvider());
return new CreateObjectRule(
self::createReflectionProvider(),
self::getContainer()->getByType(YiiConfigHelper::class),
);
}

}

0 comments on commit d3b9fd4

Please sign in to comment.