mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Merge pull request #10263 from robchett/maintain_loop_start_val_after_increment
Maintain loop start val after increment/decrement
This commit is contained in:
commit
7233f38805
@ -24,6 +24,8 @@ use Psalm\Issue\PossiblyInvalidOperand;
|
||||
use Psalm\Issue\PossiblyNullOperand;
|
||||
use Psalm\Issue\StringIncrement;
|
||||
use Psalm\IssueBuffer;
|
||||
use Psalm\Node\Expr\BinaryOp\VirtualMinus;
|
||||
use Psalm\Node\Expr\BinaryOp\VirtualPlus;
|
||||
use Psalm\StatementsSource;
|
||||
use Psalm\Type;
|
||||
use Psalm\Type\Atomic;
|
||||
@ -821,6 +823,28 @@ final class ArithmeticOpAnalyzer
|
||||
$result_type = Type::getInt();
|
||||
}
|
||||
}
|
||||
} elseif ($parent instanceof VirtualPlus || $parent instanceof VirtualMinus) {
|
||||
$sum = $parent instanceof VirtualPlus ? 1 : -1;
|
||||
if ($context && $context->inside_loop && $left_type_part instanceof TLiteralInt) {
|
||||
if ($parent instanceof VirtualPlus) {
|
||||
$new_type = new TIntRange($left_type_part->value + $sum, null);
|
||||
} else {
|
||||
$new_type = new TIntRange(null, $left_type_part->value + $sum);
|
||||
}
|
||||
} elseif ($left_type_part instanceof TLiteralInt) {
|
||||
$new_type = new TLiteralInt($left_type_part->value + $sum);
|
||||
} elseif ($left_type_part instanceof TIntRange) {
|
||||
$start = $left_type_part->min_bound === null ? null : $left_type_part->min_bound + $sum;
|
||||
$end = $left_type_part->max_bound === null ? null : $left_type_part->max_bound + $sum;
|
||||
$new_type = new TIntRange($start, $end);
|
||||
} else {
|
||||
$new_type = new TInt();
|
||||
}
|
||||
|
||||
$result_type = Type::combineUnionTypes(
|
||||
new Union([$new_type], ['from_calculation' => true]),
|
||||
$result_type,
|
||||
);
|
||||
} else {
|
||||
$result_type = Type::combineUnionTypes(
|
||||
$always_positive ? Type::getIntRange(1, null) : Type::getInt(true),
|
||||
|
@ -955,6 +955,40 @@ class BinaryOperationTest extends TestCase
|
||||
'$b' => 'float|int',
|
||||
],
|
||||
],
|
||||
'incrementInLoop' => [
|
||||
'code' => '<?php
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
if (rand(0,1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for ($j = 100; $j < 110; $j++) {
|
||||
if (rand(0,1)) {
|
||||
break;
|
||||
}
|
||||
}',
|
||||
'assertions' => [
|
||||
'$i' => 'int<0, 10>',
|
||||
'$j' => 'int<100, 110>',
|
||||
],
|
||||
],
|
||||
'decrementInLoop' => [
|
||||
'code' => '<?php
|
||||
for ($i = 10; $i > 0; $i--) {
|
||||
if (rand(0,1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for ($j = 110; $j > 100; $j--) {
|
||||
if (rand(0,1)) {
|
||||
break;
|
||||
}
|
||||
}',
|
||||
'assertions' => [
|
||||
'$i' => 'int<0, 10>',
|
||||
'$j' => 'int<100, 110>',
|
||||
],
|
||||
],
|
||||
'coalesceFilterOutNullEvenWithTernary' => [
|
||||
'code' => '<?php
|
||||
|
||||
|
@ -143,7 +143,7 @@ class ForTest extends TestCase
|
||||
* @param list<int> $arr
|
||||
*/
|
||||
function cartesianProduct(array $arr) : void {
|
||||
for ($i = 20; $arr[$i] === 5 && $i > 0; $i--) {}
|
||||
for ($i = 20; $i > 0 && $arr[$i] === 5 ; $i--) {}
|
||||
}',
|
||||
],
|
||||
'noCrashOnLongThing' => [
|
||||
|
@ -441,6 +441,64 @@ class RedundantConditionTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'allowIntValueCheckAfterComparisonDueToUnderflow' => [
|
||||
'code' => '<?php
|
||||
function foo(int $x) : void {
|
||||
$x = $x - 1;
|
||||
|
||||
if (!is_int($x)) {
|
||||
echo "Is a float.";
|
||||
} else {
|
||||
echo "Is an int.";
|
||||
}
|
||||
}
|
||||
|
||||
function bar(int $x) : void {
|
||||
$x = $x - 1;
|
||||
|
||||
if (is_float($x)) {
|
||||
echo "Is a float.";
|
||||
} else {
|
||||
echo "Is an int.";
|
||||
}
|
||||
}',
|
||||
],
|
||||
'allowIntValueCheckAfterComparisonDueToUnderflowDec' => [
|
||||
'code' => '<?php
|
||||
function foo(int $x) : void {
|
||||
$x--;
|
||||
|
||||
if (!is_int($x)) {
|
||||
echo "Is a float.";
|
||||
} else {
|
||||
echo "Is an int.";
|
||||
}
|
||||
}
|
||||
|
||||
function bar(int $x) : void {
|
||||
$x--;
|
||||
|
||||
if (is_float($x)) {
|
||||
echo "Is a float.";
|
||||
} else {
|
||||
echo "Is an int.";
|
||||
}
|
||||
}',
|
||||
],
|
||||
'allowIntValueCheckAfterComparisonDueToConditionalUnderflow' => [
|
||||
'code' => '<?php
|
||||
function foo(int $x) : void {
|
||||
if (rand(0, 1)) {
|
||||
$x = $x - 1;
|
||||
}
|
||||
|
||||
if (is_float($x)) {
|
||||
echo "Is a float.";
|
||||
} else {
|
||||
echo "Is an int.";
|
||||
}
|
||||
}',
|
||||
],
|
||||
'changeStringValue' => [
|
||||
'code' => '<?php
|
||||
$concat = "";
|
||||
|
Loading…
x
Reference in New Issue
Block a user