mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
support shift and bitwise operations in constants (#4740)
This commit is contained in:
parent
08d9246b9a
commit
5f9aff5734
@ -43,13 +43,11 @@ class NonComparisonOpAnalyzer
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mod
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mul
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Pow
|
||||
|| (($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight
|
||||
)
|
||||
)
|
||||
) {
|
||||
NonDivArithmeticOpAnalyzer::analyze(
|
||||
$statements_analyzer,
|
||||
|
@ -313,11 +313,17 @@ class NonDivArithmeticOpAnalyzer
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mul) {
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value * $right_type_part->value);
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Pow) {
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value ^ $right_type_part->value);
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value ** $right_type_part->value);
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr) {
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value | $right_type_part->value);
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd) {
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value & $right_type_part->value);
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor) {
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value ^ $right_type_part->value);
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft) {
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value << $right_type_part->value);
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight) {
|
||||
$calculated_type = Type::getInt(false, $left_type_part->value >> $right_type_part->value);
|
||||
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Div) {
|
||||
$value = $left_type_part->value / $right_type_part->value;
|
||||
|
||||
|
@ -13,6 +13,9 @@ use function count;
|
||||
use function array_shift;
|
||||
use function reset;
|
||||
|
||||
/**
|
||||
* This class takes a statement and return its type by analyzing each part of the statement if necessary
|
||||
*/
|
||||
class SimpleTypeInferer
|
||||
{
|
||||
/**
|
||||
@ -148,6 +151,11 @@ class SimpleTypeInferer
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mod
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Mul
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Pow
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftRight
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\ShiftLeft
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr
|
||||
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd
|
||||
) {
|
||||
NonDivArithmeticOpAnalyzer::analyze(
|
||||
$file_source instanceof StatementsSource ? $file_source : null,
|
||||
|
@ -58,6 +58,8 @@ class ConstantTypeResolver
|
||||
|| $c instanceof UnresolvedConstant\UnresolvedDivisionOp
|
||||
|| $c instanceof UnresolvedConstant\UnresolvedMultiplicationOp
|
||||
|| $c instanceof UnresolvedConstant\UnresolvedBitwiseOr
|
||||
|| $c instanceof UnresolvedConstant\UnresolvedBitwiseXor
|
||||
|| $c instanceof UnresolvedConstant\UnresolvedBitwiseAnd
|
||||
) {
|
||||
if (($left instanceof Type\Atomic\TLiteralFloat || $left instanceof Type\Atomic\TLiteralInt)
|
||||
&& ($right instanceof Type\Atomic\TLiteralFloat || $right instanceof Type\Atomic\TLiteralInt)
|
||||
@ -78,6 +80,14 @@ class ConstantTypeResolver
|
||||
return self::getLiteralTypeFromScalarValue($left->value | $right->value);
|
||||
}
|
||||
|
||||
if ($c instanceof UnresolvedConstant\UnresolvedBitwiseXor) {
|
||||
return self::getLiteralTypeFromScalarValue($left->value ^ $right->value);
|
||||
}
|
||||
|
||||
if ($c instanceof UnresolvedConstant\UnresolvedBitwiseAnd) {
|
||||
return self::getLiteralTypeFromScalarValue($left->value & $right->value);
|
||||
}
|
||||
|
||||
return self::getLiteralTypeFromScalarValue($left->value * $right->value);
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,14 @@ class ExpressionResolver
|
||||
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseOr) {
|
||||
return new UnresolvedConstant\UnresolvedBitwiseOr($left, $right);
|
||||
}
|
||||
|
||||
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseXor) {
|
||||
return new UnresolvedConstant\UnresolvedBitwiseXor($left, $right);
|
||||
}
|
||||
|
||||
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp\BitwiseAnd) {
|
||||
return new UnresolvedConstant\UnresolvedBitwiseAnd($left, $right);
|
||||
}
|
||||
}
|
||||
|
||||
if ($stmt instanceof PhpParser\Node\Expr\Ternary) {
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Internal\Scanner\UnresolvedConstant;
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
class UnresolvedBitwiseAnd extends UnresolvedBinaryOp
|
||||
{
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Internal\Scanner\UnresolvedConstant;
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
class UnresolvedBitwiseXor extends UnresolvedBinaryOp
|
||||
{
|
||||
}
|
@ -174,9 +174,9 @@ class BinaryOperationTest extends TestCase
|
||||
'assertions' => [
|
||||
'$a' => 'int',
|
||||
'$b' => 'int',
|
||||
'$c' => 'positive-int',
|
||||
'$d' => 'positive-int',
|
||||
'$e' => 'positive-int',
|
||||
'$c' => 'int',
|
||||
'$d' => 'int',
|
||||
'$e' => 'int',
|
||||
'$f' => 'string',
|
||||
],
|
||||
],
|
||||
@ -187,8 +187,8 @@ class BinaryOperationTest extends TestCase
|
||||
$c = (true xor false);
|
||||
$d = (false xor false);',
|
||||
'assertions' => [
|
||||
'$a' => 'positive-int',
|
||||
'$b' => 'positive-int',
|
||||
'$a' => 'int',
|
||||
'$b' => 'int',
|
||||
'$c' => 'bool',
|
||||
'$d' => 'bool',
|
||||
],
|
||||
@ -216,11 +216,9 @@ class BinaryOperationTest extends TestCase
|
||||
],
|
||||
'exponent' => [
|
||||
'<?php
|
||||
$a = "x" ^ "y";
|
||||
$b = 4 ^ 5;',
|
||||
$b = 4 ** 5;',
|
||||
'assertions' => [
|
||||
'$a' => 'string',
|
||||
'$b' => 'positive-int',
|
||||
'$b' => 'int',
|
||||
],
|
||||
],
|
||||
'bitwiseNot' => [
|
||||
|
@ -27,6 +27,11 @@ class Php56Test extends TestCase
|
||||
const THREE = self::TWO + 1;
|
||||
const ONE_THIRD = self::ONE / self::THREE;
|
||||
const SENTENCE = "The value of THREE is " . self::THREE;
|
||||
const SHIFT = self::ONE >> 2;
|
||||
const SHIFT2 = self::ONE << 1;
|
||||
const BITAND = 1 & 1;
|
||||
const BITOR = 1 | 1;
|
||||
const BITXOR = 1 ^ 1;
|
||||
|
||||
/** @var int */
|
||||
public $four = self::ONE + self::THREE;
|
||||
@ -46,7 +51,12 @@ class Php56Test extends TestCase
|
||||
$c1_3rd = C::ONE_THIRD;
|
||||
$c_sentence = C::SENTENCE;
|
||||
$cf = (new C)->f();
|
||||
$c4 = (new C)->four;',
|
||||
$c4 = (new C)->four;
|
||||
$shift = C::SHIFT;
|
||||
$shift2 = C::SHIFT2;
|
||||
$bitand = C::BITAND;
|
||||
$bitor = C::BITOR;
|
||||
$bitxor = C::BITXOR;',
|
||||
'assertions' => [
|
||||
'$c1' => 'int',
|
||||
'$c2===' => 'int(2)',
|
||||
@ -55,18 +65,32 @@ class Php56Test extends TestCase
|
||||
'$c_sentence' => 'string',
|
||||
'$cf' => 'int',
|
||||
'$c4' => 'int',
|
||||
'$shift' => 'int',
|
||||
'$shift2' => 'int',
|
||||
'$bitand' => 'int',
|
||||
'$bitor' => 'int',
|
||||
'$bitxor' => 'int',
|
||||
],
|
||||
],
|
||||
'constFeatures' => [
|
||||
'<?php
|
||||
const ONE = 1;
|
||||
const TWO = ONE * 2;
|
||||
const BITWISE = ONE & 2;
|
||||
const SHIFT = ONE << 2;
|
||||
const SHIFT2 = PHP_INT_MAX << 1;
|
||||
|
||||
$one = ONE;
|
||||
$two = TWO;',
|
||||
$two = TWO;
|
||||
$bitwise = BITWISE;
|
||||
$shift = SHIFT;
|
||||
$shift2 = SHIFT2;',
|
||||
'assertions' => [
|
||||
'$one' => 'int',
|
||||
'$two' => 'int',
|
||||
'$bitwise' => 'int',
|
||||
'$shift' => 'int',
|
||||
'$shift2' => 'int',
|
||||
],
|
||||
],
|
||||
'exponentiation' => [
|
||||
|
Loading…
x
Reference in New Issue
Block a user