mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-04 02:10:51 +00:00
Updated Rector to commit e8e2db769d857346202bc0f59ab4a618ee5b5202
e8e2db769d
[TypeDeclaration] Add assigned new to variable in ReturnTypeFromReturnNewRector (#2647)
This commit is contained in:
parent
8b3c974a42
commit
42d59f4003
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Rector\TypeDeclaration\NodeAnalyzer\ReturnTypeAnalyzer;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Expr\Yield_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
final class StrictReturnNewAnalyzer
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\NodeNameResolver\NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
public function __construct(BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver)
|
||||
{
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
|
||||
*/
|
||||
public function matchAlwaysReturnVariableNew($functionLike) : ?string
|
||||
{
|
||||
if ($functionLike->stmts === null) {
|
||||
return null;
|
||||
}
|
||||
if ($this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($functionLike, [Yield_::class])) {
|
||||
return null;
|
||||
}
|
||||
/** @var Return_[] $returns */
|
||||
$returns = $this->betterNodeFinder->findInstancesOfInFunctionLikeScoped($functionLike, Return_::class);
|
||||
if ($returns === []) {
|
||||
return null;
|
||||
}
|
||||
// is one statement depth 3?
|
||||
if (!$this->areExclusiveExprReturns($returns)) {
|
||||
return null;
|
||||
}
|
||||
// has root return?
|
||||
if (!$this->hasClassMethodRootReturn($functionLike)) {
|
||||
return null;
|
||||
}
|
||||
if (\count($returns) !== 1) {
|
||||
return null;
|
||||
}
|
||||
// exact one return of variable
|
||||
$onlyReturn = $returns[0];
|
||||
if (!$onlyReturn->expr instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
$createdVariablesToTypes = $this->resolveCreatedVariablesToTypes($functionLike);
|
||||
$returnedVariableName = $this->nodeNameResolver->getName($onlyReturn->expr);
|
||||
return $createdVariablesToTypes[$returnedVariableName] ?? null;
|
||||
}
|
||||
/**
|
||||
* @param Return_[] $returns
|
||||
*/
|
||||
private function areExclusiveExprReturns(array $returns) : bool
|
||||
{
|
||||
foreach ($returns as $return) {
|
||||
if (!$return->expr instanceof Expr) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $functionLike
|
||||
*/
|
||||
private function hasClassMethodRootReturn($functionLike) : bool
|
||||
{
|
||||
foreach ((array) $functionLike->stmts as $stmt) {
|
||||
if ($stmt instanceof Return_) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* @return array<string, string>
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $functionLike
|
||||
*/
|
||||
private function resolveCreatedVariablesToTypes($functionLike) : array
|
||||
{
|
||||
$createdVariablesToTypes = [];
|
||||
// what new is assigned to it?
|
||||
foreach ((array) $functionLike->stmts as $stmt) {
|
||||
if (!$stmt instanceof Expression) {
|
||||
continue;
|
||||
}
|
||||
if (!$stmt->expr instanceof Assign) {
|
||||
continue;
|
||||
}
|
||||
$assign = $stmt->expr;
|
||||
if (!$assign->expr instanceof New_) {
|
||||
continue;
|
||||
}
|
||||
if (!$assign->var instanceof Variable) {
|
||||
continue;
|
||||
}
|
||||
$variableName = $this->nodeNameResolver->getName($assign->var);
|
||||
if (!\is_string($variableName)) {
|
||||
continue;
|
||||
}
|
||||
$className = $this->nodeNameResolver->getName($assign->expr->class);
|
||||
if (!\is_string($className)) {
|
||||
continue;
|
||||
}
|
||||
$createdVariablesToTypes[$variableName] = $className;
|
||||
}
|
||||
return $createdVariablesToTypes;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use PhpParser\Node\Expr\ArrowFunction;
|
|||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
|
@ -15,6 +16,7 @@ use PHPStan\Reflection\ClassReflection;
|
|||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StaticType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\Core\Enum\ObjectReference;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
|
@ -23,6 +25,7 @@ use Rector\Core\ValueObject\PhpVersionFeature;
|
|||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\SelfStaticType;
|
||||
use Rector\TypeDeclaration\NodeAnalyzer\ReturnTypeAnalyzer\StrictReturnNewAnalyzer;
|
||||
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
@ -46,11 +49,17 @@ final class ReturnTypeFromReturnNewRector extends AbstractRector implements MinP
|
|||
* @var \Rector\Core\Reflection\ReflectionResolver
|
||||
*/
|
||||
private $reflectionResolver;
|
||||
public function __construct(TypeFactory $typeFactory, ReflectionProvider $reflectionProvider, ReflectionResolver $reflectionResolver)
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\TypeDeclaration\NodeAnalyzer\ReturnTypeAnalyzer\StrictReturnNewAnalyzer
|
||||
*/
|
||||
private $strictReturnNewAnalyzer;
|
||||
public function __construct(TypeFactory $typeFactory, ReflectionProvider $reflectionProvider, ReflectionResolver $reflectionResolver, StrictReturnNewAnalyzer $strictReturnNewAnalyzer)
|
||||
{
|
||||
$this->typeFactory = $typeFactory;
|
||||
$this->reflectionProvider = $reflectionProvider;
|
||||
$this->reflectionResolver = $reflectionResolver;
|
||||
$this->strictReturnNewAnalyzer = $strictReturnNewAnalyzer;
|
||||
}
|
||||
public function getRuleDefinition() : RuleDefinition
|
||||
{
|
||||
|
@ -89,29 +98,14 @@ CODE_SAMPLE
|
|||
if ($node->returnType !== null) {
|
||||
return null;
|
||||
}
|
||||
if ($node instanceof ArrowFunction) {
|
||||
$returns = [new Return_($node->expr)];
|
||||
} else {
|
||||
/** @var Return_[] $returns */
|
||||
$returns = $this->betterNodeFinder->findInstancesOfInFunctionLikeScoped($node, Return_::class);
|
||||
}
|
||||
if ($returns === []) {
|
||||
return null;
|
||||
}
|
||||
$newTypes = [];
|
||||
foreach ($returns as $return) {
|
||||
if (!$return->expr instanceof New_) {
|
||||
return null;
|
||||
if (!$node instanceof ArrowFunction) {
|
||||
$returnedNewClassName = $this->strictReturnNewAnalyzer->matchAlwaysReturnVariableNew($node);
|
||||
if (\is_string($returnedNewClassName)) {
|
||||
$node->returnType = new FullyQualified($returnedNewClassName);
|
||||
return $node;
|
||||
}
|
||||
$new = $return->expr;
|
||||
if (!$new->class instanceof Name) {
|
||||
return null;
|
||||
}
|
||||
$newTypes[] = $this->createObjectTypeFromNew($new);
|
||||
}
|
||||
$returnType = $this->typeFactory->createMixedPassedOrUnionType($newTypes);
|
||||
$node->returnType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType, TypeKind::RETURN);
|
||||
return $node;
|
||||
return $this->refactorDirectReturnNew($node);
|
||||
}
|
||||
public function provideMinPhpVersion() : int
|
||||
{
|
||||
|
@ -139,4 +133,50 @@ CODE_SAMPLE
|
|||
$classReflection = $this->reflectionProvider->getClass($className);
|
||||
return new ObjectType($className, null, $classReflection);
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\ArrowFunction|\PhpParser\Node\Expr\Closure $node
|
||||
* @return null|\PhpParser\Node\Expr\ArrowFunction|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure
|
||||
*/
|
||||
private function refactorDirectReturnNew($node)
|
||||
{
|
||||
if ($node instanceof ArrowFunction) {
|
||||
$returns = [new Return_($node->expr)];
|
||||
} else {
|
||||
/** @var Return_[] $returns */
|
||||
$returns = $this->betterNodeFinder->findInstancesOfInFunctionLikeScoped($node, Return_::class);
|
||||
}
|
||||
if ($returns === []) {
|
||||
return null;
|
||||
}
|
||||
$newTypes = $this->resolveReturnNewType($returns);
|
||||
if ($newTypes === null) {
|
||||
return null;
|
||||
}
|
||||
$returnType = $this->typeFactory->createMixedPassedOrUnionType($newTypes);
|
||||
$returnTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType, TypeKind::RETURN);
|
||||
if (!$returnTypeNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
$node->returnType = $returnTypeNode;
|
||||
return $node;
|
||||
}
|
||||
/**
|
||||
* @param Return_[] $returns
|
||||
* @return Type[]|null
|
||||
*/
|
||||
private function resolveReturnNewType(array $returns) : ?array
|
||||
{
|
||||
$newTypes = [];
|
||||
foreach ($returns as $return) {
|
||||
if (!$return->expr instanceof New_) {
|
||||
return null;
|
||||
}
|
||||
$new = $return->expr;
|
||||
if (!$new->class instanceof Name) {
|
||||
return null;
|
||||
}
|
||||
$newTypes[] = $this->createObjectTypeFromNew($new);
|
||||
}
|
||||
return $newTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,12 @@ final class VersionResolver
|
|||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const PACKAGE_VERSION = 'fba410bf6ed6da0657cb8ec939a22ad3988fc4ad';
|
||||
public const PACKAGE_VERSION = 'e8e2db769d857346202bc0f59ab4a618ee5b5202';
|
||||
/**
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const RELEASE_DATE = '2022-07-09 14:09:38';
|
||||
public const RELEASE_DATE = '2022-07-09 14:50:32';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
|
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
|
@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
|
|||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit45dd80ba9097691ea865802d8b675d2f::getLoader();
|
||||
return ComposerAutoloaderInitf833c8a4a67a7cd48d0e4f56703bd04d::getLoader();
|
||||
|
|
1
vendor/composer/autoload_classmap.php
vendored
1
vendor/composer/autoload_classmap.php
vendored
|
@ -2996,6 +2996,7 @@ return array(
|
|||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\AlwaysStrictReturnAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/AlwaysStrictReturnAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictBoolReturnTypeAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictBoolReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictNativeFunctionReturnTypeAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictNativeFunctionReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictReturnNewAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictReturnNewAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictScalarReturnTypeAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictScalarReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\TypeNodeUnwrapper' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/TypeNodeUnwrapper.php',
|
||||
'Rector\\TypeDeclaration\\NodeTypeAnalyzer\\CallTypeAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeTypeAnalyzer/CallTypeAnalyzer.php',
|
||||
|
|
14
vendor/composer/autoload_real.php
vendored
14
vendor/composer/autoload_real.php
vendored
|
@ -2,7 +2,7 @@
|
|||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit45dd80ba9097691ea865802d8b675d2f
|
||||
class ComposerAutoloaderInitf833c8a4a67a7cd48d0e4f56703bd04d
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
|
@ -22,19 +22,19 @@ class ComposerAutoloaderInit45dd80ba9097691ea865802d8b675d2f
|
|||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit45dd80ba9097691ea865802d8b675d2f', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInitf833c8a4a67a7cd48d0e4f56703bd04d', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit45dd80ba9097691ea865802d8b675d2f', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitf833c8a4a67a7cd48d0e4f56703bd04d', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit45dd80ba9097691ea865802d8b675d2f::getInitializer($loader));
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitf833c8a4a67a7cd48d0e4f56703bd04d::getInitializer($loader));
|
||||
|
||||
$loader->setClassMapAuthoritative(true);
|
||||
$loader->register(true);
|
||||
|
||||
$includeFiles = \Composer\Autoload\ComposerStaticInit45dd80ba9097691ea865802d8b675d2f::$files;
|
||||
$includeFiles = \Composer\Autoload\ComposerStaticInitf833c8a4a67a7cd48d0e4f56703bd04d::$files;
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
composerRequire45dd80ba9097691ea865802d8b675d2f($fileIdentifier, $file);
|
||||
composerRequiref833c8a4a67a7cd48d0e4f56703bd04d($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
|
@ -46,7 +46,7 @@ class ComposerAutoloaderInit45dd80ba9097691ea865802d8b675d2f
|
|||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
function composerRequire45dd80ba9097691ea865802d8b675d2f($fileIdentifier, $file)
|
||||
function composerRequiref833c8a4a67a7cd48d0e4f56703bd04d($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
|
9
vendor/composer/autoload_static.php
vendored
9
vendor/composer/autoload_static.php
vendored
|
@ -4,7 +4,7 @@
|
|||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit45dd80ba9097691ea865802d8b675d2f
|
||||
class ComposerStaticInitf833c8a4a67a7cd48d0e4f56703bd04d
|
||||
{
|
||||
public static $files = array (
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
|
@ -3303,6 +3303,7 @@ class ComposerStaticInit45dd80ba9097691ea865802d8b675d2f
|
|||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\AlwaysStrictReturnAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/AlwaysStrictReturnAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictBoolReturnTypeAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictBoolReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictNativeFunctionReturnTypeAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictNativeFunctionReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictReturnNewAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictReturnNewAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnTypeAnalyzer\\StrictScalarReturnTypeAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictScalarReturnTypeAnalyzer.php',
|
||||
'Rector\\TypeDeclaration\\NodeAnalyzer\\TypeNodeUnwrapper' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/TypeNodeUnwrapper.php',
|
||||
'Rector\\TypeDeclaration\\NodeTypeAnalyzer\\CallTypeAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeTypeAnalyzer/CallTypeAnalyzer.php',
|
||||
|
@ -3412,9 +3413,9 @@ class ComposerStaticInit45dd80ba9097691ea865802d8b675d2f
|
|||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit45dd80ba9097691ea865802d8b675d2f::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit45dd80ba9097691ea865802d8b675d2f::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit45dd80ba9097691ea865802d8b675d2f::$classMap;
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitf833c8a4a67a7cd48d0e4f56703bd04d::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitf833c8a4a67a7cd48d0e4f56703bd04d::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInitf833c8a4a67a7cd48d0e4f56703bd04d::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user