2
2
3
3
namespace PHPStan \Rules \Comparison ;
4
4
5
+ use PhpParser \Node \Expr \BinaryOp \BooleanAnd ;
6
+ use PhpParser \Node \Expr \BinaryOp \LogicalAnd ;
7
+ use PHPStan \Node \BooleanAndNode ;
5
8
use PHPStan \Rules \RuleErrorBuilder ;
6
9
use PHPStan \Type \Constant \ConstantBooleanType ;
7
10
8
11
/**
9
- * @implements \PHPStan\Rules\Rule<\PhpParser\Node\Expr\BinaryOp\BooleanAnd >
12
+ * @implements \PHPStan\Rules\Rule<BooleanAndNode >
10
13
*/
11
14
class BooleanAndConstantConditionRule implements \PHPStan \Rules \Rule
12
15
{
@@ -15,18 +18,22 @@ class BooleanAndConstantConditionRule implements \PHPStan\Rules\Rule
15
18
16
19
private bool $ treatPhpDocTypesAsCertain ;
17
20
21
+ private bool $ checkLogicalAndConstantCondition ;
22
+
18
23
public function __construct (
19
24
ConstantConditionRuleHelper $ helper ,
20
- bool $ treatPhpDocTypesAsCertain
25
+ bool $ treatPhpDocTypesAsCertain ,
26
+ bool $ checkLogicalAndConstantCondition
21
27
)
22
28
{
23
29
$ this ->helper = $ helper ;
24
30
$ this ->treatPhpDocTypesAsCertain = $ treatPhpDocTypesAsCertain ;
31
+ $ this ->checkLogicalAndConstantCondition = $ checkLogicalAndConstantCondition ;
25
32
}
26
33
27
34
public function getNodeType (): string
28
35
{
29
- return \ PhpParser \ Node \ Expr \ BinaryOp \BooleanAnd ::class;
36
+ return BooleanAndNode ::class;
30
37
}
31
38
32
39
public function processNode (
@@ -35,15 +42,22 @@ public function processNode(
35
42
): array
36
43
{
37
44
$ errors = [];
38
- $ leftType = $ this ->helper ->getBooleanType ($ scope , $ node ->left );
45
+
46
+ /** @var BooleanAnd|LogicalAnd $originalNode */
47
+ $ originalNode = $ node ->getOriginalNode ();
48
+ if (!$ originalNode instanceof BooleanAnd && !$ this ->checkLogicalAndConstantCondition ) {
49
+ return [];
50
+ }
51
+
52
+ $ leftType = $ this ->helper ->getBooleanType ($ scope , $ originalNode ->left );
39
53
$ tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>. ' ;
40
54
if ($ leftType instanceof ConstantBooleanType) {
41
- $ addTipLeft = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ node , $ tipText ): RuleErrorBuilder {
55
+ $ addTipLeft = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ tipText , $ originalNode ): RuleErrorBuilder {
42
56
if (!$ this ->treatPhpDocTypesAsCertain ) {
43
57
return $ ruleErrorBuilder ;
44
58
}
45
59
46
- $ booleanNativeType = $ this ->helper ->getNativeBooleanType ($ scope , $ node ->left );
60
+ $ booleanNativeType = $ this ->helper ->getNativeBooleanType ($ scope , $ originalNode ->left );
47
61
if ($ booleanNativeType instanceof ConstantBooleanType) {
48
62
return $ ruleErrorBuilder ;
49
63
}
@@ -53,22 +67,23 @@ public function processNode(
53
67
$ errors [] = $ addTipLeft (RuleErrorBuilder::message (sprintf (
54
68
'Left side of && is always %s. ' ,
55
69
$ leftType ->getValue () ? 'true ' : 'false '
56
- )))->line ($ node ->left ->getLine ())->build ();
70
+ )))->line ($ originalNode ->left ->getLine ())->build ();
57
71
}
58
72
73
+ $ rightScope = $ node ->getRightScope ();
59
74
$ rightType = $ this ->helper ->getBooleanType (
60
- $ scope -> filterByTruthyValue ( $ node -> left ) ,
61
- $ node ->right
75
+ $ rightScope ,
76
+ $ originalNode ->right
62
77
);
63
78
if ($ rightType instanceof ConstantBooleanType) {
64
- $ addTipRight = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ node , $ tipText ): RuleErrorBuilder {
79
+ $ addTipRight = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ rightScope , $ originalNode , $ tipText ): RuleErrorBuilder {
65
80
if (!$ this ->treatPhpDocTypesAsCertain ) {
66
81
return $ ruleErrorBuilder ;
67
82
}
68
83
69
84
$ booleanNativeType = $ this ->helper ->getNativeBooleanType (
70
- $ scope ->doNotTreatPhpDocTypesAsCertain ()-> filterByTruthyValue ( $ node -> left ),
71
- $ node ->right
85
+ $ rightScope ->doNotTreatPhpDocTypesAsCertain (),
86
+ $ originalNode ->right
72
87
);
73
88
if ($ booleanNativeType instanceof ConstantBooleanType) {
74
89
return $ ruleErrorBuilder ;
@@ -79,18 +94,18 @@ public function processNode(
79
94
$ errors [] = $ addTipRight (RuleErrorBuilder::message (sprintf (
80
95
'Right side of && is always %s. ' ,
81
96
$ rightType ->getValue () ? 'true ' : 'false '
82
- )))->line ($ node ->right ->getLine ())->build ();
97
+ )))->line ($ originalNode ->right ->getLine ())->build ();
83
98
}
84
99
85
100
if (count ($ errors ) === 0 ) {
86
- $ nodeType = $ scope ->getType ($ node );
101
+ $ nodeType = $ scope ->getType ($ originalNode );
87
102
if ($ nodeType instanceof ConstantBooleanType) {
88
- $ addTip = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ node , $ tipText ): RuleErrorBuilder {
103
+ $ addTip = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ originalNode , $ tipText ): RuleErrorBuilder {
89
104
if (!$ this ->treatPhpDocTypesAsCertain ) {
90
105
return $ ruleErrorBuilder ;
91
106
}
92
107
93
- $ booleanNativeType = $ scope ->doNotTreatPhpDocTypesAsCertain ()->getType ($ node );
108
+ $ booleanNativeType = $ scope ->doNotTreatPhpDocTypesAsCertain ()->getType ($ originalNode );
94
109
if ($ booleanNativeType instanceof ConstantBooleanType) {
95
110
return $ ruleErrorBuilder ;
96
111
}
0 commit comments