mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
Updated Rector to commit 3ed476b9ab65958d85416e48a810b11dbaf4283a
3ed476b9ab
[TypeDeclaration] Add AddReturnArrayDocblockBasedOnArrayMapRector (#6235)
This commit is contained in:
parent
86cae8066f
commit
c5919c93d6
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Rector\TypeDeclaration\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrowFunction;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
||||
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Rector\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\StaticTypeMapper\StaticTypeMapper;
|
||||
use Rector\TypeDeclaration\NodeAnalyzer\ReturnAnalyzer;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
/**
|
||||
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddReturnArrayDocblockBasedOnArrayMapRector\AddReturnArrayDocblockBasedOnArrayMapRectorTest
|
||||
*/
|
||||
final class AddReturnArrayDocblockBasedOnArrayMapRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\PhpParser\Node\BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\TypeDeclaration\NodeAnalyzer\ReturnAnalyzer
|
||||
*/
|
||||
private $returnAnalyzer;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\StaticTypeMapper\StaticTypeMapper
|
||||
*/
|
||||
private $staticTypeMapper;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
|
||||
*/
|
||||
private $typeFactory;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger
|
||||
*/
|
||||
private $phpDocTypeChanger;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
|
||||
*/
|
||||
private $phpDocInfoFactory;
|
||||
public function __construct(BetterNodeFinder $betterNodeFinder, ReturnAnalyzer $returnAnalyzer, StaticTypeMapper $staticTypeMapper, TypeFactory $typeFactory, PhpDocTypeChanger $phpDocTypeChanger, PhpDocInfoFactory $phpDocInfoFactory)
|
||||
{
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->returnAnalyzer = $returnAnalyzer;
|
||||
$this->staticTypeMapper = $staticTypeMapper;
|
||||
$this->typeFactory = $typeFactory;
|
||||
$this->phpDocTypeChanger = $phpDocTypeChanger;
|
||||
$this->phpDocInfoFactory = $phpDocInfoFactory;
|
||||
}
|
||||
public function getRuleDefinition() : RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Add @return array docblock based on array_map() return strict type', [new CodeSample(<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function getItems(array $items)
|
||||
{
|
||||
return array_map(function ($item): int {
|
||||
return $item->id;
|
||||
}, $items);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
, <<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getItems(array $items)
|
||||
{
|
||||
return array_map(function ($item): int {
|
||||
return $item->id;
|
||||
}, $items);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
)]);
|
||||
}
|
||||
public function getNodeTypes() : array
|
||||
{
|
||||
return [ClassMethod::class, Function_::class];
|
||||
}
|
||||
/**
|
||||
* @param ClassMethod|Function_ $node
|
||||
* @return null|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Stmt\ClassMethod
|
||||
*/
|
||||
public function refactor(Node $node)
|
||||
{
|
||||
$returnsScoped = $this->betterNodeFinder->findReturnsScoped($node);
|
||||
if ($this->hasNonArrayReturnType($node)) {
|
||||
return null;
|
||||
}
|
||||
// nothing to return? skip it
|
||||
if ($returnsScoped === []) {
|
||||
return null;
|
||||
}
|
||||
// only returns with expr and no void
|
||||
if (!$this->returnAnalyzer->hasOnlyReturnWithExpr($node, $returnsScoped)) {
|
||||
return null;
|
||||
}
|
||||
$closureReturnTypes = [];
|
||||
foreach ($returnsScoped as $returnScoped) {
|
||||
if (!$returnScoped->expr instanceof FuncCall) {
|
||||
return null;
|
||||
}
|
||||
$arrayMapClosure = $this->matchArrayMapClosure($returnScoped->expr);
|
||||
if (!$arrayMapClosure instanceof FunctionLike) {
|
||||
return null;
|
||||
}
|
||||
if (!$arrayMapClosure->returnType instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
$closureReturnTypes[] = $this->staticTypeMapper->mapPhpParserNodePHPStanType($arrayMapClosure->returnType);
|
||||
}
|
||||
$returnType = $this->typeFactory->createMixedPassedOrUnionType($closureReturnTypes);
|
||||
$arrayType = new ArrayType(new MixedType(), $returnType);
|
||||
$functionLikePhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
|
||||
$hasChanged = $this->phpDocTypeChanger->changeReturnType($node, $functionLikePhpDocInfo, $arrayType);
|
||||
if ($hasChanged) {
|
||||
return null;
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_ $functionLike
|
||||
*/
|
||||
private function hasNonArrayReturnType($functionLike) : bool
|
||||
{
|
||||
if (!$functionLike->returnType instanceof Identifier) {
|
||||
return \false;
|
||||
}
|
||||
return $functionLike->returnType->toLowerString() !== 'array';
|
||||
}
|
||||
/**
|
||||
* @return \PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction|null
|
||||
*/
|
||||
private function matchArrayMapClosure(FuncCall $funcCall)
|
||||
{
|
||||
if (!$this->isName($funcCall, 'array_map')) {
|
||||
return null;
|
||||
}
|
||||
if ($funcCall->isFirstClassCallable()) {
|
||||
return null;
|
||||
}
|
||||
// lets infer strict array_map() type
|
||||
$firstArg = $funcCall->getArgs()[0];
|
||||
if (!$firstArg->value instanceof Closure && !$firstArg->value instanceof ArrowFunction) {
|
||||
return null;
|
||||
}
|
||||
return $firstArg->value;
|
||||
}
|
||||
}
|
@ -19,12 +19,12 @@ final class VersionResolver
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const PACKAGE_VERSION = 'fdd7f638a6e1f4d7ebf244f5827acdb687f14b3c';
|
||||
public const PACKAGE_VERSION = '3ed476b9ab65958d85416e48a810b11dbaf4283a';
|
||||
/**
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const RELEASE_DATE = '2024-08-14 20:21:02';
|
||||
public const RELEASE_DATE = '2024-08-15 00:26:49';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
1
vendor/composer/autoload_classmap.php
vendored
1
vendor/composer/autoload_classmap.php
vendored
@ -2444,6 +2444,7 @@ return array(
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddParamTypeBasedOnPHPUnitDataProviderRector' => $baseDir . '/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeBasedOnPHPUnitDataProviderRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddParamTypeDeclarationRector' => $baseDir . '/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeDeclarationRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddParamTypeFromPropertyTypeRector' => $baseDir . '/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeFromPropertyTypeRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnArrayDocblockBasedOnArrayMapRector' => $baseDir . '/rules/TypeDeclaration/Rector/ClassMethod/AddReturnArrayDocblockBasedOnArrayMapRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnTypeDeclarationBasedOnParentClassMethodRector' => $baseDir . '/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationBasedOnParentClassMethodRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnTypeDeclarationRector' => $baseDir . '/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddTypeFromResourceDocblockRector' => $baseDir . '/rules/TypeDeclaration/Rector/ClassMethod/AddTypeFromResourceDocblockRector.php',
|
||||
|
1
vendor/composer/autoload_static.php
vendored
1
vendor/composer/autoload_static.php
vendored
@ -2663,6 +2663,7 @@ class ComposerStaticInit969cf4fb8686733ba64d08544d342ca0
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddParamTypeBasedOnPHPUnitDataProviderRector' => __DIR__ . '/../..' . '/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeBasedOnPHPUnitDataProviderRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddParamTypeDeclarationRector' => __DIR__ . '/../..' . '/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeDeclarationRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddParamTypeFromPropertyTypeRector' => __DIR__ . '/../..' . '/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeFromPropertyTypeRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnArrayDocblockBasedOnArrayMapRector' => __DIR__ . '/../..' . '/rules/TypeDeclaration/Rector/ClassMethod/AddReturnArrayDocblockBasedOnArrayMapRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnTypeDeclarationBasedOnParentClassMethodRector' => __DIR__ . '/../..' . '/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationBasedOnParentClassMethodRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnTypeDeclarationRector' => __DIR__ . '/../..' . '/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector.php',
|
||||
'Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddTypeFromResourceDocblockRector' => __DIR__ . '/../..' . '/rules/TypeDeclaration/Rector/ClassMethod/AddTypeFromResourceDocblockRector.php',
|
||||
|
Loading…
x
Reference in New Issue
Block a user