From 87e4c5e0a890cf6b6a08ffc6a7d118afd1949e26 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 2 Sep 2019 11:07:18 +0200 Subject: [PATCH] remove ReturnTypeResolver --- .../Closure/AddClosureReturnTypeRector.php | 26 +-- .../ReturnTypeResolver/ReturnTypeResolver.php | 51 ------ .../AllAssignNodePropertyTypeInferer.php | 2 +- .../GetterPropertyTypeInferer.php | 150 ++++++++++++++++++ ...terTypeDeclarationPropertyTypeInferer.php} | 48 +++--- .../ReturnedNodeReturnTypeInferer.php | 40 ----- .../AddArrayReturnDocTypeRectorTest.php | 2 +- .../PropertyTypeDeclarationRectorTest.php | 2 +- 8 files changed, 199 insertions(+), 122 deletions(-) delete mode 100644 packages/TypeDeclaration/src/ReturnTypeResolver/ReturnTypeResolver.php create mode 100644 packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php rename packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/{GetterOrSetterPropertyTypeInferer.php => GetterTypeDeclarationPropertyTypeInferer.php} (63%) delete mode 100644 packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodeReturnTypeInferer.php diff --git a/packages/TypeDeclaration/src/Rector/Closure/AddClosureReturnTypeRector.php b/packages/TypeDeclaration/src/Rector/Closure/AddClosureReturnTypeRector.php index db4225c4e1e..34c7686ffa3 100644 --- a/packages/TypeDeclaration/src/Rector/Closure/AddClosureReturnTypeRector.php +++ b/packages/TypeDeclaration/src/Rector/Closure/AddClosureReturnTypeRector.php @@ -6,21 +6,29 @@ use PhpParser\Node; use PhpParser\Node\Expr\Closure; use PHPStan\Analyser\Scope; use Rector\NodeTypeResolver\Node\AttributeKey; -use Rector\PhpParser\Node\Manipulator\FunctionLikeManipulator; +use Rector\NodeTypeResolver\Php\ReturnTypeInfo; +use Rector\Php\TypeAnalyzer; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; +use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; final class AddClosureReturnTypeRector extends AbstractRector { /** - * @var FunctionLikeManipulator + * @var ReturnTypeInferer */ - private $functionLikeManipulator; + private $returnTypeInferer; - public function __construct(FunctionLikeManipulator $functionLikeManipulator) + /** + * @var TypeAnalyzer + */ + private $typeAnalyzer; + + public function __construct(ReturnTypeInferer $returnTypeInferer, TypeAnalyzer $typeAnalyzer) { - $this->functionLikeManipulator = $functionLikeManipulator; + $this->returnTypeInferer = $returnTypeInferer; + $this->typeAnalyzer = $typeAnalyzer; } public function getDefinition(): RectorDefinition @@ -81,12 +89,10 @@ CODE_SAMPLE return null; } - $staticReturnType = $this->functionLikeManipulator->resolveStaticReturnTypeInfo($node); - if ($staticReturnType === null) { - return null; - } + $inferedReturnTypes = $this->returnTypeInferer->inferFunctionLike($node); + $returnTypeInfo = new ReturnTypeInfo($inferedReturnTypes, $this->typeAnalyzer, $inferedReturnTypes); - $returnTypeNode = $staticReturnType->getFqnTypeNode(); + $returnTypeNode = $returnTypeInfo->getFqnTypeNode(); if ($returnTypeNode === null) { return null; } diff --git a/packages/TypeDeclaration/src/ReturnTypeResolver/ReturnTypeResolver.php b/packages/TypeDeclaration/src/ReturnTypeResolver/ReturnTypeResolver.php deleted file mode 100644 index 2864cbef123..00000000000 --- a/packages/TypeDeclaration/src/ReturnTypeResolver/ReturnTypeResolver.php +++ /dev/null @@ -1,51 +0,0 @@ -docBlockManipulator = $docBlockManipulator; - $this->functionLikeManipulator = $functionLikeManipulator; - } - - /** - * @param ClassMethod|Function_ $functionLike - */ - public function resolveFunctionLikeReturnType(FunctionLike $functionLike): ?ReturnTypeInfo - { - $docReturnTypeInfo = $this->docBlockManipulator->getReturnTypeInfo($functionLike); - $codeReturnTypeInfo = $this->functionLikeManipulator->resolveStaticReturnTypeInfo($functionLike); - - // code has priority over docblock - if ($docReturnTypeInfo === null) { - return $codeReturnTypeInfo; - } - - if ($codeReturnTypeInfo && $codeReturnTypeInfo->getTypeNode()) { - return $codeReturnTypeInfo; - } - - return $docReturnTypeInfo; - } -} diff --git a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php index 213aef51283..ff84c5c5df8 100644 --- a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php +++ b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php @@ -44,6 +44,6 @@ final class AllAssignNodePropertyTypeInferer extends AbstractTypeInferer impleme public function getPriority(): int { - return 500; + return 610; } } diff --git a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php new file mode 100644 index 00000000000..366bf5f1459 --- /dev/null +++ b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterPropertyTypeInferer.php @@ -0,0 +1,150 @@ +returnedNodesReturnTypeInferer = $returnedNodesReturnTypeInferer; + $this->returnTagReturnTypeInferer = $returnTagReturnTypeInferer; + } + + /** + * @return string[] + */ + public function inferProperty(Property $property): array + { + /** @var Class_ $class */ + $class = $property->getAttribute(AttributeKey::CLASS_NODE); + + /** @var string $propertyName */ + $propertyName = $this->nameResolver->getName($property); + + foreach ($class->getMethods() as $classMethod) { + if (! $this->hasClassMethodOnlyStatementReturnOfPropertyFetch($classMethod, $propertyName)) { + continue; + } + + $returnTypes = $this->inferClassMethodReturnTypes($classMethod); + if ($returnTypes !== []) { + return $returnTypes; + } + } + + return []; + } + + public function getPriority(): int + { + return 600; + } + + private function hasClassMethodOnlyStatementReturnOfPropertyFetch( + ClassMethod $classMethod, + string $propertyName + ): bool { + if (count((array) $classMethod->stmts) !== 1) { + return false; + } + + $onlyClassMethodStmt = $classMethod->stmts[0]; + if (! $onlyClassMethodStmt instanceof Return_) { + return false; + } + + /** @var Return_ $return */ + $return = $onlyClassMethodStmt; + + if (! $return->expr instanceof PropertyFetch) { + return false; + } + + return $this->nameResolver->isName($return->expr, $propertyName); + } + + /** + * Intentionally local method ↓ + * @todo possible move to ReturnTypeInferer, but allow to disable/enable in case of override returnType (99 %) + * + * @param ClassMethod|Function_|Closure $functionLike + * @return string[] + */ + private function resolveFunctionLikeReturnTypeDeclaration(FunctionLike $functionLike): array + { + if ($functionLike->returnType === null) { + return []; + } + + return $this->resolveReturnTypeToString($functionLike->returnType); + } + + /** + * @return string[] + */ + private function inferClassMethodReturnTypes(ClassMethod $classMethod): array + { + $returnTypeDeclarationTypes = $this->resolveFunctionLikeReturnTypeDeclaration($classMethod); + if ($returnTypeDeclarationTypes) { + return $returnTypeDeclarationTypes; + } + + $inferedTypes = $this->returnedNodesReturnTypeInferer->inferFunctionLike($classMethod); + if ($inferedTypes) { + return $inferedTypes; + } + + return $this->returnTagReturnTypeInferer->inferFunctionLike($classMethod); + } + + /** + * @param Identifier|Name|NullableType $node + * @return string[] + */ + private function resolveReturnTypeToString(Node $node): array + { + $types = []; + + $type = $node instanceof NullableType ? $node->type : $node; + $result = $this->nameResolver->getName($type); + if ($result !== null) { + $types[] = $result; + } + + if ($node instanceof NullableType) { + $types[] = 'null'; + } + + return $types; + } +} diff --git a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterOrSetterPropertyTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php similarity index 63% rename from packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterOrSetterPropertyTypeInferer.php rename to packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php index 34860d28d9a..610cda68dec 100644 --- a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterOrSetterPropertyTypeInferer.php +++ b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php @@ -2,28 +2,21 @@ namespace Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer; +use PhpParser\Node\Expr\Closure; use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\FunctionLike; +use PhpParser\Node\NullableType; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; +use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Return_; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface; -use Rector\TypeDeclaration\ReturnTypeResolver\ReturnTypeResolver; use Rector\TypeDeclaration\TypeInferer\AbstractTypeInferer; -final class GetterOrSetterPropertyTypeInferer extends AbstractTypeInferer implements PropertyTypeInfererInterface +final class GetterTypeDeclarationPropertyTypeInferer extends AbstractTypeInferer implements PropertyTypeInfererInterface { - /** - * @var ReturnTypeResolver - */ - private $returnTypeResolver; - - public function __construct(ReturnTypeResolver $returnTypeResolver) - { - $this->returnTypeResolver = $returnTypeResolver; - } - /** * @return string[] */ @@ -40,7 +33,12 @@ final class GetterOrSetterPropertyTypeInferer extends AbstractTypeInferer implem continue; } - $returnTypes = $this->resolveClassMethodReturnTypes($classMethod); + $returnTypes = $this->resolveReturnTypeToString($classMethod); + // let PhpDoc solve that later for more precise type + if ($returnTypes === ['array']) { + return []; + } + if ($returnTypes !== []) { return $returnTypes; } @@ -51,7 +49,7 @@ final class GetterOrSetterPropertyTypeInferer extends AbstractTypeInferer implem public function getPriority(): int { - return 600; + return 630; } private function hasClassMethodOnlyStatementReturnOfPropertyFetch( @@ -78,15 +76,29 @@ final class GetterOrSetterPropertyTypeInferer extends AbstractTypeInferer implem } /** + * @param Function_|ClassMethod|Closure $functionLike * @return string[] */ - private function resolveClassMethodReturnTypes(ClassMethod $classMethod): array + private function resolveReturnTypeToString(FunctionLike $functionLike): array { - $returnType = $this->returnTypeResolver->resolveFunctionLikeReturnType($classMethod); - if ($returnType === null) { + if ($functionLike->getReturnType() === null) { return []; } - return $returnType->getDocTypes(); + $returnType = $functionLike->getReturnType(); + + $types = []; + + $type = $returnType instanceof NullableType ? $returnType->type : $returnType; + $result = $this->nameResolver->getName($type); + if ($result !== null) { + $types[] = $result; + } + + if ($returnType instanceof NullableType) { + $types[] = 'null'; + } + + return $types; } } diff --git a/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodeReturnTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodeReturnTypeInferer.php deleted file mode 100644 index 06f9e163a35..00000000000 --- a/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodeReturnTypeInferer.php +++ /dev/null @@ -1,40 +0,0 @@ -functionLikeManipulator = $functionLikeManipulator; - } - - /** - * @param ClassMethod|Closure|Function_ $functionLike - * @return string[] - */ - public function inferFunctionLike(FunctionLike $functionLike): array - { - $resolvedReturnTypeInfo = $this->functionLikeManipulator->resolveStaticReturnTypeInfo($functionLike); - - return $resolvedReturnTypeInfo ? $resolvedReturnTypeInfo->getDocTypes() : []; - } - - public function getPriority(): int - { - return 500; - } -} diff --git a/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php b/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php index dfb18da631c..e81991e5358 100644 --- a/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php +++ b/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php @@ -17,7 +17,7 @@ final class AddArrayReturnDocTypeRectorTest extends AbstractRectorTestCase __DIR__ . '/Fixture/simple_array.php.inc', __DIR__ . '/Fixture/add_without_return_type_declaration.php.inc', __DIR__ . '/Fixture/fix_incorrect_array.php.inc', - // skip + // skip __DIR__ . '/Fixture/skip_constructor.php.inc', __DIR__ . '/Fixture/skip_array_after_array_type.php.inc', __DIR__ . '/Fixture/skip_shorten_class_name.php.inc', diff --git a/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php b/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php index bc92e758a31..89bfe63989d 100644 --- a/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php +++ b/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php @@ -26,7 +26,7 @@ final class PropertyTypeDeclarationRectorTest extends AbstractRectorTestCase __DIR__ . '/Fixture/single_nullable_return.php.inc', __DIR__ . '/Fixture/getter_type.php.inc', __DIR__ . '/Fixture/setter_type.php.inc', - // skip + // skip __DIR__ . '/Fixture/skip_multi_vars.php.inc', ]); }