22
33namespace PHPStan \Rules \Comparison ;
44
5+ use PhpParser \Node \Expr \BinaryOp \BooleanAnd ;
6+ use PhpParser \Node \Expr \BinaryOp \LogicalAnd ;
7+ use PHPStan \Node \BooleanAndNode ;
58use PHPStan \Rules \RuleErrorBuilder ;
69use PHPStan \Type \Constant \ConstantBooleanType ;
710
811/**
9- * @implements \PHPStan\Rules\Rule<\PhpParser\Node\Expr\BinaryOp\BooleanAnd >
12+ * @implements \PHPStan\Rules\Rule<BooleanAndNode >
1013 */
1114class BooleanAndConstantConditionRule implements \PHPStan \Rules \Rule
1215{
@@ -15,18 +18,22 @@ class BooleanAndConstantConditionRule implements \PHPStan\Rules\Rule
1518
1619 private bool $ treatPhpDocTypesAsCertain ;
1720
21+ private bool $ checkLogicalAndConstantCondition ;
22+
1823 public function __construct (
1924 ConstantConditionRuleHelper $ helper ,
20- bool $ treatPhpDocTypesAsCertain
25+ bool $ treatPhpDocTypesAsCertain ,
26+ bool $ checkLogicalAndConstantCondition
2127 )
2228 {
2329 $ this ->helper = $ helper ;
2430 $ this ->treatPhpDocTypesAsCertain = $ treatPhpDocTypesAsCertain ;
31+ $ this ->checkLogicalAndConstantCondition = $ checkLogicalAndConstantCondition ;
2532 }
2633
2734 public function getNodeType (): string
2835 {
29- return \ PhpParser \ Node \ Expr \ BinaryOp \BooleanAnd ::class;
36+ return BooleanAndNode ::class;
3037 }
3138
3239 public function processNode (
@@ -35,15 +42,22 @@ public function processNode(
3542 ): array
3643 {
3744 $ 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 );
3953 $ 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%</>. ' ;
4054 if ($ leftType instanceof ConstantBooleanType) {
41- $ addTipLeft = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ node , $ tipText ): RuleErrorBuilder {
55+ $ addTipLeft = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ tipText , $ originalNode ): RuleErrorBuilder {
4256 if (!$ this ->treatPhpDocTypesAsCertain ) {
4357 return $ ruleErrorBuilder ;
4458 }
4559
46- $ booleanNativeType = $ this ->helper ->getNativeBooleanType ($ scope , $ node ->left );
60+ $ booleanNativeType = $ this ->helper ->getNativeBooleanType ($ scope , $ originalNode ->left );
4761 if ($ booleanNativeType instanceof ConstantBooleanType) {
4862 return $ ruleErrorBuilder ;
4963 }
@@ -53,22 +67,23 @@ public function processNode(
5367 $ errors [] = $ addTipLeft (RuleErrorBuilder::message (sprintf (
5468 'Left side of && is always %s. ' ,
5569 $ leftType ->getValue () ? 'true ' : 'false '
56- )))->line ($ node ->left ->getLine ())->build ();
70+ )))->line ($ originalNode ->left ->getLine ())->build ();
5771 }
5872
73+ $ rightScope = $ node ->getRightScope ();
5974 $ rightType = $ this ->helper ->getBooleanType (
60- $ scope -> filterByTruthyValue ( $ node -> left ) ,
61- $ node ->right
75+ $ rightScope ,
76+ $ originalNode ->right
6277 );
6378 if ($ rightType instanceof ConstantBooleanType) {
64- $ addTipRight = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ node , $ tipText ): RuleErrorBuilder {
79+ $ addTipRight = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ rightScope , $ originalNode , $ tipText ): RuleErrorBuilder {
6580 if (!$ this ->treatPhpDocTypesAsCertain ) {
6681 return $ ruleErrorBuilder ;
6782 }
6883
6984 $ booleanNativeType = $ this ->helper ->getNativeBooleanType (
70- $ scope ->doNotTreatPhpDocTypesAsCertain ()-> filterByTruthyValue ( $ node -> left ),
71- $ node ->right
85+ $ rightScope ->doNotTreatPhpDocTypesAsCertain (),
86+ $ originalNode ->right
7287 );
7388 if ($ booleanNativeType instanceof ConstantBooleanType) {
7489 return $ ruleErrorBuilder ;
@@ -79,18 +94,18 @@ public function processNode(
7994 $ errors [] = $ addTipRight (RuleErrorBuilder::message (sprintf (
8095 'Right side of && is always %s. ' ,
8196 $ rightType ->getValue () ? 'true ' : 'false '
82- )))->line ($ node ->right ->getLine ())->build ();
97+ )))->line ($ originalNode ->right ->getLine ())->build ();
8398 }
8499
85100 if (count ($ errors ) === 0 ) {
86- $ nodeType = $ scope ->getType ($ node );
101+ $ nodeType = $ scope ->getType ($ originalNode );
87102 if ($ nodeType instanceof ConstantBooleanType) {
88- $ addTip = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ node , $ tipText ): RuleErrorBuilder {
103+ $ addTip = function (RuleErrorBuilder $ ruleErrorBuilder ) use ($ scope , $ originalNode , $ tipText ): RuleErrorBuilder {
89104 if (!$ this ->treatPhpDocTypesAsCertain ) {
90105 return $ ruleErrorBuilder ;
91106 }
92107
93- $ booleanNativeType = $ scope ->doNotTreatPhpDocTypesAsCertain ()->getType ($ node );
108+ $ booleanNativeType = $ scope ->doNotTreatPhpDocTypesAsCertain ()->getType ($ originalNode );
94109 if ($ booleanNativeType instanceof ConstantBooleanType) {
95110 return $ ruleErrorBuilder ;
96111 }
0 commit comments