Skip to content

Commit 29bbc50

Browse files
authored
Merge pull request #5 from marc-mabe/fix-self-static-getValues
fixed #4 return type detection of [self|static]::getValues()
2 parents cb2808b + fe87f3c commit 29bbc50

File tree

4 files changed

+77
-10
lines changed

4 files changed

+77
-10
lines changed

src/EnumDynamicReturnTypeExtension.php

+15-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PhpParser\Node\Expr\StaticCall;
88
use PHPStan\Analyser\Scope;
99
use PHPStan\Reflection\MethodReflection;
10+
use PHPStan\Reflection\ParametersAcceptorSelector;
1011
use PHPStan\Type\ArrayType;
1112
use PHPStan\Type\Constant\ConstantArrayType;
1213
use PHPStan\Type\ConstantTypeHelper;
@@ -81,22 +82,30 @@ public function getTypeFromStaticMethodCall(
8182
StaticCall $staticCall,
8283
Scope $scope
8384
): Type {
84-
$callClass = $staticCall->class->toString();
85-
$methodLower = strtolower($methodReflection->getName());
85+
$callClass = $staticCall->class->toString();
86+
87+
// Can't detect possible types on static::*()
88+
// as it depends on defined enumerators of unknown inherited classes
89+
if ($callClass === 'static') {
90+
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
91+
}
8692

87-
return $this->staticMethods[$methodLower]($callClass);
93+
if ($callClass === 'self') {
94+
$callClass = $scope->getClassReflection()->getName();
95+
}
96+
97+
$methodLower = strtolower($methodReflection->getName());
98+
return $this->objectMethods[$methodLower]($callClass);
8899
}
89100

90101
public function getTypeFromMethodCall(
91102
MethodReflection $methodReflection,
92103
MethodCall $methodCall,
93104
Scope $scope
94105
): Type {
95-
$callType = $scope->getType($methodCall->var);
96-
$callClasses = $callType->getReferencedClasses();
97106
$methodLower = strtolower($methodReflection->getName());
98107
$returnTypes = [];
99-
foreach ($callClasses as $callClass) {
108+
foreach ($scope->getType($methodCall->var)->getReferencedClasses() as $callClass) {
100109
$returnTypes[] = $this->objectMethods[$methodLower]($callClass);
101110
}
102111

Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
[
22
{
3-
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::staticMethodFail() should return array<int, bool> but returns array<int, float|int|string>.",
3+
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::staticMethodFail() should return array<int, null> but returns array<int, float|int|string>.",
44
"line": 24,
55
"ignorable": true
66
},
77
{
8-
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::objectMethodFail() should return array<int, bool> but returns array<int, float|int|string>.",
8+
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::objectMethodFail() should return array<int, null> but returns array<int, float|int|string>.",
99
"line": 36,
1010
"ignorable": true
11+
},
12+
{
13+
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\MyEnum::selfGetValuesFail() should return array<int, null> but returns array<int, int|string>.",
14+
"line": 54,
15+
"ignorable": true
16+
},
17+
{
18+
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\MyInheritedEnum::inheritSelfGetValuesFail() should return array<int, null> but returns array<int, float|int|string>.",
19+
"line": 77,
20+
"ignorable": true
1121
}
1222
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[
2+
{
3+
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\MyEnum::staticGetValuesFail() should return array<int, null> but returns array<int, array|bool|float|int|string|null>.",
4+
"line": 60,
5+
"ignorable": true
6+
},
7+
{
8+
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\MyInheritedEnum::inheritStaticGetValuesFail() should return array<int, null> but returns array<int, array|bool|float|int|string|null>.",
9+
"line": 83,
10+
"ignorable": true
11+
}
12+
]

tests/integration/data/EnumGetValuesReturnType.php

+38-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public static function staticMethodValid(): array
1818
return MyInheritedEnum::getValues();
1919
}
2020

21-
/** @return array<int, bool> */
21+
/** @return array<int, null> */
2222
public static function staticMethodFail(): array
2323
{
2424
return MyInheritedEnum::getValues();
@@ -30,7 +30,7 @@ public static function objectMethodValid(): array
3030
return MyInheritedEnum::STR()->getValues();
3131
}
3232

33-
/** @return array<int, bool> */
33+
/** @return array<int, null> */
3434
public static function objectMethodFail(): array
3535
{
3636
return MyInheritedEnum::STR()->getValues();
@@ -41,9 +41,45 @@ class MyEnum extends Enum
4141
{
4242
const STR = 'str';
4343
const INT = 1;
44+
45+
/** @return array<int, int|string> */
46+
public static function selfGetValuesValid(): array
47+
{
48+
return self::getValues();
49+
}
50+
51+
/** @return array<int, null> */
52+
public static function selfGetValuesFail(): array
53+
{
54+
return self::getValues();
55+
}
56+
57+
/** @return array<int, null> */
58+
public static function staticGetValuesFail(): array
59+
{
60+
return static::getValues();
61+
}
4462
}
4563

4664
class MyInheritedEnum extends MyEnum
4765
{
4866
const FLOAT = 1.1;
67+
68+
/** @return array<int, float|int|string> */
69+
public static function inheritSelfGetValuesValid(): array
70+
{
71+
return self::getValues();
72+
}
73+
74+
/** @return array<int, null> */
75+
public static function inheritSelfGetValuesFail(): array
76+
{
77+
return self::getValues();
78+
}
79+
80+
/** @return array<int, null> */
81+
public static function inheritStaticGetValuesFail(): array
82+
{
83+
return static::getValues();
84+
}
4985
}

0 commit comments

Comments
 (0)