mirror of https://github.com/rectorphp/rector.git
[PHP 8.0] Add return type support to ConstantListClassToEnumRector (#2420)
* add return type support * lock to last stable phpstan * [ci-review] Rector Rectify * [ci-review] Rector Rectify Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
e368dabaed
commit
7722a57d80
|
@ -7,7 +7,7 @@
|
|||
],
|
||||
"require": {
|
||||
"php": "^7.2|^8.0",
|
||||
"phpstan/phpstan": "^1.7.6"
|
||||
"phpstan/phpstan": "1.7.8"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"nikic/php-parser": "^4.14.0",
|
||||
"ondram/ci-detector": "^4.1",
|
||||
"phpstan/phpdoc-parser": "^1.5.1",
|
||||
"phpstan/phpstan": "^1.7.6",
|
||||
"phpstan/phpstan": "1.7.8",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"react/child-process": "^0.6.4",
|
||||
"react/event-loop": "^1.3",
|
||||
|
|
|
@ -709,3 +709,6 @@ parameters:
|
|||
- '#Register "Rector\\Php80\\Rector\\Class_\\ConstantListClassToEnumRector" service to "php80\.php" config set#'
|
||||
- '#Rule Rector\\Php80\\Rector\\Class_\\ConstantListClassToEnumRector must implements Rector\\VersionBonding\\Contract\\MinPhpVersionInterface#'
|
||||
- '#Register "Rector\\DowngradePhp80\\Rector\\Enum_\\DowngradeEnumToConstantListClassRector" service to "downgrade\-php80\.php" config set#'
|
||||
-
|
||||
message: '#Method "refactor(Params|Return)\(\)" returns bool type, so the name should start with is/has/was#'
|
||||
path: rules/Php80/Rector/Class_/ConstantListClassToEnumRector.php
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Fixture;
|
||||
|
||||
use Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source\Gear;
|
||||
|
||||
final class ChangeReturnType
|
||||
{
|
||||
/**
|
||||
* @return Gear::* $gear
|
||||
*/
|
||||
public function changeGear(): string
|
||||
{
|
||||
return Gear::FIRST;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Fixture;
|
||||
|
||||
use Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source\Gear;
|
||||
|
||||
final class ChangeReturnType
|
||||
{
|
||||
public function changeGear(): \Rector\Tests\Php80\Rector\Class_\ConstantListClassToEnumRector\Source\Gear
|
||||
{
|
||||
return Gear::FIRST;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -6,9 +6,10 @@ namespace Rector\Php80\NodeAnalyzer;
|
|||
|
||||
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Reflection\ParameterReflection;
|
||||
use PHPStan\Reflection\Php\PhpParameterReflection;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
|
||||
|
@ -24,33 +25,46 @@ final class EnumParamAnalyzer
|
|||
) {
|
||||
}
|
||||
|
||||
public function matchClassName(ParameterReflection $parameterReflection, PhpDocInfo $phpDocInfo): ?string
|
||||
public function matchParameterClassName(ParameterReflection $parameterReflection, PhpDocInfo $phpDocInfo): ?string
|
||||
{
|
||||
if (! $parameterReflection instanceof PhpParameterReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($parameterReflection->getName());
|
||||
if (! $paramTagValueNode instanceof ParamTagValueNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $paramTagValueNode->type instanceof ConstTypeNode) {
|
||||
$className = $this->resolveClassFromConstType($paramTagValueNode->type);
|
||||
if ($className === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$constTypeNode = $paramTagValueNode->type;
|
||||
if (! $constTypeNode->constExpr instanceof ConstFetchNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$constExpr = $constTypeNode->constExpr;
|
||||
$className = $constExpr->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
|
||||
|
||||
if (! $this->reflectionProvider->hasClass($className)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $className;
|
||||
}
|
||||
|
||||
public function matchReturnClassName(PhpDocInfo $phpDocInfo): ?string
|
||||
{
|
||||
$returnTagValueNode = $phpDocInfo->getReturnTagValue();
|
||||
if (! $returnTagValueNode instanceof ReturnTagValueNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->resolveClassFromConstType($returnTagValueNode->type);
|
||||
}
|
||||
|
||||
private function resolveClassFromConstType(TypeNode $typeNode): ?string
|
||||
{
|
||||
if (! $typeNode instanceof ConstTypeNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $typeNode->constExpr instanceof ConstFetchNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$constExpr = $typeNode->constExpr;
|
||||
return $constExpr->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use PhpParser\Node\Param;
|
|||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
|
||||
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
|
@ -88,10 +89,6 @@ CODE_SAMPLE
|
|||
|
||||
private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod
|
||||
{
|
||||
if ($classMethod->params === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// enum param types doc requires a docblock
|
||||
$phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod);
|
||||
if (! $phpDocInfo instanceof PhpDocInfo) {
|
||||
|
@ -103,31 +100,15 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$hasNodeChanged = false;
|
||||
// refactor params
|
||||
$haveParamsChanged = $this->refactorParams($methodReflection, $phpDocInfo, $classMethod);
|
||||
|
||||
$parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants());
|
||||
|
||||
foreach ($parametersAcceptor->getParameters() as $parameterReflection) {
|
||||
$enumLikeClass = $this->enumParamAnalyzer->matchClassName($parameterReflection, $phpDocInfo);
|
||||
if ($enumLikeClass === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$param = $this->getParamByName($classMethod, $parameterReflection->getName());
|
||||
if (! $param instanceof Param) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// change and remove
|
||||
$param->type = new FullyQualified($enumLikeClass);
|
||||
$hasNodeChanged = true;
|
||||
|
||||
/** @var ParamTagValueNode $paramTagValueNode */
|
||||
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($parameterReflection->getName());
|
||||
$this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $paramTagValueNode);
|
||||
$hasReturnChanged = $this->refactorReturn($phpDocInfo, $classMethod);
|
||||
if ($haveParamsChanged) {
|
||||
return $classMethod;
|
||||
}
|
||||
|
||||
if ($hasNodeChanged) {
|
||||
if ($hasReturnChanged) {
|
||||
return $classMethod;
|
||||
}
|
||||
|
||||
|
@ -146,4 +127,51 @@ CODE_SAMPLE
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function refactorParams(
|
||||
MethodReflection $methodReflection,
|
||||
PhpDocInfo $phpDocInfo,
|
||||
ClassMethod $classMethod
|
||||
): bool {
|
||||
$hasNodeChanged = false;
|
||||
|
||||
$parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants());
|
||||
foreach ($parametersAcceptor->getParameters() as $parameterReflection) {
|
||||
$enumLikeClass = $this->enumParamAnalyzer->matchParameterClassName($parameterReflection, $phpDocInfo);
|
||||
if ($enumLikeClass === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$param = $this->getParamByName($classMethod, $parameterReflection->getName());
|
||||
if (! $param instanceof Param) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// change and remove
|
||||
$param->type = new FullyQualified($enumLikeClass);
|
||||
$hasNodeChanged = true;
|
||||
|
||||
/** @var ParamTagValueNode $paramTagValueNode */
|
||||
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($parameterReflection->getName());
|
||||
$this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $paramTagValueNode);
|
||||
}
|
||||
|
||||
return $hasNodeChanged;
|
||||
}
|
||||
|
||||
private function refactorReturn(PhpDocInfo $phpDocInfo, ClassMethod $classMethod): bool
|
||||
{
|
||||
$returnType = $this->enumParamAnalyzer->matchReturnClassName($phpDocInfo);
|
||||
if ($returnType === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$classMethod->returnType = new FullyQualified($returnType);
|
||||
|
||||
/** @var ReturnTagValueNode $returnTagValueNode */
|
||||
$returnTagValueNode = $phpDocInfo->getReturnTagValue();
|
||||
$this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $returnTagValueNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue