Skip to content

Commit a78a2e7

Browse files
committed
All count functions and methods return 0 or positive-int
1 parent 6784a1c commit a78a2e7

File tree

9 files changed

+99
-69
lines changed

9 files changed

+99
-69
lines changed

resources/functionMap.php

+47-47
Large diffs are not rendered by default.

src/Reflection/Php/PhpClassReflectionExtension.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ private function inferAndCachePropertyTypes(
769769

770770
$classNameParts = explode('\\', $declaringClass->getName());
771771
$namespace = null;
772-
if (count($classNameParts) > 0) {
772+
if (count($classNameParts) > 1) {
773773
$namespace = implode('\\', array_slice($classNameParts, 0, -1));
774774
}
775775

src/Rules/Whitespace/FileWhitespaceRule.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,7 @@ public function getLastNodes(): array
7474
$nodeTraverser->traverse($nodes);
7575

7676
$lastNodes = $visitor->getLastNodes();
77-
if (count($nodes) > 0) {
78-
$lastNodes[] = $nodes[count($nodes) - 1];
79-
}
77+
$lastNodes[] = $nodes[count($nodes) - 1];
8078
foreach ($lastNodes as $lastNode) {
8179
if (!$lastNode instanceof Node\Stmt\InlineHTML || Strings::match($lastNode->value, '#^(\s+)$#') === null) {
8280
continue;

src/Type/ArrayType.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ public function toArray(): Type
276276

277277
public function count(): Type
278278
{
279-
return new IntegerType();
279+
return IntegerRangeType::fromInterval(0, null);
280280
}
281281

282282
public static function castToArrayKeyType(Type $offsetType): Type

src/Type/Php/CountFunctionReturnTypeExtension.php

+9-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PHPStan\Reflection\FunctionReflection;
88
use PHPStan\Reflection\ParametersAcceptorSelector;
99
use PHPStan\Type\Constant\ConstantIntegerType;
10+
use PHPStan\Type\IntegerRangeType;
1011
use PHPStan\Type\Type;
1112
use PHPStan\Type\TypeCombinator;
1213
use PHPStan\Type\TypeUtils;
@@ -36,12 +37,17 @@ public function getTypeFromFunctionCall(
3637
}
3738
}
3839

39-
$arrays = TypeUtils::getArrays($scope->getType($functionCall->args[0]->value));
40-
if (count($arrays) === 0) {
40+
$argType = $scope->getType($functionCall->args[0]->value);
41+
$constantArrays = TypeUtils::getConstantArrays($scope->getType($functionCall->args[0]->value));
42+
if (count($constantArrays) === 0) {
43+
if ($argType->isIterableAtLeastOnce()->yes()) {
44+
return IntegerRangeType::fromInterval(1, null);
45+
}
46+
4147
return ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
4248
}
4349
$countTypes = [];
44-
foreach ($arrays as $array) {
50+
foreach ($constantArrays as $array) {
4551
$countTypes[] = $array->count();
4652
}
4753

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+9-3
Original file line numberDiff line numberDiff line change
@@ -2530,7 +2530,7 @@ public function dataBinaryOperations(): array
25302530
'count($arrayOfIntegers)',
25312531
],
25322532
[
2533-
'int',
2533+
'int<0, max>',
25342534
'count($arrayOfIntegers, \COUNT_RECURSIVE)',
25352535
],
25362536
[
@@ -2802,11 +2802,11 @@ public function dataBinaryOperations(): array
28022802
'count($array)',
28032803
],
28042804
[
2805-
'int',
2805+
'int<0, max>',
28062806
'count()',
28072807
],
28082808
[
2809-
'int',
2809+
'int<0, max>',
28102810
'count($appendingToArrayInBranches)',
28112811
],
28122812
[
@@ -10204,6 +10204,11 @@ public function dataExtraIntTypes(): array
1020410204
return $this->gatherAssertTypes(__DIR__ . '/data/extra-int-types.php');
1020510205
}
1020610206

10207+
public function dataCount(): array
10208+
{
10209+
return $this->gatherAssertTypes(__DIR__ . '/data/count-type.php');
10210+
}
10211+
1020710212
/**
1020810213
* @dataProvider dataBug2574
1020910214
* @dataProvider dataBug2577
@@ -10287,6 +10292,7 @@ public function dataExtraIntTypes(): array
1028710292
* @dataProvider dataBug3961
1028810293
* @dataProvider dataBug1924
1028910294
* @dataProvider dataExtraIntTypes
10295+
* @dataProvider dataCount
1029010296
* @param string $assertType
1029110297
* @param string $file
1029210298
* @param mixed ...$args

tests/PHPStan/Analyser/data/bug-2648.php

+7-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function doFoo(array $list): void
1616
assertType('int<2, max>', count($list));
1717
unset($list['fooo']);
1818
assertType('array<bool>', $list);
19-
assertType('int', count($list));
19+
assertType('int<0, max>', count($list));
2020
}
2121
}
2222

@@ -28,24 +28,24 @@ public function doBar(array $list): void
2828
if (count($list) > 1) {
2929
assertType('int<2, max>', count($list));
3030
foreach ($list as $key => $item) {
31-
assertType('int<2, max>|int<min, 0>', count($list));
31+
assertType('0|int<2, max>', count($list));
3232
if ($item === false) {
3333
unset($list[$key]);
34-
assertType('int', count($list));
34+
assertType('int<0, max>', count($list));
3535
}
3636

37-
assertType('int', count($list));
37+
assertType('int<0, max>', count($list));
3838

3939
if (count($list) === 1) {
40-
assertType('int', count($list));
40+
assertType('int<1, max>', count($list));
4141
break;
4242
}
4343
}
4444

45-
assertType('int', count($list));
45+
assertType('int<0, max>', count($list));
4646
}
4747

48-
assertType('int', count($list));
48+
assertType('int<0, max>', count($list));
4949
}
5050

5151
}

tests/PHPStan/Analyser/data/bug-2750.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ function (array $input) {
88
\assert(count($input) > 0);
99
assertType('int<1, max>', count($input));
1010
array_shift($input);
11-
assertType('int', count($input));
11+
assertType('int<0, max>', count($input));
1212

1313
\assert(count($input) > 0);
1414
assertType('int<1, max>', count($input));
1515
array_pop($input);
16-
assertType('int', count($input));
16+
assertType('int<0, max>', count($input));
1717

1818
\assert(count($input) > 0);
1919
assertType('int<1, max>', count($input));
2020
array_unshift($input, 'test');
21-
assertType('int', count($input));
21+
assertType('int<1, max>', count($input));
2222

2323
\assert(count($input) > 0);
2424
assertType('int<1, max>', count($input));
2525
array_push($input, 'nope');
26-
assertType('int', count($input));
26+
assertType('int<1, max>', count($input));
2727
};
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace CountType;
4+
5+
use function PHPStan\Analyser\assertType;
6+
7+
class Foo
8+
{
9+
10+
/**
11+
* @param non-empty-array $nonEmpty
12+
*/
13+
public function doFoo(
14+
array $nonEmpty
15+
)
16+
{
17+
assertType('int<1, max>', count($nonEmpty));
18+
}
19+
20+
}

0 commit comments

Comments
 (0)