Skip to content

19 files changed

+566
-1
lines changed

src/PhpDoc/TypeNodeResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ private function resolveConstTypeNode(ConstTypeNode $typeNode, NameScope $nameSc
724724
return new ErrorType();
725725
}
726726

727-
return $classReflection->getConstant($constantName)->getValueType();
727+
return ConstantTypeHelper::getTypeFromValue($classReflection->getConstant($constantName)->getValue());
728728
}
729729

730730
if ($constExpr instanceof ConstExprFloatNode) {

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,13 @@ public function dataFileAsserts(): iterable
487487
yield from $this->gatherAssertTypes(__DIR__ . '/data/sizeof.php');
488488

489489
yield from $this->gatherAssertTypes(__DIR__ . '/data/div-by-zero.php');
490+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5072.php');
491+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5530.php');
492+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-1861.php');
493+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4843.php');
494+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4602.php');
495+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4499.php');
496+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2142.php');
490497
}
491498

492499
/**
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Bug1861;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Tree
8+
{
9+
/**
10+
* @var self[]
11+
*/
12+
private $children = [];
13+
14+
public function isPath(): void
15+
{
16+
switch (count($this->children)) {
17+
case 0:
18+
assertType('array()', $this->children);
19+
break;
20+
case 1:
21+
assertType('array<' . self::class . '>&nonEmpty', $this->children);
22+
assertType(self::class, reset($this->children));
23+
break;
24+
default:
25+
assertType('array<' . self::class . '>&nonEmpty', $this->children);
26+
break;
27+
}
28+
}
29+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace Bug2142;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
10+
function doFoo1(array $arr): void
11+
{
12+
if (count($arr) > 0) {
13+
assertType('array&nonEmpty', $arr);
14+
}
15+
}
16+
17+
/**
18+
* @param string[] $arr
19+
*/
20+
function doFoo2(array $arr): void
21+
{
22+
if (count($arr) != 0) {
23+
assertType('array<string>&nonEmpty', $arr);
24+
}
25+
}
26+
27+
/**
28+
* @param string[] $arr
29+
*/
30+
function doFoo3(array $arr): void
31+
{
32+
if (count($arr) == 1) {
33+
assertType('array<string>&nonEmpty', $arr);
34+
}
35+
}
36+
37+
/**
38+
* @param string[] $arr
39+
*/
40+
function doFoo4(array $arr): void
41+
{
42+
if ($arr != []) {
43+
assertType('array<string>&nonEmpty', $arr);
44+
}
45+
}
46+
47+
/**
48+
* @param string[] $arr
49+
*/
50+
function doFoo5(array $arr): void
51+
{
52+
if (sizeof($arr) !== 0) {
53+
assertType('array<string>&nonEmpty', $arr);
54+
}
55+
}
56+
57+
/**
58+
* @param string[] $arr
59+
*/
60+
function doFoo6(array $arr): void
61+
{
62+
if (count($arr) !== 0) {
63+
assertType('array<string>&nonEmpty', $arr);
64+
}
65+
}
66+
67+
68+
/**
69+
* @param string[] $arr
70+
*/
71+
function doFoo7(array $arr): void
72+
{
73+
if (!empty($arr)) {
74+
assertType('array<string>&nonEmpty', $arr);
75+
}
76+
}
77+
78+
/**
79+
* @param string[] $arr
80+
*/
81+
function doFoo8(array $arr): void
82+
{
83+
if (count($arr) === 1) {
84+
assertType('array<string>&nonEmpty', $arr);
85+
}
86+
}
87+
88+
89+
/**
90+
* @param string[] $arr
91+
*/
92+
function doFoo9(array $arr): void
93+
{
94+
if ($arr !== []) {
95+
assertType('array<string>&nonEmpty', $arr);
96+
}
97+
}
98+
99+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Bug4499;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
10+
/** @param list<int> $things */
11+
function thing(array $things) : void{
12+
switch(count($things)){
13+
case 1:
14+
assertType('array<int, int>&nonEmpty', $things);
15+
assertType('int', array_shift($things));
16+
}
17+
}
18+
19+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Bug4602;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class HelloWorld
8+
{
9+
/** @param positive-int $limit */
10+
public function limit(int $limit): void
11+
{
12+
}
13+
14+
public function doSomething(int $limit): void
15+
{
16+
if ($limit <= 1) {
17+
return;
18+
}
19+
assertType('int<1, max>', $limit - 1);
20+
}
21+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Bug4843;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Bar {
8+
/**
9+
* @var int
10+
* @psalm-var 0|positive-int
11+
*/
12+
protected $depth = 0;
13+
14+
function foo(bool $isRoot): void {
15+
assertType('int<0, max>', $this->depth + ($isRoot ? 0 : 1));
16+
}
17+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Bug5072;
4+
5+
6+
use function PHPStan\Testing\assertType;
7+
8+
class HelloWorld
9+
{
10+
11+
public function doFoo(): void
12+
{
13+
assertType('1', max(1, -3));
14+
}
15+
16+
/**
17+
* @param array<string, mixed> $params
18+
*/
19+
public function incorrect(array $params): void
20+
{
21+
$page = isset($params['page']) ? intval($params['page']) : 1;
22+
assertType('int<1, max>', max(1, $page));
23+
}
24+
25+
public function incorrectWithConstant(): void
26+
{
27+
assertType('int<1, max>', max(1, PHP_INT_MAX));
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Bug5530;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
/** @var string */
10+
public const TYPE_A = 'a';
11+
/** @var string */
12+
public const TYPE_B = 'b';
13+
14+
/**
15+
* @param self::TYPE_* $arg
16+
*/
17+
public function run(string $arg = self::TYPE_A): void
18+
{
19+
assertType('\'a\'|\'b\'', $arg);
20+
}
21+
22+
/**
23+
* @param self::TYPE_A|self::TYPE_B $arg
24+
*/
25+
public function run2(string $arg = self::TYPE_A): void
26+
{
27+
assertType('\'a\'|\'b\'', $arg);
28+
}
29+
}

tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@ public function testBug5372Two(): void
6161
$this->analyse([__DIR__ . '/data/bug-5372_2.php'], []);
6262
}
6363

64+
public function testBug5447(): void
65+
{
66+
$this->analyse([__DIR__ . '/data/bug-5447.php'], []);
67+
}
68+
6469
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Bug5447;
4+
5+
class A {
6+
const FIELD_VERSION = 'VERSION';
7+
const FIELD_STAMP = 'STAMP';
8+
const FIELD_RCV_ID = 'RCV_ID';
9+
const FIELD_AMOUNT = 'AMOUNT';
10+
const FIELD_REF = 'REF';
11+
const FIELD_DATE = 'DATE';
12+
const FIELD_RETURN = 'RETURN';
13+
const FIELD_CANCEL = 'CANCEL';
14+
const FIELD_REJECT = 'REJECT';
15+
16+
/**
17+
* @phpstan-var array<self::FIELD_*, string>
18+
*/
19+
private array $parameters = [];
20+
21+
/**
22+
* @phpstan-param self::FIELD_* $key
23+
*/
24+
public function setParameter(string $key, string $value) : void
25+
{
26+
$this->parameters[$key] = $value;
27+
}
28+
29+
/**
30+
* @phpstan-return array<self::FIELD_*, string>
31+
*/
32+
public function getParameters() : array
33+
{
34+
return $this->parameters;
35+
}
36+
}

tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,12 @@ public function testBug4857(): void
123123
]);
124124
}
125125

