mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
added array-size max constraint to greater check (#4175)
added a few unit tests
This commit is contained in:
parent
5d04368d98
commit
c361f86c68
@ -247,6 +247,8 @@ class AssertionFinder
|
||||
$count_equality_position = self::hasNonEmptyCountEqualityCheck($conditional, $min_count);
|
||||
$min_comparison = null;
|
||||
$positive_number_position = self::hasPositiveNumberCheck($conditional, $min_comparison);
|
||||
$max_count = null;
|
||||
$count_inequality_position = self::hasLessThanCountEqualityCheck($conditional, $max_count);
|
||||
|
||||
if ($count_equality_position) {
|
||||
if ($count_equality_position === self::ASSIGNMENT_TO_RIGHT) {
|
||||
@ -277,6 +279,31 @@ class AssertionFinder
|
||||
return $if_types;
|
||||
}
|
||||
|
||||
if ($count_inequality_position) {
|
||||
if ($count_inequality_position === self::ASSIGNMENT_TO_LEFT) {
|
||||
$count_expr = $conditional->right;
|
||||
} else {
|
||||
throw new \UnexpectedValueException('$count_inequality_position value');
|
||||
}
|
||||
|
||||
/** @var PhpParser\Node\Expr\FuncCall $count_expr */
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
$count_expr->args[0]->value,
|
||||
$this_class_name,
|
||||
$source
|
||||
);
|
||||
|
||||
if ($var_name) {
|
||||
if ($max_count) {
|
||||
$if_types[$var_name] = [['!has-at-least-' . ($max_count + 1)]];
|
||||
} else {
|
||||
$if_types[$var_name] = [['!non-empty-countable']];
|
||||
}
|
||||
}
|
||||
|
||||
return $if_types;
|
||||
}
|
||||
|
||||
if ($positive_number_position) {
|
||||
if ($positive_number_position === self::ASSIGNMENT_TO_RIGHT) {
|
||||
$var_name = ExpressionIdentifier::getArrayVarId(
|
||||
@ -2755,16 +2782,13 @@ class AssertionFinder
|
||||
&& strtolower($conditional->left->name->parts[0]) === 'count'
|
||||
&& $conditional->left->args;
|
||||
|
||||
$operator_greater_than_or_equal =
|
||||
$operator_less_than_or_equal =
|
||||
$conditional instanceof PhpParser\Node\Expr\BinaryOp\SmallerOrEqual
|
||||
|| $conditional instanceof PhpParser\Node\Expr\BinaryOp\Smaller;
|
||||
|
||||
if ($left_count
|
||||
&& $conditional->right instanceof PhpParser\Node\Scalar\LNumber
|
||||
&& $operator_greater_than_or_equal
|
||||
&& $conditional->right->value >= (
|
||||
$conditional instanceof PhpParser\Node\Expr\BinaryOp\Smaller ? 0 : 1
|
||||
)
|
||||
&& $operator_less_than_or_equal
|
||||
) {
|
||||
$max_count = $conditional->right->value -
|
||||
($conditional instanceof PhpParser\Node\Expr\BinaryOp\Smaller ? 1 : 0);
|
||||
@ -2777,16 +2801,13 @@ class AssertionFinder
|
||||
&& strtolower($conditional->right->name->parts[0]) === 'count'
|
||||
&& $conditional->right->args;
|
||||
|
||||
$operator_less_than_or_equal =
|
||||
$operator_greater_than_or_equal =
|
||||
$conditional instanceof PhpParser\Node\Expr\BinaryOp\GreaterOrEqual
|
||||
|| $conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater;
|
||||
|
||||
if ($right_count
|
||||
&& $conditional->left instanceof PhpParser\Node\Scalar\LNumber
|
||||
&& $operator_less_than_or_equal
|
||||
&& $conditional->left->value >= (
|
||||
$conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater ? 0 : 1
|
||||
)
|
||||
&& $operator_greater_than_or_equal
|
||||
) {
|
||||
$max_count = $conditional->left->value -
|
||||
($conditional instanceof PhpParser\Node\Expr\BinaryOp\Greater ? 1 : 0);
|
||||
|
@ -419,15 +419,110 @@ class ArrayFunctionCallTest extends TestCase
|
||||
'$b' => 'int',
|
||||
],
|
||||
],
|
||||
'arrayPopNonEmptyAfterCountLessThanEqualToOne' => [
|
||||
'arrayNotEmptyArrayAfterCountLessThanEqualToOne' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$a = [1, 2, 3];
|
||||
$b = 5;
|
||||
if (count($a) <= 1) {
|
||||
echo $a[0];
|
||||
$leftCount = [1, 2, 3];
|
||||
if (count($leftCount) <= 1) {
|
||||
echo $leftCount[0];
|
||||
}
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
if (1 >= count($rightCount)) {
|
||||
echo $rightCount[0];
|
||||
}',
|
||||
],
|
||||
'arrayNotEmptyArrayAfterCountLessThanTwo' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$leftCount = [1, 2, 3];
|
||||
if (count($leftCount) < 2) {
|
||||
echo $leftCount[0];
|
||||
}
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
if (2 > count($rightCount)) {
|
||||
echo $rightCount[0];
|
||||
}',
|
||||
],
|
||||
'arrayEmptyArrayAfterCountLessThanOne' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$leftCount = [1, 2, 3];
|
||||
assert (count($leftCount) < 1);
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
assert (1 > count($rightCount));',
|
||||
'assertions' => [
|
||||
'$leftCount' => 'array<empty, empty>',
|
||||
'$rightCount' => 'array<empty, empty>',
|
||||
],
|
||||
],
|
||||
'arrayEmptyArrayAfterCountLessThanEqualToZero' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$leftCount = [1, 2, 3];
|
||||
assert (count($leftCount) <= 0);
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
assert (0 >= count($rightCount));',
|
||||
'assertions' => [
|
||||
'$leftCount' => 'array<empty, empty>',
|
||||
'$rightCount' => 'array<empty, empty>',
|
||||
],
|
||||
],
|
||||
'arrayNotNonEmptyArrayAfterCountGreaterThanEqualToZero' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$leftCount = [1, 2, 3];
|
||||
assert(count($leftCount) >= 0);
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
assert(0 <= count($rightCount));',
|
||||
'assertions' => [
|
||||
'$leftCount' => 'list<int>',
|
||||
'$rightCount' => 'list<int>',
|
||||
],
|
||||
],
|
||||
'arrayNotNonEmptyArrayAfterCountGreaterThanMinusOne' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$leftCount = [1, 2, 3];
|
||||
assert (count($leftCount) > -1);
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
assert (-1 < count($rightCount));',
|
||||
'assertions' => [
|
||||
'$leftCount' => 'list<int>',
|
||||
'$rightCount' => 'list<int>',
|
||||
],
|
||||
],
|
||||
'arrayNonEmptyArrayAfterCountGreaterThanEqualToOne' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$leftCount = [1, 2, 3];
|
||||
assert(count($leftCount) >= 1);
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
assert(1 <= count($rightCount));',
|
||||
'assertions' => [
|
||||
'$leftCount' => 'non-empty-list<int>',
|
||||
'$rightCount' => 'non-empty-list<int>',
|
||||
],
|
||||
],
|
||||
'arrayNonEmptyArrayAfterCountGreaterThanZero' => [
|
||||
'<?php
|
||||
/** @var list<int> */
|
||||
$leftCount = [1, 2, 3];
|
||||
assert (count($leftCount) > 0);
|
||||
/** @var list<int> */
|
||||
$rightCount = [1, 2, 3];
|
||||
assert (0 < count($rightCount));',
|
||||
'assertions' => [
|
||||
'$leftCount' => 'non-empty-list<int>',
|
||||
'$rightCount' => 'non-empty-list<int>',
|
||||
],
|
||||
],
|
||||
'arrayPopNonEmptyAfterArrayAddition' => [
|
||||
'<?php
|
||||
/** @var array<string, int> */
|
||||
|
Loading…
Reference in New Issue
Block a user