mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 05:48:21 +01:00
infer from @return doc type in PropertyTypeDeclaratoin
This commit is contained in:
parent
fcf3409584
commit
310ef2ae6e
@ -8,21 +8,20 @@ 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;
|
||||
use Rector\TypeDeclaration\ReturnTypeResolver\ReturnTypeResolver;
|
||||
|
||||
final class GetterOrSetterPropertyTypeInferer extends AbstractPropertyTypeInferer implements PropertyTypeInfererInterface
|
||||
{
|
||||
/**
|
||||
* @var BetterStandardPrinter
|
||||
* @var ReturnTypeResolver
|
||||
*/
|
||||
private $betterStandardPrinter;
|
||||
private $returnTypeResolver;
|
||||
|
||||
public function __construct(BetterStandardPrinter $betterStandardPrinter)
|
||||
public function __construct(ReturnTypeResolver $returnTypeResolver)
|
||||
{
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
$this->returnTypeResolver = $returnTypeResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,16 +39,11 @@ final class GetterOrSetterPropertyTypeInferer extends AbstractPropertyTypeInfere
|
||||
if (! $this->hasClassMethodOnlyStatementReturnOfPropertyFetch($classMethod, $propertyName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$returnTypes = $this->resolveClassMethodReturnTypes($classMethod);
|
||||
if ($returnTypes !== []) {
|
||||
return $returnTypes;
|
||||
}
|
||||
|
||||
throw new ShouldNotHappenException(sprintf(
|
||||
'"%s" for "%s" type',
|
||||
__METHOD__,
|
||||
$this->betterStandardPrinter->print($classMethod->returnType)
|
||||
));
|
||||
}
|
||||
|
||||
return [];
|
||||
@ -88,9 +82,11 @@ final class GetterOrSetterPropertyTypeInferer extends AbstractPropertyTypeInfere
|
||||
*/
|
||||
private function resolveClassMethodReturnTypes(ClassMethod $classMethod): array
|
||||
{
|
||||
// @todo resolve from doc?
|
||||
// resolve from doc
|
||||
if (! $classMethod->returnType) {
|
||||
return [];
|
||||
$returnType = $this->returnTypeResolver->resolveFunctionLikeReturnType($classMethod);
|
||||
|
||||
return $returnType->getDocTypes();
|
||||
}
|
||||
|
||||
if ($classMethod->returnType instanceof NullableType) {
|
||||
|
@ -49,11 +49,14 @@ abstract class AbstractTypeDeclarationRector extends AbstractRector
|
||||
*/
|
||||
protected $functionLikeManipulator;
|
||||
|
||||
public function __construct(
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function autowireAbstractTypeDeclarationRector(
|
||||
DocBlockManipulator $docBlockManipulator,
|
||||
ParsedNodesByType $parsedNodesByType,
|
||||
FunctionLikeManipulator $functionLikeManipulator
|
||||
) {
|
||||
): void {
|
||||
$this->docBlockManipulator = $docBlockManipulator;
|
||||
$this->parsedNodesByType = $parsedNodesByType;
|
||||
$this->functionLikeManipulator = $functionLikeManipulator;
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace Rector\TypeDeclaration\Rector\FunctionLike;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
@ -13,6 +12,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\Php\ReturnTypeInfo;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use Rector\TypeDeclaration\ReturnTypeResolver\ReturnTypeResolver;
|
||||
|
||||
final class ReturnTypeDeclarationRector extends AbstractTypeDeclarationRector
|
||||
{
|
||||
@ -21,6 +21,16 @@ final class ReturnTypeDeclarationRector extends AbstractTypeDeclarationRector
|
||||
*/
|
||||
private const EXCLUDED_METHOD_NAMES = ['__construct', '__destruct', '__clone'];
|
||||
|
||||
/**
|
||||
* @var ReturnTypeResolver
|
||||
*/
|
||||
private $returnTypeResolver;
|
||||
|
||||
public function __construct(ReturnTypeResolver $returnTypeResolver)
|
||||
{
|
||||
$this->returnTypeResolver = $returnTypeResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
@ -82,7 +92,7 @@ CODE_SAMPLE
|
||||
}
|
||||
}
|
||||
|
||||
$returnTypeInfo = $this->resolveReturnType($node);
|
||||
$returnTypeInfo = $this->returnTypeResolver->resolveFunctionLikeReturnType($node);
|
||||
if ($returnTypeInfo === null) {
|
||||
return null;
|
||||
}
|
||||
@ -125,26 +135,6 @@ CODE_SAMPLE
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod|Function_ $functionLike
|
||||
*/
|
||||
private function resolveReturnType(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add typehint to all children
|
||||
*/
|
||||
|
@ -0,0 +1,51 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\ReturnTypeResolver;
|
||||
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use Rector\NodeTypeResolver\Php\ReturnTypeInfo;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
|
||||
use Rector\PhpParser\Node\Manipulator\FunctionLikeManipulator;
|
||||
|
||||
final class ReturnTypeResolver
|
||||
{
|
||||
/**
|
||||
* @var DocBlockManipulator
|
||||
*/
|
||||
private $docBlockManipulator;
|
||||
|
||||
/**
|
||||
* @var FunctionLikeManipulator
|
||||
*/
|
||||
private $functionLikeManipulator;
|
||||
|
||||
public function __construct(
|
||||
DocBlockManipulator $docBlockManipulator,
|
||||
FunctionLikeManipulator $functionLikeManipulator
|
||||
) {
|
||||
$this->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;
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
|
||||
final class GetterType
|
||||
{
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
*/
|
||||
private $language;
|
||||
|
||||
private $surname;
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function hasLanguage(): bool
|
||||
{
|
||||
return $this->language !== null;
|
||||
}
|
||||
|
||||
public function getLanguage()
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
public function setLanguage(string $language): void
|
||||
{
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): void
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSurname()
|
||||
{
|
||||
return $this->surname;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
|
||||
final class GetterType
|
||||
{
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
* @var string
|
||||
*/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
* @var string
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* @Serializer\Type("string")
|
||||
* @var string
|
||||
*/
|
||||
private $language;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $surname;
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function hasLanguage(): bool
|
||||
{
|
||||
return $this->language !== null;
|
||||
}
|
||||
|
||||
public function getLanguage()
|
||||
{
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
public function setLanguage(string $language): void
|
||||
{
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): void
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSurname()
|
||||
{
|
||||
return $this->surname;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
final class SetterType
|
||||
{
|
||||
private $email;
|
||||
private $name;
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
return $this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\PropertyTypeDeclarationRector\Fixture;
|
||||
|
||||
final class SetterType
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $email;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
return $this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -15,13 +15,13 @@ final class PropertyTypeDeclarationRectorTest extends AbstractRectorTestCase
|
||||
__DIR__ . '/Fixture/constructor_assign.php.inc',
|
||||
__DIR__ . '/Fixture/phpunit_setup.php.inc',
|
||||
__DIR__ . '/Fixture/default_value.php.inc',
|
||||
|
||||
__DIR__ . '/Fixture/doctrine_column.php.inc',
|
||||
__DIR__ . '/Fixture/doctrine_relation.php.inc',
|
||||
|
||||
// get and set
|
||||
__DIR__ . '/Fixture/complex.php.inc',
|
||||
|
||||
__DIR__ . '/Fixture/single_nullable_return.php.inc',
|
||||
__DIR__ . '/Fixture/getter_type.php.inc',
|
||||
__DIR__ . '/Fixture/setter_type.php.inc',
|
||||
// skip
|
||||
__DIR__ . '/Fixture/skip_multi_vars.php.inc',
|
||||
]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user