From 8f5239030e95bd481bb9a7a20dd65b85e6ee54c0 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Wed, 2 Sep 2026 22:45:21 +0200 Subject: [PATCH] [TypeDeclarationDocblocks] Limit ClassMethodArrayDocblockParamFromLocalCallsRector to private methods Only private methods have a closed set of local callers, so the inferred @param array type is safe. Public and protected methods can be called from outside the class, where the argument types are unknown. Claude-Session: https://claude.ai/code/session_01DCgCmqW1U7rcp5nuhXNtaC --- .../handle_non_final_protected.php.inc | 38 ---------------- ...le_non_final_protected_with_parent.php.inc | 42 ------------------ .../handle_protected_method_in_final.php.inc | 42 ------------------ .../Fixture/handle_public.php.inc | 44 ------------------- .../objects_overrule_empty_array.php.inc | 4 +- .../Fixture/skip_protected.php.inc | 17 +++++++ .../Fixture/skip_public.php.inc | 17 +++++++ .../Source/SafeParentClass.php | 7 --- ...ArrayDocblockParamFromLocalCallsRector.php | 16 ++----- .../UsefulArrayTagNodeAnalyzer.php | 2 +- 10 files changed, 40 insertions(+), 189 deletions(-) delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected_with_parent.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_protected_method_in_final.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_public.php.inc create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_protected.php.inc create mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_public.php.inc delete mode 100644 rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Source/SafeParentClass.php diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected.php.inc deleted file mode 100644 index 97c433b0dea..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected.php.inc +++ /dev/null @@ -1,38 +0,0 @@ -run(['item1', 'item2']); - } - - protected function run(array $items) - { - } -} - -?> ------ -run(['item1', 'item2']); - } - - /** - * @param string[] $items - */ - protected function run(array $items) - { - } -} - -?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected_with_parent.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected_with_parent.php.inc deleted file mode 100644 index 8b93297caec..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_non_final_protected_with_parent.php.inc +++ /dev/null @@ -1,42 +0,0 @@ -run(['item1', 'item2']); - } - - protected function run(array $items) - { - } -} - -?> ------ -run(['item1', 'item2']); - } - - /** - * @param string[] $items - */ - protected function run(array $items) - { - } -} - -?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_protected_method_in_final.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_protected_method_in_final.php.inc deleted file mode 100644 index 8c3477ee311..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_protected_method_in_final.php.inc +++ /dev/null @@ -1,42 +0,0 @@ -run([2512, 3423]); - - $this->run([324, 534]); - } - - protected function run(array $items) - { - } -} - -?> ------ -run([2512, 3423]); - - $this->run([324, 534]); - } - - /** - * @param int[] $items - */ - protected function run(array $items) - { - } -} - -?> diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_public.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_public.php.inc deleted file mode 100644 index 9976d430394..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/handle_public.php.inc +++ /dev/null @@ -1,44 +0,0 @@ -run([2512, 3423]); - - $this->run([324, 534]); - } - - public function run(array $items) - { - } -} - -?> - ------ -run([2512, 3423]); - - $this->run([324, 534]); - } - - /** - * @param int[] $items - */ - public function run(array $items) - { - } -} - -?> - diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/objects_overrule_empty_array.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/objects_overrule_empty_array.php.inc index bc0fdeeb75e..4506ed5584e 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/objects_overrule_empty_array.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/objects_overrule_empty_array.php.inc @@ -14,7 +14,7 @@ final class ObjectsOverruleEmptyArray $this->run($emptyArray); } - public function run(array $result) + private function run(array $result) { } @@ -56,7 +56,7 @@ final class ObjectsOverruleEmptyArray /** * @param \Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\ClassMethodArrayDocblockParamFromLocalCallsRector\Source\SomeReturnedObject[] $result */ - public function run(array $result) + private function run(array $result) { } diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_protected.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_protected.php.inc new file mode 100644 index 00000000000..78956e2e766 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_protected.php.inc @@ -0,0 +1,17 @@ +run([2512, 3423]); + + $this->run([324, 534]); + } + + protected function run(array $items) + { + } +} diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_public.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_public.php.inc new file mode 100644 index 00000000000..780e1b0b98d --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/skip_public.php.inc @@ -0,0 +1,17 @@ +run([2512, 3423]); + + $this->run([324, 534]); + } + + public function run(array $items) + { + } +} diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Source/SafeParentClass.php b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Source/SafeParentClass.php deleted file mode 100644 index a0ca61c08fc..00000000000 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Source/SafeParentClass.php +++ /dev/null @@ -1,7 +0,0 @@ -classMethodManipulator->hasParentMethodOrInterfaceMethod($node, $this->getName($classMethod))) { + // only private methods have a closed set of local callers; public/protected can be called from outside + if (! $classMethod->isPrivate()) { continue; } @@ -115,13 +112,6 @@ public function refactor(Node $node): ?Node continue; } - if ($parameterTagValueNode instanceof ParamTagValueNode - && $classMethod->isPublic() && - $this->usefulArrayTagNodeAnalyzer->isMixedArray($parameterTagValueNode->type)) { - // on public method, skip if there is mixed[], as caller can be anything - continue; - } - $resolvedParameterType = $classMethodParameterTypes[$parameterPosition] ?? $classMethodParameterTypes[$parameterName] ?? null; if (! $resolvedParameterType instanceof Type) { diff --git a/rules/TypeDeclarationDocblocks/TagNodeAnalyzer/UsefulArrayTagNodeAnalyzer.php b/rules/TypeDeclarationDocblocks/TagNodeAnalyzer/UsefulArrayTagNodeAnalyzer.php index 645c741ec80..23b945cca42 100644 --- a/rules/TypeDeclarationDocblocks/TagNodeAnalyzer/UsefulArrayTagNodeAnalyzer.php +++ b/rules/TypeDeclarationDocblocks/TagNodeAnalyzer/UsefulArrayTagNodeAnalyzer.php @@ -27,7 +27,7 @@ public function isUsefulArrayTag(null|ReturnTagValueNode|ParamTagValueNode|VarTa return ! in_array($type->name, ['array', 'mixed', 'iterable'], true); } - public function isMixedArray(TypeNode $typeNode): bool + private function isMixedArray(TypeNode $typeNode): bool { return $typeNode instanceof SpacingAwareArrayTypeNode && $typeNode->type instanceof IdentifierTypeNode && $typeNode->type->name === 'mixed'; }