Skip to content

Commit 815dd47

Browse files
ruudkondrejmirtes
authored andcommitted
Narrow type of Collection::last() when using Collection::isEmpty()
1 parent 2486f59 commit 815dd47

File tree

4 files changed

+46
-16
lines changed

4 files changed

+46
-16
lines changed

extension.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,6 @@ services:
313313

314314
# Doctrine Collection
315315
-
316-
class: PHPStan\Type\Doctrine\Collection\FirstTypeSpecifyingExtension
316+
class: PHPStan\Type\Doctrine\Collection\IsEmptyTypeSpecifyingExtension
317317
tags:
318318
- phpstan.typeSpecifier.methodTypeSpecifyingExtension

src/Type/Doctrine/Collection/FirstTypeSpecifyingExtension.php renamed to src/Type/Doctrine/Collection/IsEmptyTypeSpecifyingExtension.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
use PHPStan\Type\Constant\ConstantBooleanType;
1313
use PHPStan\Type\MethodTypeSpecifyingExtension;
1414

15-
final class FirstTypeSpecifyingExtension implements MethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
15+
final class IsEmptyTypeSpecifyingExtension implements MethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
1616
{
1717

1818
private const COLLECTION_CLASS = 'Doctrine\Common\Collections\Collection';
1919
private const IS_EMPTY_METHOD_NAME = 'isEmpty';
2020
private const FIRST_METHOD_NAME = 'first';
21+
private const LAST_METHOD_NAME = 'last';
2122

2223
/** @var TypeSpecifier */
2324
private $typeSpecifier;
@@ -47,11 +48,19 @@ public function specifyTypes(
4748
TypeSpecifierContext $context
4849
): SpecifiedTypes
4950
{
50-
return $this->typeSpecifier->create(
51+
$first = $this->typeSpecifier->create(
5152
new MethodCall($node->var, self::FIRST_METHOD_NAME),
5253
new ConstantBooleanType(false),
5354
$context
5455
);
56+
57+
$last = $this->typeSpecifier->create(
58+
new MethodCall($node->var, self::LAST_METHOD_NAME),
59+
new ConstantBooleanType(false),
60+
$context
61+
);
62+
63+
return $first->unionWith($last);
5564
}
5665

5766
public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void

tests/Type/Doctrine/Collection/FirstTypeSpecifyingExtensionTest.php renamed to tests/Type/Doctrine/Collection/IsEmptyTypeSpecifyingExtensionTest.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
/**
88
* @extends \PHPStan\Testing\RuleTestCase<VariableTypeReportingRule>
99
*/
10-
class FirstTypeSpecifyingExtensionTest extends \PHPStan\Testing\RuleTestCase
10+
class IsEmptyTypeSpecifyingExtensionTest extends \PHPStan\Testing\RuleTestCase
1111
{
1212

1313
protected function getRule(): Rule
@@ -21,24 +21,36 @@ protected function getRule(): Rule
2121
protected function getMethodTypeSpecifyingExtensions(): array
2222
{
2323
return [
24-
new FirstTypeSpecifyingExtension(),
24+
new IsEmptyTypeSpecifyingExtension(),
2525
];
2626
}
2727

2828
public function testExtension(): void
2929
{
3030
$this->analyse([__DIR__ . '/data/collection.php'], [
3131
[
32-
'Variable $entityOrFalse is: MyEntity|false',
32+
'Variable $entityOrFalse1 is: MyEntity|false',
3333
18,
3434
],
3535
[
36-
'Variable $false is: false',
37-
22,
36+
'Variable $entityOrFalse2 is: MyEntity|false',
37+
21,
3838
],
3939
[
40-
'Variable $entity is: MyEntity',
41-
27,
40+
'Variable $false1 is: false',
41+
25,
42+
],
43+
[
44+
'Variable $false2 is: false',
45+
28,
46+
],
47+
[
48+
'Variable $entity1 is: MyEntity',
49+
33,
50+
],
51+
[
52+
'Variable $entity2 is: MyEntity',
53+
36,
4254
],
4355
]);
4456
}

tests/Type/Doctrine/Collection/data/collection.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,24 @@ class MyEntity
1414
*/
1515
$collection = new ArrayCollection();
1616

17-
$entityOrFalse = $collection->first();
18-
$entityOrFalse;
17+
$entityOrFalse1 = $collection->first();
18+
$entityOrFalse1;
19+
20+
$entityOrFalse2 = $collection->last();
21+
$entityOrFalse2;
1922

2023
if ($collection->isEmpty()) {
21-
$false = $collection->first();
22-
$false;
24+
$false1 = $collection->first();
25+
$false1;
26+
27+
$false2 = $collection->last();
28+
$false2;
2329
}
2430

2531
if (!$collection->isEmpty()) {
26-
$entity = $collection->first();
27-
$entity;
32+
$entity1 = $collection->first();
33+
$entity1;
34+
35+
$entity2 = $collection->last();
36+
$entity2;
2837
}

0 commit comments

Comments
 (0)