Skip to content

Commit

Permalink
add return type support
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Jun 2, 2022
1 parent e368dab commit 97cb339
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 31 deletions.
3 changes: 3 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -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;
}
}

?>
38 changes: 26 additions & 12 deletions rules/Php80/NodeAnalyzer/EnumParamAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

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;
Expand All @@ -24,33 +25,46 @@ public function __construct(
) {
}

public function matchClassName(ParameterReflection $parameterReflection, PhpDocInfo $phpDocInfo): ?string
public function matchParameterClassName(ParameterReflection $parameterReflection, PhpDocInfo $phpDocInfo): ?string
{
if (! $parameterReflection instanceof PhpParameterReflection) {
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($parameterReflection->getName());
if (! $paramTagValueNode instanceof ParamTagValueNode) {
return null;
}

$paramTagValueNode = $phpDocInfo->getParamTagValueByName($parameterReflection->getName());
if (! $paramTagValueNode instanceof ParamTagValueNode) {
$className = $this->resolveClassFromConstType($paramTagValueNode->type);
if ($className === null) {
return null;
}

if (! $paramTagValueNode->type instanceof ConstTypeNode) {
if (! $this->reflectionProvider->hasClass($className)) {
return null;
}

$constTypeNode = $paramTagValueNode->type;
if (! $constTypeNode->constExpr instanceof ConstFetchNode) {
return $className;
}

public function matchReturnClassName(PhpDocInfo $phpDocInfo): ?string
{
$returnTagValueNode = $phpDocInfo->getReturnTagValue();
if (! $returnTagValueNode instanceof ReturnTagValueNode) {
return null;
}

$constExpr = $constTypeNode->constExpr;
$className = $constExpr->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
return $this->resolveClassFromConstType($returnTagValueNode->type);
}

if (! $this->reflectionProvider->hasClass($className)) {
private function resolveClassFromConstType(TypeNode $typeNode): ?string
{
if (! $typeNode instanceof ConstTypeNode) {
return null;
}

return $className;
if (! $typeNode->constExpr instanceof ConstFetchNode) {
return null;
}

$constExpr = $typeNode->constExpr;
return $constExpr->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
}
}
63 changes: 44 additions & 19 deletions rules/Php80/Rector/Class_/ConstantListClassToEnumRector.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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;
Expand Down Expand Up @@ -88,10 +89,6 @@ public function refactor(Node $node): ?Node

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) {
Expand All @@ -103,12 +100,41 @@ private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod
return null;
}

// refactor params
$haveParamsChanged = $this->refactorParams($methodReflection, $phpDocInfo, $classMethod);

$hasReturnChanged = $this->refactorReturn($phpDocInfo, $classMethod);

if ($haveParamsChanged || $hasReturnChanged) {
return $classMethod;
}

return null;
}

private function getParamByName(ClassMethod $classMethod, string $desiredParamName): ?Param
{
foreach ($classMethod->params as $param) {
if (! $this->nodeNameResolver->isName($param, $desiredParamName)) {
continue;
}

return $param;
}

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->matchClassName($parameterReflection, $phpDocInfo);
$enumLikeClass = $this->enumParamAnalyzer->matchParameterClassName($parameterReflection, $phpDocInfo);
if ($enumLikeClass === null) {
continue;
}
Expand All @@ -127,23 +153,22 @@ private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod
$this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $paramTagValueNode);
}

if ($hasNodeChanged) {
return $classMethod;
}

return null;
return $hasNodeChanged;
}

private function getParamByName(ClassMethod $classMethod, string $desiredParamName): ?Param
private function refactorReturn(PhpDocInfo $phpDocInfo, ClassMethod $classMethod): bool
{
foreach ($classMethod->params as $param) {
if (! $this->nodeNameResolver->isName($param, $desiredParamName)) {
continue;
}

return $param;
$returnType = $this->enumParamAnalyzer->matchReturnClassName($phpDocInfo);
if ($returnType === null) {
return false;
}

return null;
$classMethod->returnType = new FullyQualified($returnType);

/** @var ReturnTagValueNode $returnTagValueNode */
$returnTagValueNode = $phpDocInfo->getReturnTagValue();
$this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $returnTagValueNode);

return true;
}
}

0 comments on commit 97cb339

Please sign in to comment.