126+
public function testBug5454(): void
127+
{
128+
if (PHP_VERSION_ID < 80000 && !self::$useStaticReflectionProvider) {
129+
$this->markTestSkipped('Test requires PHP 8.0.');
130+
}
131+
$this->analyse([__DIR__ . '/data/bug-5454.php'], []);
132+
}
133+
126134
}

tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,4 +475,22 @@ public function testBug4848(): void
475475
]);
476476
}
477477

478+
public function testBug4793(): void
479+
{
480+
$this->checkAlwaysTrueStrictComparison = true;
481+
$this->analyse([__DIR__ . '/data/bug-4793.php'], []);
482+
}
483+
484+
public function testBug5062(): void
485+
{
486+
$this->checkAlwaysTrueStrictComparison = true;
487+
$this->analyse([__DIR__ . '/data/bug-5062.php'], []);
488+
}
489+
490+
public function testBug3366(): void
491+
{
492+
$this->checkAlwaysTrueStrictComparison = true;
493+
$this->analyse([__DIR__ . '/data/bug-3366.php'], []);
494+
}
495+
478496
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Bug3366;
4+
5+
class Foo
6+
{
7+
8+
function sayHello(string $name): void
9+
{
10+
if ($name === '' ||
11+
$name === '1' ||
12+
$name === '2' ||
13+
$name === '3' ||
14+
$name === '4' ||
15+
$name === '5' ||
16+
$name === '6' ||
17+
$name === '7' ||
18+
$name === '8' ||
19+
$name === '9' ||
20+
$name === '0'
21+
) {
22+
echo 'hello';
23+
}
24+
}
25+
26+
}

0 commit comments

Comments
 (0)