Skip to content

Commit

Permalink
Do arithmetic for preg_split arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Oct 13, 2020
1 parent a6c73a9 commit 8f21179
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,48 @@ private static function analyzeNonDivOperands(
bool &$has_string_increment,
Type\Union &$result_type = null
): ?Type\Union {
if ($left_type_part instanceof TLiteralInt
&& $right_type_part instanceof TLiteralInt
&& ($left instanceof PhpParser\Node\Scalar || $left instanceof PhpParser\Node\Expr\ConstFetch)
&& ($right instanceof PhpParser\Node\Scalar || $right instanceof PhpParser\Node\Expr\ConstFetch)
) {
// time for some arithmetic!

$calculated_type = null;

if ($parent instanceof PhpParser\Node\Expr\BinaryOp\Plus) {
$calculated_type = Type::getInt(false, $left_type_part->value + $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Minus) {
$calculated_type = Type::getInt(false, $left_type_part->value - $right_type_part->value);
} elseif ($parent instanceof PhpParser\Node\Expr\BinaryOp\Mod) {
$calculated_type = Type::getInt(false, $left_type_part->value % $right_type_part->value);
} 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);
} 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);
}

if ($calculated_type) {
if ($result_type) {
$result_type = Type::combineUnionTypes(
$calculated_type,
$result_type
);
} else {
$result_type = $calculated_type;
}

$has_valid_left_operand = true;
$has_valid_right_operand = true;

return null;
}
}

if ($left_type_part instanceof TNull || $right_type_part instanceof TNull) {
// null case is handled above
return null;
Expand Down
6 changes: 5 additions & 1 deletion stubs/CoreGenericFunctions.phpstub
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,11 @@ function explode(string $delimiter, string $string, int $limit = -1) : array {}
*
* @psalm-flow ($subject) -(array-assignment)-> return
*
* @return ($flags is 0 ? non-empty-list<string>|false : list<string>|list<list<string|int>>|false)
* @template TFlags as 0|1|2|3|4|5|6|7
*
* @param TFlags $flags
*
* @return (TFlags is 0|2 ? non-empty-list<string>|false : (TFlags is 1|3 ? list<string>|false : list<array{string,int}>|false))
*
* @psalm-ignore-falsable-return
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/BinaryOperationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public function providerValidCodeParse(): iterable
$c = 25 % 2.5;
$d = 25.5 % 2.5;',
'assertions' => [
'$a' => 'int|int',
'$a' => 'int',
'$b' => 'int',
'$c' => 'int',
'$d' => 'int',
Expand Down
7 changes: 7 additions & 0 deletions tests/FunctionCallTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,13 @@ function foo(string $s) {
return preg_split("/ /", $s);
}'
],
'pregSplitWithFlags' => [
'<?php
/** @return list<string> */
function foo(string $s) {
return preg_split("/ /", $s, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
}'
],
'mbConvertEncodingWithArray' => [
'<?php
/**
Expand Down
2 changes: 1 addition & 1 deletion tests/TypeReconciliation/TypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ public function fooFoo() {}
class B {
/** @return void */
public function barBar(One $one = null, Two $two = null) {
if ($one !== null && ($two || 1 + 1 === 3)) {
if ($one !== null && ($two || rand(0, 1))) {
$one->fooFoo();
}
}
Expand Down

0 comments on commit 8f21179

Please sign in to comment.