From 12eb975b30ce6c9d7f7430a5bf56b5aeacf5fcfe Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 10 Aug 2026 21:03:24 +0200 Subject: [PATCH] [deprecation] Deprecate AddParamArrayDocblockBasedOnArrayMapRector, as a single array_map() call is a vague type source The rule reads the closure param type of one array_map() call inside the body and turns it into a @param docblock for the whole parameter. One call site does not prove what every caller passes, so the added type is often too narrow. Add the docblock manually instead. --- phpstan.neon | 1 + ...ArrayDocblockBasedOnArrayMapRectorTest.php | 28 ------ .../Fixture/override_bare_mixed.php.inc | 33 ------- .../Fixture/override_dummy_array.php.inc | 33 ------- .../Fixture/override_mixed_type.php.inc | 33 ------- .../Fixture/skip_better_existing_type.php.inc | 14 --- .../Fixture/some_class.php.inc | 30 ------ .../config/configured_rule.php | 9 -- .../NodeFinder/ArrayMapClosureExprFinder.php | 66 ------------- ...aramArrayDocblockBasedOnArrayMapRector.php | 97 ++----------------- .../Level/TypeDeclarationDocblocksLevel.php | 2 - 11 files changed, 9 insertions(+), 337 deletions(-) delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/AddParamArrayDocblockBasedOnArrayMapRectorTest.php delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_bare_mixed.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_dummy_array.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_mixed_type.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/skip_better_existing_type.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/some_class.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/config/configured_rule.php delete mode 100644 rules/TypeDeclarationDocblocks/NodeFinder/ArrayMapClosureExprFinder.php diff --git a/phpstan.neon b/phpstan.neon index 268e79a2ab6..bc725b29610 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -467,6 +467,7 @@ parameters: - '#Class "Rector\\CodeQuality\\Rector\\Switch_\\SwitchTrueToIfRector" is missing @see annotation with test case class reference#' - '#Class "Rector\\TypeDeclarationDocblocks\\Rector\\ClassMethod\\AddReturnDocblockForDimFetchArrayFromAssignsRector" is missing @see annotation with test case class reference#' - '#Class "Rector\\Assert\\Rector\\ClassMethod\\AddAssertArrayFromClassMethodDocblockRector" is missing @see annotation with test case class reference#' + - '#Class "Rector\\TypeDeclarationDocblocks\\Rector\\ClassMethod\\AddParamArrayDocblockBasedOnArrayMapRector" is missing @see annotation with test case class reference#' # @todo fix in phpstan-rules - diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/AddParamArrayDocblockBasedOnArrayMapRectorTest.php b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/AddParamArrayDocblockBasedOnArrayMapRectorTest.php deleted file mode 100644 index 14244050c09..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/AddParamArrayDocblockBasedOnArrayMapRectorTest.php +++ /dev/null @@ -1,28 +0,0 @@ -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/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_bare_mixed.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_bare_mixed.php.inc deleted file mode 100644 index c88c3b6b82f..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_bare_mixed.php.inc +++ /dev/null @@ -1,33 +0,0 @@ - trim($item), $items); - } -} - -?> ------ - trim($item), $items); - } -} - -?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_dummy_array.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_dummy_array.php.inc deleted file mode 100644 index 425af84cf8e..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_dummy_array.php.inc +++ /dev/null @@ -1,33 +0,0 @@ - trim($item), $items); - } -} - -?> ------ - trim($item), $items); - } -} - -?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_mixed_type.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_mixed_type.php.inc deleted file mode 100644 index 461858d30de..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/override_mixed_type.php.inc +++ /dev/null @@ -1,33 +0,0 @@ - trim($item), $items); - } -} - -?> ------ - trim($item), $items); - } -} - -?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/skip_better_existing_type.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/skip_better_existing_type.php.inc deleted file mode 100644 index 765fd64628f..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/skip_better_existing_type.php.inc +++ /dev/null @@ -1,14 +0,0 @@ - $items - */ - public function run(array $items): void - { - array_map(fn (string $item) => trim($item), $items); - } -} diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/some_class.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/some_class.php.inc deleted file mode 100644 index 14627faf497..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/Fixture/some_class.php.inc +++ /dev/null @@ -1,30 +0,0 @@ - trim($item), $items); - } -} - -?> ------ - trim($item), $items); - } -} - -?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/config/configured_rule.php b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/config/configured_rule.php deleted file mode 100644 index 8be29c33185..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector/config/configured_rule.php +++ /dev/null @@ -1,9 +0,0 @@ -withRules([AddParamArrayDocblockBasedOnArrayMapRector::class]); diff --git a/rules/TypeDeclarationDocblocks/NodeFinder/ArrayMapClosureExprFinder.php b/rules/TypeDeclarationDocblocks/NodeFinder/ArrayMapClosureExprFinder.php deleted file mode 100644 index 031f2a137f2..00000000000 --- a/rules/TypeDeclarationDocblocks/NodeFinder/ArrayMapClosureExprFinder.php +++ /dev/null @@ -1,66 +0,0 @@ - - */ - public function findByVariableName(ClassMethod|Function_ $functionLike, string $variableName): array - { - if ($functionLike->stmts === null) { - return []; - } - - /** @var FuncCall[] $funcCalls */ - $funcCalls = $this->betterNodeFinder->findInstancesOfScoped($functionLike->stmts, FuncCall::class); - - $arrayMapClosures = []; - - foreach ($funcCalls as $funcCall) { - if ($funcCall->isFirstClassCallable()) { - continue; - } - - if (! $this->nodeNameResolver->isName($funcCall, 'array_map')) { - continue; - } - - $secondArg = $funcCall->getArgs()[1]; - if (! $secondArg->value instanceof Variable) { - continue; - } - - if (! $this->nodeNameResolver->isName($secondArg->value, $variableName)) { - continue; - } - - $firstArg = $funcCall->getArgs()[0]; - if (! $firstArg->value instanceof Closure && ! $firstArg->value instanceof ArrowFunction) { - continue; - } - - $arrayMapClosures[] = $firstArg->value; - } - - return $arrayMapClosures; - } -} diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php index 9b6cf452a9e..1e9a091e404 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddParamArrayDocblockBasedOnArrayMapRector.php @@ -5,36 +5,19 @@ namespace Rector\TypeDeclarationDocblocks\Rector\ClassMethod; use PhpParser\Node; -use PhpParser\Node\Identifier; -use PhpParser\Node\Param; 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\Configuration\Deprecation\Contract\DeprecatedInterface; +use Rector\Exception\ShouldNotHappenException; use Rector\Rector\AbstractRector; -use Rector\StaticTypeMapper\StaticTypeMapper; -use Rector\TypeDeclarationDocblocks\NodeDocblockTypeDecorator; -use Rector\TypeDeclarationDocblocks\NodeFinder\ArrayMapClosureExprFinder; -use Rector\TypeDeclarationDocblocks\TagNodeAnalyzer\UsefulArrayTagNodeAnalyzer; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockBasedOnArrayMapRector\AddParamArrayDocblockBasedOnArrayMapRectorTest + * @deprecated This rule is deprecated, as a single array_map() closure only proves what one call site reads. The param type is vague and unreliable. Add the @param docblock manually instead. */ -final class AddParamArrayDocblockBasedOnArrayMapRector extends AbstractRector +final class AddParamArrayDocblockBasedOnArrayMapRector extends AbstractRector implements DeprecatedInterface { - public function __construct( - private readonly ArrayMapClosureExprFinder $arrayMapClosureExprFinder, - private readonly StaticTypeMapper $staticTypeMapper, - private readonly PhpDocInfoFactory $phpDocInfoFactory, - private readonly UsefulArrayTagNodeAnalyzer $usefulArrayTagNodeAnalyzer, - private readonly NodeDocblockTypeDecorator $nodeDocblockTypeDecorator - ) { - - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition('Add @param array docblock if array_map is used on the parameter', [ @@ -78,73 +61,9 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - if ($node->getParams() === []) { - return null; - } - - $hasChanged = false; - $functionPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); - - foreach ($node->params as $param) { - // handle only arrays - if (! $this->isArrayParam($param)) { - continue; - } - - $paramName = $this->getName($param); - - $arrayMapClosures = $this->arrayMapClosureExprFinder->findByVariableName($node, $paramName); - if ($arrayMapClosures === []) { - continue; - } - - foreach ($arrayMapClosures as $arrayMapClosure) { - $params = $arrayMapClosure->getParams(); - if ($params === []) { - continue; - } - - $firstParam = $params[0]; - $paramTypeNode = $firstParam->type; - if ($paramTypeNode === null) { - continue; - } - - if ($this->usefulArrayTagNodeAnalyzer->isUsefulArrayTag( - $functionPhpDocInfo->getParamTagValueByName($paramName) - )) { - continue; - } - - $paramType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($paramTypeNode); - $arrayParamType = new ArrayType(new MixedType(), $paramType); - - if ($this->nodeDocblockTypeDecorator->decorateGenericIterableParamType( - $arrayParamType, - $functionPhpDocInfo, - $node, - $param, - $paramName - )) { - $hasChanged = true; - } - } - - } - - if (! $hasChanged) { - return null; - } - - return $node; - } - - private function isArrayParam(Param $param): bool - { - if (! $param->type instanceof Identifier) { - return false; - } - - return $this->isName($param->type, 'array'); + throw new ShouldNotHappenException(sprintf( + '"%s" rule is deprecated, as the param type guessed from a single array_map() closure is vague and unreliable. Add the @param docblock manually instead', + self::class + )); } } diff --git a/src/Config/Level/TypeDeclarationDocblocksLevel.php b/src/Config/Level/TypeDeclarationDocblocksLevel.php index 49a5c45d39b..b9de49b8866 100644 --- a/src/Config/Level/TypeDeclarationDocblocksLevel.php +++ b/src/Config/Level/TypeDeclarationDocblocksLevel.php @@ -13,7 +13,6 @@ use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarArrayFromGetterReturnRector; use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarArrayFromPropertyDefaultsRector; use Rector\TypeDeclarationDocblocks\Rector\Class_\DocblockVarFromParamDocblockInConstructorRector; -use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockBasedOnArrayMapRector; use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockFromAssignsParamToParamReferenceRector; use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockFromDimFetchAccessRector; use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForArrayDimAssignedObjectRector; @@ -36,7 +35,6 @@ final class TypeDeclarationDocblocksLevel // param AddParamArrayDocblockFromDimFetchAccessRector::class, ClassMethodArrayDocblockParamFromLocalCallsRector::class, - AddParamArrayDocblockBasedOnArrayMapRector::class, AddParamArrayDocblockFromAssignsParamToParamReferenceRector::class, AddParamArrayDocblockBasedOnCallableNativeFuncCallRector::class,