From bf2faee2955a710c55529ab7bee3a1365719980a Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 1 Aug 2019 01:02:23 +0200 Subject: [PATCH] add return nullable type to GetterOrSetterPropertyTypeInferer --- .../GetterOrSetterPropertyTypeInferer.php | 97 ++++++++++++++----- .../Fixture/single_nullable_return.php.inc | 48 +++++++++ .../PropertyTypeDeclarationRectorTest.php | 2 + 3 files changed, 124 insertions(+), 23 deletions(-) create mode 100644 packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/Fixture/single_nullable_return.php.inc diff --git a/packages/TypeDeclaration/src/PropertyTypeInferer/GetterOrSetterPropertyTypeInferer.php b/packages/TypeDeclaration/src/PropertyTypeInferer/GetterOrSetterPropertyTypeInferer.php index d11075a46eba..99bbad9aa7f4 100644 --- a/packages/TypeDeclaration/src/PropertyTypeInferer/GetterOrSetterPropertyTypeInferer.php +++ b/packages/TypeDeclaration/src/PropertyTypeInferer/GetterOrSetterPropertyTypeInferer.php @@ -3,15 +3,28 @@ namespace Rector\TypeDeclaration\PropertyTypeInferer; use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\NullableType; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Return_; use Rector\Exception\ShouldNotHappenException; use Rector\NodeTypeResolver\Node\AttributeKey; +use Rector\PhpParser\Printer\BetterStandardPrinter; use Rector\TypeDeclaration\Contract\PropertyTypeInfererInterface; final class GetterOrSetterPropertyTypeInferer extends AbstractPropertyTypeInferer implements PropertyTypeInfererInterface { + /** + * @var BetterStandardPrinter + */ + private $betterStandardPrinter; + + public function __construct(BetterStandardPrinter $betterStandardPrinter) + { + $this->betterStandardPrinter = $betterStandardPrinter; + } + /** * @return string[] */ @@ -24,41 +37,79 @@ public function inferProperty(Property $property): array $propertyName = $this->nameResolver->resolve($property); foreach ($class->getMethods() as $classMethod) { - if (count((array) $classMethod->stmts) !== 1) { + if (! $this->hasClassMethodOnlyStatementReturnOfPropertyFetch($classMethod, $propertyName)) { continue; } - - $onlyClassMethodStmt = $classMethod->stmts[0]; - if (! $onlyClassMethodStmt instanceof Return_) { - continue; + $returnTypes = $this->resolveClassMethodReturnTypes($classMethod); + if ($returnTypes !== []) { + return $returnTypes; } - if (! $onlyClassMethodStmt->expr instanceof PropertyFetch) { - continue; - } + throw new ShouldNotHappenException(sprintf( + '"%s" for "%s" type', + __METHOD__, + $this->betterStandardPrinter->print($classMethod->returnType) + )); + } - if (! $this->nameResolver->isName($onlyClassMethodStmt->expr, $propertyName)) { - continue; - } + return []; + } - // @todo resolve from doc? - if (! $classMethod->returnType) { - continue; - } + public function getPriority(): int + { + return 600; + } - $result = $this->nameResolver->resolve($classMethod->returnType); - if ($result !== null) { - return [$result]; - } + private function hasClassMethodOnlyStatementReturnOfPropertyFetch( + ClassMethod $classMethod, + string $propertyName + ): bool { + if (count((array) $classMethod->stmts) !== 1) { + return false; + } - throw new ShouldNotHappenException(__METHOD__); + $onlyClassMethodStmt = $classMethod->stmts[0]; + if (! $onlyClassMethodStmt instanceof Return_) { + return false; } - return []; + /** @var Return_ $return */ + $return = $onlyClassMethodStmt; + + if (! $return->expr instanceof PropertyFetch) { + return false; + } + + return $this->nameResolver->isName($return->expr, $propertyName); } - public function getPriority(): int + /** + * @return string[] + */ + private function resolveClassMethodReturnTypes(ClassMethod $classMethod): array { - return 600; + // @todo resolve from doc? + if (! $classMethod->returnType) { + return []; + } + + if ($classMethod->returnType instanceof NullableType) { + $type = $classMethod->returnType->type; + } else { + $type = $classMethod->returnType; + } + + $result = $this->nameResolver->resolve($type); + if ($result !== null) { + $types = [$result]; + + if ($classMethod->returnType instanceof NullableType) { + $types[] = 'null'; + } + + return $types; + } + + return []; } } diff --git a/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/Fixture/single_nullable_return.php.inc b/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/Fixture/single_nullable_return.php.inc new file mode 100644 index 000000000000..fa9a01a65697 --- /dev/null +++ b/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/Fixture/single_nullable_return.php.inc @@ -0,0 +1,48 @@ +file; + } + + public function setFile(File $file): void + { + $this->file = $file; + } +} + +?> +----- +file; + } + + public function setFile(File $file): void + { + $this->file = $file; + } +} + +?> diff --git a/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php b/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php index e7609051de47..a1ddef75fdee 100644 --- a/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php +++ b/packages/TypeDeclaration/tests/Rector/Property/PropertyTypeDeclarationRector/PropertyTypeDeclarationRectorTest.php @@ -20,6 +20,8 @@ public function test(): void __DIR__ . '/Fixture/doctrine_relation.php.inc', __DIR__ . '/Fixture/complex.php.inc', + + __DIR__ . '/Fixture/single_nullable_return.php.inc', // skip __DIR__ . '/Fixture/skip_multi_vars.php.inc', ]);