diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php index c26fa7ca6ef..83d11e83b48 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/NonDivArithmeticOpAnalyzer.php @@ -663,7 +663,15 @@ private static function analyzeNonDivOperands( if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Minus) { $always_positive = false; } elseif ($left_is_positive && $right_is_positive) { - $always_positive = true; + if ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor + || $parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd + || $parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft + || $parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight + ) { + $always_positive = false; + } else { + $always_positive = true; + } } elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus && ($left_type_part instanceof TLiteralInt && $left_type_part->value === 0) && $right_is_positive diff --git a/tests/BinaryOperationTest.php b/tests/BinaryOperationTest.php index cb898886f7d..d46ef20f1f7 100644 --- a/tests/BinaryOperationTest.php +++ b/tests/BinaryOperationTest.php @@ -357,6 +357,37 @@ function onlyZeroOrPlusMinusOne(int $i): int { function foo($a, $b): void { onlyZeroOrPlusMinusOne($a <=> $b); }' + ], + 'notAlwaysPositiveBitOperations' => [ + '> $b)) { + echo "Actually, zero\n"; + } + + if (8 === PHP_INT_SIZE) { + if (0 === ($a << $d)) { + echo "Actually, zero\n"; + } + } else { + if (0 === ($a << $c)) { + echo "Actually, zero\n"; + } + }' ] ]; }