diff --git a/composer.json b/composer.json index 3554449e..abbc08b0 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ ], "require": { "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^0.12.60" + "phpstan/phpstan": "^0.12.66" }, "require-dev": { "phing/phing": "^2.16.3", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index f5968cd9..c271301d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2,16 +2,6 @@ parameters: ignoreErrors: - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanAndRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\BinaryOp\\\\BooleanAnd\\) of method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanAndRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanNotRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" count: 1 @@ -22,16 +12,6 @@ parameters: count: 1 path: src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanOrRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\BinaryOp\\\\BooleanOr\\) of method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanOrRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInElseIfConditionRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" count: 1 @@ -282,16 +262,6 @@ parameters: count: 1 path: src/Rules/VariableVariables/VariableVariablesRule.php - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanAndRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanAndRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanNotRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" count: 1 @@ -302,16 +272,6 @@ parameters: count: 1 path: tests/Rules/BooleansInConditions/BooleanInBooleanNotRuleTest.php - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanOrRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanOrRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInElseIfConditionRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" count: 1 diff --git a/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php b/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php index bdea564c..be661639 100644 --- a/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php +++ b/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php @@ -2,8 +2,13 @@ namespace PHPStan\Rules\BooleansInConditions; +use PhpParser\Node\Expr\BinaryOp\BooleanAnd; +use PHPStan\Node\BooleanAndNode; use PHPStan\Type\VerbosityLevel; +/** + * @implements \PHPStan\Rules\Rule + */ class BooleanInBooleanAndRule implements \PHPStan\Rules\Rule { @@ -17,27 +22,28 @@ public function __construct(BooleanRuleHelper $helper) public function getNodeType(): string { - return \PhpParser\Node\Expr\BinaryOp\BooleanAnd::class; + return BooleanAndNode::class; } - /** - * @param \PhpParser\Node\Expr\BinaryOp\BooleanAnd $node - * @param \PHPStan\Analyser\Scope $scope - * @return string[] errors - */ public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array { + $originalNode = $node->getOriginalNode(); + if (!$originalNode instanceof BooleanAnd) { + return []; + } + $messages = []; - if (!$this->helper->passesAsBoolean($scope, $node->left)) { - $leftType = $scope->getType($node->left); + if (!$this->helper->passesAsBoolean($scope, $originalNode->left)) { + $leftType = $scope->getType($originalNode->left); $messages[] = sprintf( 'Only booleans are allowed in &&, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) ); } - $rightType = $scope->getType($node->right); - if (!$this->helper->passesAsBoolean($scope, $node->right)) { + $rightScope = $node->getRightScope(); + if (!$this->helper->passesAsBoolean($rightScope, $originalNode->right)) { + $rightType = $rightScope->getType($originalNode->right); $messages[] = sprintf( 'Only booleans are allowed in &&, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) diff --git a/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php b/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php index 77b90269..deb64152 100644 --- a/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php +++ b/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php @@ -2,8 +2,13 @@ namespace PHPStan\Rules\BooleansInConditions; +use PhpParser\Node\Expr\BinaryOp\BooleanOr; +use PHPStan\Node\BooleanOrNode; use PHPStan\Type\VerbosityLevel; +/** + * @implements \PHPStan\Rules\Rule + */ class BooleanInBooleanOrRule implements \PHPStan\Rules\Rule { @@ -17,27 +22,28 @@ public function __construct(BooleanRuleHelper $helper) public function getNodeType(): string { - return \PhpParser\Node\Expr\BinaryOp\BooleanOr::class; + return BooleanOrNode::class; } - /** - * @param \PhpParser\Node\Expr\BinaryOp\BooleanOr $node - * @param \PHPStan\Analyser\Scope $scope - * @return string[] errors - */ public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array { + $originalNode = $node->getOriginalNode(); + if (!$originalNode instanceof BooleanOr) { + return []; + } + $messages = []; - if (!$this->helper->passesAsBoolean($scope, $node->left)) { - $leftType = $scope->getType($node->left); + if (!$this->helper->passesAsBoolean($scope, $originalNode->left)) { + $leftType = $scope->getType($originalNode->left); $messages[] = sprintf( 'Only booleans are allowed in ||, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) ); } - if (!$this->helper->passesAsBoolean($scope, $node->right)) { - $rightType = $scope->getType($node->right); + $rightScope = $node->getRightScope(); + if (!$this->helper->passesAsBoolean($rightScope, $originalNode->right)) { + $rightType = $rightScope->getType($originalNode->right); $messages[] = sprintf( 'Only booleans are allowed in ||, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) diff --git a/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php index 80c82a3b..4df87758 100644 --- a/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; +/** + * @extends \PHPStan\Testing\RuleTestCase + */ class BooleanInBooleanAndRuleTest extends \PHPStan\Testing\RuleTestCase { @@ -48,4 +51,14 @@ public function testRule(): void ]); } + public function testBug104(): void + { + $this->analyse([__DIR__ . '/data/bug-104.php'], [ + [ + 'Only booleans are allowed in &&, string given on the right side.', + 13, + ], + ]); + } + } diff --git a/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php index c4c1ddbe..3c8ccaf7 100644 --- a/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; +/** + * @extends \PHPStan\Testing\RuleTestCase + */ class BooleanInBooleanOrRuleTest extends \PHPStan\Testing\RuleTestCase { @@ -37,10 +40,6 @@ public function testRule(): void 'Only booleans are allowed in ||, string given on the left side.', 27, ], - [ - 'Only booleans are allowed in ||, string given on the right side.', - 27, - ], [ 'Only booleans are allowed in ||, mixed given on the right side.', 29, diff --git a/tests/Rules/BooleansInConditions/data/bug-104.php b/tests/Rules/BooleansInConditions/data/bug-104.php new file mode 100644 index 00000000..8bc5f249 --- /dev/null +++ b/tests/Rules/BooleansInConditions/data/bug-104.php @@ -0,0 +1,25 @@ +