From 1bf424cd9b209dd5580e29b0ed2e62e80a3d782e Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 24 Sep 2025 17:46:10 +0200 Subject: [PATCH] [type-declaration-docblocks] Add AddParamArrayDocblockFromAssignsParamToParamReferenceRector --- ...AssignsParamToParamReferenceRectorTest.php | 28 ++++ .../skip_dim_fetch_assign_deep.php.inc | 11 ++ .../Fixture/skip_multiple_assigns.php.inc | 12 ++ .../Fixture/some_class.php.inc | 30 ++++ .../config/configured_rule.php | 9 ++ ...etchFinder.php => ArrayDimFetchFinder.php} | 33 ++++- ...FromAssignsParamToParamReferenceRector.php | 138 ++++++++++++++++++ ...mArrayDocblockFromDimFetchAccessRector.php | 6 +- 8 files changed, 263 insertions(+), 4 deletions(-) create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/AddParamArrayDocblockFromAssignsParamToParamReferenceRectorTest.php create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/Fixture/skip_dim_fetch_assign_deep.php.inc create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/Fixture/skip_multiple_assigns.php.inc create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/Fixture/some_class.php.inc create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/config/configured_rule.php rename rules/TypeDeclarationDocblocks/NodeFinder/{DimFetchFinder.php => ArrayDimFetchFinder.php} (51%) create mode 100644 rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector.php diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/AddParamArrayDocblockFromAssignsParamToParamReferenceRectorTest.php b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/AddParamArrayDocblockFromAssignsParamToParamReferenceRectorTest.php new file mode 100644 index 00000000000..d43772a6e24 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/AddParamArrayDocblockFromAssignsParamToParamReferenceRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/Fixture/skip_dim_fetch_assign_deep.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/Fixture/skip_dim_fetch_assign_deep.php.inc new file mode 100644 index 00000000000..f79a3ed5cfd --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/Fixture/skip_dim_fetch_assign_deep.php.inc @@ -0,0 +1,11 @@ + +----- + diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/config/configured_rule.php b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/config/configured_rule.php new file mode 100644 index 00000000000..b3beda53d79 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector/config/configured_rule.php @@ -0,0 +1,9 @@ +withRules([AddParamArrayDocblockFromAssignsParamToParamReferenceRector::class]); diff --git a/rules/TypeDeclarationDocblocks/NodeFinder/DimFetchFinder.php b/rules/TypeDeclarationDocblocks/NodeFinder/ArrayDimFetchFinder.php similarity index 51% rename from rules/TypeDeclarationDocblocks/NodeFinder/DimFetchFinder.php rename to rules/TypeDeclarationDocblocks/NodeFinder/ArrayDimFetchFinder.php index 81b71a6bd80..c2222081b4c 100644 --- a/rules/TypeDeclarationDocblocks/NodeFinder/DimFetchFinder.php +++ b/rules/TypeDeclarationDocblocks/NodeFinder/ArrayDimFetchFinder.php @@ -5,12 +5,15 @@ namespace Rector\TypeDeclarationDocblocks\NodeFinder; use PhpParser\Node; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\ArrayDimFetch; +use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Stmt\ClassMethod; use Rector\NodeNameResolver\NodeNameResolver; use Rector\PhpParser\Node\BetterNodeFinder; -final readonly class DimFetchFinder +final readonly class ArrayDimFetchFinder { public function __construct( private BetterNodeFinder $betterNodeFinder, @@ -18,6 +21,34 @@ public function __construct( ) { } + /** + * @return Expr[] + */ + public function findDimFetchAssignToVariableName(ClassMethod $classMethod, string $variableName): array + { + $assigns = $this->betterNodeFinder->findInstancesOfScoped((array) $classMethod->stmts, Assign::class); + + $exprs = []; + foreach ($assigns as $assign) { + if (! $assign->var instanceof ArrayDimFetch) { + continue; + } + + $arrayDimFetch = $assign->var; + if (! $arrayDimFetch->var instanceof Variable) { + continue; + } + + if (! $this->nodeNameResolver->isName($arrayDimFetch->var, $variableName)) { + continue; + } + + $exprs[] = $assign->expr; + } + + return $exprs; + } + /** * @return ArrayDimFetch[] */ diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector.php new file mode 100644 index 00000000000..a67d880da1e --- /dev/null +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromAssignsParamToParamReferenceRector.php @@ -0,0 +1,138 @@ +> + */ + public function getNodeTypes(): array + { + return [ClassMethod::class]; + } + + /** + * @param ClassMethod $node + */ + public function refactor(Node $node): ?Node + { + $hasChanged = false; + + if ($node->getParams() === []) { + return null; + } + + $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); + + foreach ($node->getParams() as $param) { + if (! $param->byRef) { + continue; + } + + if (! $param->type instanceof Identifier) { + continue; + } + + if (! $this->isName($param->type, 'array')) { + continue; + } + + $paramName = $this->getName($param); + $paramTagValueNode = $phpDocInfo->getParamTagValueByName($paramName); + + // already defined, lets skip it + if ($paramTagValueNode instanceof ParamTagValueNode) { + continue; + } + + $exprs = $this->arrayDimFetchFinder->findDimFetchAssignToVariableName($node, $paramName); + + // to kick off with one + if (count($exprs) !== 1) { + continue; + } + + $assignedExprType = $this->getType($exprs[0]); + $iterableType = new ArrayType(new MixedType(), $assignedExprType); + + $hasParamTypeChanged = $this->nodeDocblockTypeDecorator->decorateGenericIterableParamType( + $iterableType, + $phpDocInfo, + $node, + $paramName + ); + + if (! $hasParamTypeChanged) { + continue; + } + + $hasChanged = true; + } + + if (! $hasChanged) { + return null; + } + + return $node; + } +} diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromDimFetchAccessRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromDimFetchAccessRector.php index 0942ba3a4b0..3ad2384872f 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromDimFetchAccessRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockFromDimFetchAccessRector.php @@ -15,7 +15,7 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Comments\NodeDocBlock\DocBlockUpdater; use Rector\Rector\AbstractRector; -use Rector\TypeDeclarationDocblocks\NodeFinder\DimFetchFinder; +use Rector\TypeDeclarationDocblocks\NodeFinder\ArrayDimFetchFinder; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -26,7 +26,7 @@ final class AddParamArrayDocblockFromDimFetchAccessRector extends AbstractRector { public function __construct( private readonly PhpDocInfoFactory $phpDocInfoFactory, - private readonly DimFetchFinder $dimFetchFinder, + private readonly ArrayDimFetchFinder $arrayDimFetchFinder, private readonly DocBlockUpdater $docBlockUpdater ) { } @@ -109,7 +109,7 @@ public function refactor(Node $node): ?Node continue; } - $dimFetches = $this->dimFetchFinder->findByVariableName($node, $paramName); + $dimFetches = $this->arrayDimFetchFinder->findByVariableName($node, $paramName); if ($dimFetches === []) { continue; }