From ceb493065c7bfaf39cc61d5fa8358b064ef568cd Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 20 Aug 2021 22:32:12 +0700 Subject: [PATCH] [DowngradePhp80] Remove self return type if child already has no return type (#725) * [DowngradePhp80] Remove self return type if child already has no return type * comment * fix * clean up * phpstan --- phpstan.neon | 10 ++++ ..._self_child_already_no_return_type.php.inc | 44 ++++++++++++++ .../DowngradeStaticTypeDeclarationRector.php | 59 +++++++++++++++++-- 3 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 rules-tests/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector/Fixture/remove_self_child_already_no_return_type.php.inc diff --git a/phpstan.neon b/phpstan.neon index aa32cfd2274..84d3078285a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -528,3 +528,13 @@ parameters: paths: - rules/Php72/Rector/Assign/ReplaceEachAssignmentWithKeyCurrentRector.php + - + message: '#foreach\(\), while\(\), for\(\) or if\(\) cannot contain a complex expression\. Extract it to a new variable on a line before#' + paths: + - packages/NodeNestingScope/FlowOfControlLocator.php + - packages/NodeNestingScope/ParentFinder.php + - rules/CodeQuality/Rector/Return_/SimplifyUselessVariableRector.php + - rules/CodingStyle/Rector/Assign/ManualJsonStringToJsonEncodeArrayRector.php + - rules/Php70/Rector/FuncCall/MultiDirnameRector.php + - src/Application/FileProcessor.php + - src/PhpParser/Node/BetterNodeFinder.php diff --git a/rules-tests/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector/Fixture/remove_self_child_already_no_return_type.php.inc b/rules-tests/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector/Fixture/remove_self_child_already_no_return_type.php.inc new file mode 100644 index 00000000000..693018536df --- /dev/null +++ b/rules-tests/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector/Fixture/remove_self_child_already_no_return_type.php.inc @@ -0,0 +1,44 @@ + +----- + diff --git a/rules/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector.php b/rules/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector.php index 02489cc5e91..d33cee07176 100644 --- a/rules/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector.php +++ b/rules/DowngradePhp80/Rector/ClassMethod/DowngradeStaticTypeDeclarationRector.php @@ -7,11 +7,14 @@ use PhpParser\Node; use PhpParser\Node\Name; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\StaticType; +use Rector\Core\PhpParser\AstResolver; use Rector\Core\Rector\AbstractRector; use Rector\DowngradePhp71\TypeDeclaration\PhpDocFromTypeDeclarationDecorator; +use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -23,7 +26,9 @@ final class DowngradeStaticTypeDeclarationRector extends AbstractRector { public function __construct( private PhpDocFromTypeDeclarationDecorator $phpDocFromTypeDeclarationDecorator, - private ReflectionProvider $reflectionProvider + private ReflectionProvider $reflectionProvider, + private AstResolver $astResolver, + private FamilyRelationsAnalyzer $familyRelationsAnalyzer ) { } @@ -73,10 +78,9 @@ public function getStatic() */ public function refactor(Node $node): ?Node { - if ($node->returnType instanceof Name && $this->nodeNameResolver->isName( - $node->returnType, - 'self' - )) { + $scope = $node->getAttribute(AttributeKey::SCOPE); + + if ($scope instanceof Scope && $this->shouldSkip($node, $scope)) { return null; } @@ -104,4 +108,49 @@ public function refactor(Node $node): ?Node return $node; } + + private function shouldSkip(ClassMethod $classMethod, Scope $scope): bool + { + if (! $classMethod->returnType instanceof Name) { + return false; + } + + if (! $this->nodeNameResolver->isName($classMethod->returnType, 'self')) { + return false; + } + + $classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE); + $className = $this->nodeNameResolver->getName($classLike); + + if ($className === null) { + return false; + } + + if (! $this->reflectionProvider->hasClass($className)) { + return false; + } + + $classReflection = $this->reflectionProvider->getClass($className); + $methodName = $this->nodeNameResolver->getName($classMethod); + $children = $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection); + + foreach ($children as $child) { + if (! $child->hasMethod($methodName)) { + continue; + } + + $method = $child->getMethod($methodName, $scope); + $classMethod = $this->astResolver->resolveClassMethodFromMethodReflection($method); + + if (! $classMethod instanceof ClassMethod) { + continue; + } + + if ($classMethod->returnType === null) { + return false; + } + } + + return true; + } }