1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Do arithmetic for preg_split arguments

This commit is contained in:
Matt Brown 2020-10-12 20:25:46 -04:00 committed by Daniil Gentili
parent e999728892
commit 278a306681
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
5 changed files with 56 additions and 3 deletions

View File

@ -288,6 +288,48 @@ class NonDivArithmeticOpAnalyzer
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;

View File

@ -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
*/

View File

@ -133,7 +133,7 @@ class BinaryOperationTest extends TestCase
$c = 25 % 2.5;
$d = 25.5 % 2.5;',
'assertions' => [
'$a' => 'int|int',
'$a' => 'int',
'$b' => 'int',
'$c' => 'int',
'$d' => 'int',

View File

@ -1362,6 +1362,13 @@ class FunctionCallTest extends TestCase
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
/**

View File

@ -242,7 +242,7 @@ class TypeTest extends \Psalm\Tests\TestCase
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();
}
}