Skip to content

Commit

Permalink
Merge pull request #5 from marc-mabe/fix-self-static-getValues
Browse files Browse the repository at this point in the history
fixed #4 return type detection of [self|static]::getValues()
  • Loading branch information
marc-mabe authored Oct 15, 2020
2 parents cb2808b + fe87f3c commit 29bbc50
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 10 deletions.
21 changes: 15 additions & 6 deletions src/EnumDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\ConstantTypeHelper;
Expand Down Expand Up @@ -81,22 +82,30 @@ public function getTypeFromStaticMethodCall(
StaticCall $staticCall,
Scope $scope
): Type {
$callClass = $staticCall->class->toString();
$methodLower = strtolower($methodReflection->getName());
$callClass = $staticCall->class->toString();

// Can't detect possible types on static::*()
// as it depends on defined enumerators of unknown inherited classes
if ($callClass === 'static') {
return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
}

return $this->staticMethods[$methodLower]($callClass);
if ($callClass === 'self') {
$callClass = $scope->getClassReflection()->getName();
}

$methodLower = strtolower($methodReflection->getName());
return $this->objectMethods[$methodLower]($callClass);
}

public function getTypeFromMethodCall(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type {
$callType = $scope->getType($methodCall->var);
$callClasses = $callType->getReferencedClasses();
$methodLower = strtolower($methodReflection->getName());
$returnTypes = [];
foreach ($callClasses as $callClass) {
foreach ($scope->getType($methodCall->var)->getReferencedClasses() as $callClass) {
$returnTypes[] = $this->objectMethods[$methodLower]($callClass);
}

Expand Down
14 changes: 12 additions & 2 deletions tests/integration/data/EnumGetValuesReturnType-3.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
[
{
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::staticMethodFail() should return array<int, bool> but returns array<int, float|int|string>.",
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::staticMethodFail() should return array<int, null> but returns array<int, float|int|string>.",
"line": 24,
"ignorable": true
},
{
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::objectMethodFail() should return array<int, bool> but returns array<int, float|int|string>.",
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\Example::objectMethodFail() should return array<int, null> but returns array<int, float|int|string>.",
"line": 36,
"ignorable": true
},
{
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\MyEnum::selfGetValuesFail() should return array<int, null> but returns array<int, int|string>.",
"line": 54,
"ignorable": true
},
{
"message": "Method MabeEnum\\PHPStan\\tests\\integration\\data\\EnumGetValuesReturnType\\MyInheritedEnum::inheritSelfGetValuesFail() should return array<int, null> but returns array<int, float|int|string>.",
"line": 77,
"ignorable": true
}
]
12 changes: 12 additions & 0 deletions tests/integration/data/EnumGetValuesReturnType-7.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"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>.",
"line": 60,
"ignorable": true
},
{
"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>.",
"line": 83,
"ignorable": true
}
]
40 changes: 38 additions & 2 deletions tests/integration/data/EnumGetValuesReturnType.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static function staticMethodValid(): array
return MyInheritedEnum::getValues();
}

/** @return array<int, bool> */
/** @return array<int, null> */
public static function staticMethodFail(): array
{
return MyInheritedEnum::getValues();
Expand All @@ -30,7 +30,7 @@ public static function objectMethodValid(): array
return MyInheritedEnum::STR()->getValues();
}

/** @return array<int, bool> */
/** @return array<int, null> */
public static function objectMethodFail(): array
{
return MyInheritedEnum::STR()->getValues();
Expand All @@ -41,9 +41,45 @@ class MyEnum extends Enum
{
const STR = 'str';
const INT = 1;

/** @return array<int, int|string> */
public static function selfGetValuesValid(): array
{
return self::getValues();
}

/** @return array<int, null> */
public static function selfGetValuesFail(): array
{
return self::getValues();
}

/** @return array<int, null> */
public static function staticGetValuesFail(): array
{
return static::getValues();
}
}

class MyInheritedEnum extends MyEnum
{
const FLOAT = 1.1;

/** @return array<int, float|int|string> */
public static function inheritSelfGetValuesValid(): array
{
return self::getValues();
}

/** @return array<int, null> */
public static function inheritSelfGetValuesFail(): array
{
return self::getValues();
}

/** @return array<int, null> */
public static function inheritStaticGetValuesFail(): array
{
return static::getValues();
}
}

0 comments on commit 29bbc50

Please sign in to comment.