Skip to content

Commit

Permalink
Fix wrong scope in BooleanInBooleanAndRule and BooleanInBooleanOrRule
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jan 11, 2021
1 parent fb24448 commit f820776
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 65 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
40 changes: 0 additions & 40 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -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\\<PhpParser\\\\Node\\>\\:\\: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
Expand All @@ -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\\<PhpParser\\\\Node\\>\\:\\: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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
26 changes: 16 additions & 10 deletions src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<BooleanAndNode>
*/
class BooleanInBooleanAndRule implements \PHPStan\Rules\Rule
{

Expand All @@ -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())
Expand Down
26 changes: 16 additions & 10 deletions src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<BooleanOrNode>
*/
class BooleanInBooleanOrRule implements \PHPStan\Rules\Rule
{

Expand All @@ -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())
Expand Down
13 changes: 13 additions & 0 deletions tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleLevelHelper;

/**
* @extends \PHPStan\Testing\RuleTestCase<BooleanInBooleanAndRule>
*/
class BooleanInBooleanAndRuleTest extends \PHPStan\Testing\RuleTestCase
{

Expand Down Expand Up @@ -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,
],
]);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleLevelHelper;

/**
* @extends \PHPStan\Testing\RuleTestCase<BooleanInBooleanOrRule>
*/
class BooleanInBooleanOrRuleTest extends \PHPStan\Testing\RuleTestCase
{

Expand Down Expand Up @@ -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,
Expand Down
25 changes: 25 additions & 0 deletions tests/Rules/BooleansInConditions/data/bug-104.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Bug104;

class Foo
{

public function foo(?string $bar): void
{
if ($bar !== null && strpos($bar, 'bar') === 0) {
echo 'strpos works';
}
if ($bar !== null && $bar) {
echo 'string as boolean does not';
}
}

public function bar(?bool $bar): void
{
if ($bar !== null && $bar) {
echo 'foo';
}
}

}

0 comments on commit f820776

Please sign in to comment.