Skip to content

Commit

Permalink
Add missing pre/post inc/dec type specifiers in conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
jlherren committed Nov 12, 2020
1 parent 591f963 commit ec48814
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -398,13 +398,19 @@ public function specifyTypesInCondition(
}

if ($leftType instanceof ConstantIntegerType) {
if ($expr->right instanceof Expr\PostDec) {
if ($expr->right instanceof Expr\PostInc) {
$result = $result->unionWith($this->createRangeTypes(
$expr->right->var,
IntegerRangeType::fromInterval($leftType->getValue(), null, $offset + 1),
$context
));
} elseif ($expr->right instanceof Expr\PostDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->right->var,
IntegerRangeType::fromInterval($leftType->getValue(), null, $offset - 1),
$context
));
} elseif ($expr->right instanceof Expr\PreDec) {
} elseif ($expr->right instanceof Expr\PreInc || $expr->right instanceof Expr\PreDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->right->var,
IntegerRangeType::fromInterval($leftType->getValue(), null, $offset),
Expand All @@ -426,7 +432,13 @@ public function specifyTypesInCondition(
IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset + 1),
$context
));
} elseif ($expr->left instanceof Expr\PreInc) {
} elseif ($expr->left instanceof Expr\PostDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->left->var,
IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset - 1),
$context
));
} elseif ($expr->left instanceof Expr\PreInc || $expr->left instanceof Expr\PreDec) {
$result = $result->unionWith($this->createRangeTypes(
$expr->left->var,
IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset),
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10342,6 +10342,11 @@ public function dataBug3880(): array
return $this->gatherAssertTypes(__DIR__ . '/data/bug-3880.php');
}

public function dataIncDecInConditions(): array
{
return $this->gatherAssertTypes(__DIR__ . '/data/inc-dec-in-conditions.php');
}

/**
* @param string $file
* @return array<string, mixed[]>
Expand Down Expand Up @@ -10523,6 +10528,7 @@ private function gatherAssertTypes(string $file): array
* @dataProvider dataBug1233
* @dataProvider dataComparisonOperators
* @dataProvider dataBug3880
* @dataProvider dataIncDecInConditions
* @param string $assertType
* @param string $file
* @param mixed ...$args
Expand Down
101 changes: 101 additions & 0 deletions tests/PHPStan/Analyser/data/inc-dec-in-conditions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace IncDecInConditions;

use function PHPStan\Analyser\assertType;

function incLeft(int $a, int $b, int $c, int $d): void
{
if (++$a < 0) {
assertType('int<min, -1>', $a);
} else {
assertType('int<0, max>', $a);
}
if (++$b <= 0) {
assertType('int<min, 0>', $b);
} else {
assertType('int<1, max>', $b);
}
if ($c++ < 0) {
assertType('int<min, 0>', $c);
} else {
assertType('int<1, max>', $c);
}
if ($d++ <= 0) {
assertType('int<min, 1>', $d);
} else {
assertType('int<2, max>', $d);
}
}

function incRight(int $a, int $b, int $c, int $d): void
{
if (0 < ++$a) {
assertType('int<1, max>', $a);
} else {
assertType('int<min, 0>', $a);
}
if (0 <= ++$b) {
assertType('int<0, max>', $b);
} else {
assertType('int<min, -1>', $b);
}
if (0 < $c++) {
assertType('int<2, max>', $c);
} else {
assertType('int<min, 1>', $c);
}
if (0 <= $d++) {
assertType('int<1, max>', $d);
} else {
assertType('int<min, 0>', $d);
}
}

function decLeft(int $a, int $b, int $c, int $d): void
{
if (--$a < 0) {
assertType('int<min, -1>', $a);
} else {
assertType('int<0, max>', $a);
}
if (--$b <= 0) {
assertType('int<min, 0>', $b);
} else {
assertType('int<1, max>', $b);
}
if ($c-- < 0) {
assertType('int<min, -2>', $c);
} else {
assertType('int<-1, max>', $c);
}
if ($d-- <= 0) {
assertType('int<min, -1>', $d);
} else {
assertType('int<0, max>', $d);
}
}

function decRight(int $a, int $b, int $c, int $d): void
{
if (0 < --$a) {
assertType('int<1, max>', $a);
} else {
assertType('int<min, 0>', $a);
}
if (0 <= --$b) {
assertType('int<0, max>', $b);
} else {
assertType('int<min, -1>', $b);
}
if (0 < $c--) {
assertType('int<0, max>', $c);
} else {
assertType('int<min, -1>', $c);
}
if (0 <= $d--) {
assertType('int<-1, max>', $d);
} else {
assertType('int<min, -2>', $d);
}
}

0 comments on commit ec48814

Please sign in to comment.