From b48852450278959ccd374f93752f735fb86d6e09 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 20 Oct 2025 01:23:19 +0700 Subject: [PATCH 1/3] [TypeDeclaration] Skip Assert\Callback typed on ParamTypeByMethodCallTypeRector --- .../skip_in_form_builder_callback.php.inc | 37 +++++++++++++++++++ stubs/Symfony/Component/Form/AbstractType.php | 11 ++++++ .../Component/Form/FormBuilderInterface.php | 12 ++++++ .../Validator/Constraints/Callback.php | 31 ++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector/Fixture/skip_in_form_builder_callback.php.inc create mode 100644 stubs/Symfony/Component/Form/AbstractType.php create mode 100644 stubs/Symfony/Component/Form/FormBuilderInterface.php create mode 100644 stubs/Symfony/Component/Validator/Constraints/Callback.php diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector/Fixture/skip_in_form_builder_callback.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector/Fixture/skip_in_form_builder_callback.php.inc new file mode 100644 index 00000000000..fbc4f87df2c --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector/Fixture/skip_in_form_builder_callback.php.inc @@ -0,0 +1,37 @@ +add('someType', DocumentType::class, [ + 'class' => SomeType::class, + 'required' => false, + 'label' => 'Some Type', + 'attr' => [ + 'data-help' => 'some data help', + ], + 'constraints' => [ + new Assert\Callback(function ($someType, ExecutionContextInterface $context): void { + if ($someType === null) { + return; + } + + $this->use($someType); + + // some logic here + }) + ] + ]); + } + + private function use(SomeType $someType): void + { + } +} diff --git a/stubs/Symfony/Component/Form/AbstractType.php b/stubs/Symfony/Component/Form/AbstractType.php new file mode 100644 index 00000000000..436e31985a8 --- /dev/null +++ b/stubs/Symfony/Component/Form/AbstractType.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; + +if (class_exists('Symfony\Component\Validator\Constraints\Callback')) { + return; +} + +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class Callback +{ + /** + * @var string|callable + */ + public $callback; + + public function __construct(array|string|callable|null $callback = null, ?array $groups = null, mixed $payload = null, array $options = []) + { + } +} From 7c8037e0c7cff4b2a30538d3aceb114a744b9dbf Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 20 Oct 2025 01:25:50 +0700 Subject: [PATCH 2/3] clean up stubs --- .../Component/Validator/Constraints/Callback.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/stubs/Symfony/Component/Validator/Constraints/Callback.php b/stubs/Symfony/Component/Validator/Constraints/Callback.php index 7b128fb124a..2030470e21c 100644 --- a/stubs/Symfony/Component/Validator/Constraints/Callback.php +++ b/stubs/Symfony/Component/Validator/Constraints/Callback.php @@ -1,18 +1,7 @@ - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Validator\Constraint; - if (class_exists('Symfony\Component\Validator\Constraints\Callback')) { return; } From 3f309ec11545dbdbe4003b60f98ab07156be7657 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 20 Oct 2025 01:47:30 +0700 Subject: [PATCH 3/3] Fix --- rules/TypeDeclaration/NodeAnalyzer/CallerParamMatcher.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rules/TypeDeclaration/NodeAnalyzer/CallerParamMatcher.php b/rules/TypeDeclaration/NodeAnalyzer/CallerParamMatcher.php index d51f69eaa78..bd868569191 100644 --- a/rules/TypeDeclaration/NodeAnalyzer/CallerParamMatcher.php +++ b/rules/TypeDeclaration/NodeAnalyzer/CallerParamMatcher.php @@ -22,9 +22,11 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; use PHPStan\Type\MixedType; +use PHPStan\Type\Type; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\TypeComparator\TypeComparator; use Rector\PhpParser\AstResolver; +use Rector\PHPStan\ScopeFetcher; use Rector\StaticTypeMapper\StaticTypeMapper; final readonly class CallerParamMatcher @@ -120,6 +122,7 @@ private function matchCallArgPosition(StaticCall | MethodCall | FuncCall $call, { $paramName = $this->nodeNameResolver->getName($param); + $scope = ScopeFetcher::fetch($call); foreach ($call->args as $argPosition => $arg) { if (! $arg instanceof Arg) { continue; @@ -133,6 +136,11 @@ private function matchCallArgPosition(StaticCall | MethodCall | FuncCall $call, continue; } + $currentType = $scope->getType($arg->value); + if ($currentType instanceof MixedType && $currentType->getSubtractedType() instanceof Type) { + return null; + } + return $argPosition; }