From e0c5587c009ed50c6b97e2121c6a784ed0fafcbd Mon Sep 17 00:00:00 2001 From: fix-issue-bot Date: Tue, 2 Jun 2026 22:35:13 +0200 Subject: [PATCH 1/4] fix: keep nullability for params with default null value (fixes #9) --- .../AddClassMethodParamTypeRector.php | 14 +++++++++++ .../Function_/AddFunctionParamTypeRector.php | 14 ++++++++++- .../AddClassMethodParamTypeRectorTest.php | 8 ++++++ .../add_nullable_for_default_null.php.inc | 25 +++++++++++++++++++ .../AddFunctionParamTypeRectorTest.php | 5 ++++ .../Fixture/default_null_function.php.inc | 19 ++++++++++++++ 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/Fixture/add_nullable_for_default_null.php.inc create mode 100644 tests/Rector/Rector/Function_/AddFunctionParamTypeRector/Fixture/default_null_function.php.inc diff --git a/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php b/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php index 0a259cb2..ddc78e33 100644 --- a/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php +++ b/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php @@ -91,11 +91,16 @@ public function refactor(Node $node): ?Class_ continue; } +<<<<<<< HEAD // keep nullability if the param is already nullable or implicitly nullable via a null default, // otherwise the "?" would be dropped and the param would become implicitly nullable (deprecated) $isNullable = $classMethodType->isNullable() || $param->type instanceof NullableType || $this->hasNullDefault($param); +======= + // a null default value implies the type must stay nullable + $isNullable = $classMethodType->isNullable() || $this->hasDefaultNull($param); +>>>>>>> ab2bbf24 (fix: keep nullability for params with default null value (fixes #9)) $typeNode = TypeResolver::resolveTypeNode($classMethodType->getType()); if ($this->shouldSkipOverride($param, $classMethodType)) { @@ -178,4 +183,13 @@ private function shouldSkipOverride(Param $param, ClassMethodType $classMethodTy // skip already set object type return $classMethodType->isObjectType() && $rawType instanceof Name; } + + private function hasDefaultNull(Param $param): bool + { + if (! $param->default instanceof ConstFetch) { + return false; + } + + return $param->default->name->toLowerString() === 'null'; + } } diff --git a/src/Rector/Rector/Function_/AddFunctionParamTypeRector.php b/src/Rector/Rector/Function_/AddFunctionParamTypeRector.php index 7db7c8c7..b58277e5 100644 --- a/src/Rector/Rector/Function_/AddFunctionParamTypeRector.php +++ b/src/Rector/Rector/Function_/AddFunctionParamTypeRector.php @@ -5,8 +5,10 @@ namespace Rector\ArgTyper\Rector\Rector\Function_; use PhpParser\Node; +use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Name; use PhpParser\Node\NullableType; +use PhpParser\Node\Param; use PhpParser\Node\Stmt\Function_; use PHPStan\Type\NeverType; use PHPStan\Type\NullType; @@ -64,7 +66,8 @@ public function refactor(Node $node): ?Function_ continue; } - $isNullable = $paramFunctionType->isNullable(); + // a null default value implies the type must stay nullable + $isNullable = $paramFunctionType->isNullable() || $this->hasDefaultNull($param); $typeNode = TypeResolver::resolveTypeNode($paramFunctionType->getType()); if ($paramFunctionType->isObjectType() && ($param->type instanceof Name || ($param->type instanceof NullableType && $param->type->type instanceof Name))) { @@ -87,4 +90,13 @@ public function refactor(Node $node): ?Function_ return $node; } + + private function hasDefaultNull(Param $param): bool + { + if (! $param->default instanceof ConstFetch) { + return false; + } + + return $param->default->name->toLowerString() === 'null'; + } } diff --git a/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php b/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php index d637a5e6..650a75be 100644 --- a/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php +++ b/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php @@ -10,7 +10,11 @@ use PHPUnit\Framework\Attributes\DataProvider; use Rector\ArgTyper\Configuration\CallLikeTypesConfigurationProvider; use Rector\ArgTyper\Rector\ValueObject\ClassMethodType; +<<<<<<< HEAD use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\AddNullableScalarFromNullDefault; +======= +use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\AddNullableForDefaultNull; +>>>>>>> ab2bbf24 (fix: keep nullability for params with default null value (fixes #9)) use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\KeepDateTimeInterface; use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\KeepNullableDateTimeInterface; use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\KeepNullableScalarParam; @@ -35,8 +39,12 @@ public function test(string $filePath): void new ClassMethodType(KeepNullableDateTimeInterface::class, 'record', 0, 'object:' . \DateTime::class), new ClassMethodType(KeepDateTimeInterface::class, 'record', 0, 'object:' . \DateTime::class), new ClassMethodType(SkipIntToFloatOverride::class, 'passInteger', 0, IntegerType::class), +<<<<<<< HEAD new ClassMethodType(KeepNullableScalarParam::class, 'translate', 0, StringType::class), new ClassMethodType(AddNullableScalarFromNullDefault::class, 'translate', 0, StringType::class), +======= + new ClassMethodType(AddNullableForDefaultNull::class, 'run', 0, StringType::class), +>>>>>>> ab2bbf24 (fix: keep nullability for params with default null value (fixes #9)) ]; $callLikeTypesConfigurationProvider->seedClassMethodTypes($classMethodTypes); diff --git a/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/Fixture/add_nullable_for_default_null.php.inc b/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/Fixture/add_nullable_for_default_null.php.inc new file mode 100644 index 00000000..e6a45dec --- /dev/null +++ b/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/Fixture/add_nullable_for_default_null.php.inc @@ -0,0 +1,25 @@ + +----- + diff --git a/tests/Rector/Rector/Function_/AddFunctionParamTypeRector/AddFunctionParamTypeRectorTest.php b/tests/Rector/Rector/Function_/AddFunctionParamTypeRector/AddFunctionParamTypeRectorTest.php index e53eb5ba..7d57af80 100644 --- a/tests/Rector/Rector/Function_/AddFunctionParamTypeRector/AddFunctionParamTypeRectorTest.php +++ b/tests/Rector/Rector/Function_/AddFunctionParamTypeRector/AddFunctionParamTypeRectorTest.php @@ -28,6 +28,11 @@ public function test(string $filePath): void 0, StringType::class ), + new FuncCallType( + 'Rector\ArgTyper\Tests\Rector\Rector\Function_\AddFunctionParamTypeRector\Fixture\defaultNullFunction', + 0, + StringType::class + ), ]); $this->doTestFile($filePath); diff --git a/tests/Rector/Rector/Function_/AddFunctionParamTypeRector/Fixture/default_null_function.php.inc b/tests/Rector/Rector/Function_/AddFunctionParamTypeRector/Fixture/default_null_function.php.inc new file mode 100644 index 00000000..05f711cb --- /dev/null +++ b/tests/Rector/Rector/Function_/AddFunctionParamTypeRector/Fixture/default_null_function.php.inc @@ -0,0 +1,19 @@ + +----- + From 417c58970c1578ac5e92966193ed432ca66d06be Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 2 Jun 2026 22:47:54 +0200 Subject: [PATCH 2/4] fix: remove unused duplicate method and fix indentation, bump run-on-project to PHP 8.3 --- .github/workflows/run_on_project.yaml | 2 +- .../ClassMethod/AddClassMethodParamTypeRector.php | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/run_on_project.yaml b/.github/workflows/run_on_project.yaml index 941cd8a2..d3af9289 100644 --- a/.github/workflows/run_on_project.yaml +++ b/.github/workflows/run_on_project.yaml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - php_version: ['8.2'] + php_version: ['8.3'] steps: - diff --git a/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php b/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php index ddc78e33..e526e930 100644 --- a/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php +++ b/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php @@ -97,10 +97,14 @@ public function refactor(Node $node): ?Class_ $isNullable = $classMethodType->isNullable() || $param->type instanceof NullableType || $this->hasNullDefault($param); +<<<<<<< HEAD ======= // a null default value implies the type must stay nullable $isNullable = $classMethodType->isNullable() || $this->hasDefaultNull($param); >>>>>>> ab2bbf24 (fix: keep nullability for params with default null value (fixes #9)) +======= + +>>>>>>> f31ba540 (fix: remove unused duplicate method and fix indentation, bump run-on-project to PHP 8.3) $typeNode = TypeResolver::resolveTypeNode($classMethodType->getType()); if ($this->shouldSkipOverride($param, $classMethodType)) { @@ -183,13 +187,4 @@ private function shouldSkipOverride(Param $param, ClassMethodType $classMethodTy // skip already set object type return $classMethodType->isObjectType() && $rawType instanceof Name; } - - private function hasDefaultNull(Param $param): bool - { - if (! $param->default instanceof ConstFetch) { - return false; - } - - return $param->default->name->toLowerString() === 'null'; - } } From 41c27e6da9e0fea26bc2af865de2bac997fc4498 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 2 Jun 2026 22:50:31 +0200 Subject: [PATCH 3/4] ci: align run-on-project with main (symfony/console) and bump to PHP 8.4 --- .github/workflows/run_on_project.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run_on_project.yaml b/.github/workflows/run_on_project.yaml index d3af9289..61e2673a 100644 --- a/.github/workflows/run_on_project.yaml +++ b/.github/workflows/run_on_project.yaml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - php_version: ['8.3'] + php_version: ['8.4'] steps: - @@ -24,7 +24,11 @@ jobs: - run: composer require rector/argtyper --ansi +<<<<<<< HEAD # clone laravel project with dependencies +======= + # clone symfony/console project with dependencies +>>>>>>> ffae5424 (ci: align run-on-project with main (symfony/console) and bump to PHP 8.4) - run: git clone https://github.com/symfony/console.git --depth=1 - run: composer install --working-dir console --ansi From 9f9c64d947aa81ceb2b0dbc61219a61de416f097 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 2 Jun 2026 23:00:46 +0200 Subject: [PATCH 4/4] fix: resolve leftover merge conflict markers from rebase --- .github/workflows/run_on_project.yaml | 4 ---- .../ClassMethod/AddClassMethodParamTypeRector.php | 11 +---------- .../AddClassMethodParamTypeRectorTest.php | 10 ++-------- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/.github/workflows/run_on_project.yaml b/.github/workflows/run_on_project.yaml index 61e2673a..b9c25ed2 100644 --- a/.github/workflows/run_on_project.yaml +++ b/.github/workflows/run_on_project.yaml @@ -24,11 +24,7 @@ jobs: - run: composer require rector/argtyper --ansi -<<<<<<< HEAD - # clone laravel project with dependencies -======= # clone symfony/console project with dependencies ->>>>>>> ffae5424 (ci: align run-on-project with main (symfony/console) and bump to PHP 8.4) - run: git clone https://github.com/symfony/console.git --depth=1 - run: composer install --working-dir console --ansi diff --git a/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php b/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php index e526e930..28a79e90 100644 --- a/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php +++ b/src/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector.php @@ -91,20 +91,11 @@ public function refactor(Node $node): ?Class_ continue; } -<<<<<<< HEAD - // keep nullability if the param is already nullable or implicitly nullable via a null default, - // otherwise the "?" would be dropped and the param would become implicitly nullable (deprecated) + // a null default value implies the type must stay nullable $isNullable = $classMethodType->isNullable() || $param->type instanceof NullableType || $this->hasNullDefault($param); -<<<<<<< HEAD -======= - // a null default value implies the type must stay nullable - $isNullable = $classMethodType->isNullable() || $this->hasDefaultNull($param); ->>>>>>> ab2bbf24 (fix: keep nullability for params with default null value (fixes #9)) -======= ->>>>>>> f31ba540 (fix: remove unused duplicate method and fix indentation, bump run-on-project to PHP 8.3) $typeNode = TypeResolver::resolveTypeNode($classMethodType->getType()); if ($this->shouldSkipOverride($param, $classMethodType)) { diff --git a/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php b/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php index 650a75be..1dfaa04f 100644 --- a/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php +++ b/tests/Rector/Rector/ClassMethod/AddClassMethodParamTypeRector/AddClassMethodParamTypeRectorTest.php @@ -10,11 +10,8 @@ use PHPUnit\Framework\Attributes\DataProvider; use Rector\ArgTyper\Configuration\CallLikeTypesConfigurationProvider; use Rector\ArgTyper\Rector\ValueObject\ClassMethodType; -<<<<<<< HEAD -use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\AddNullableScalarFromNullDefault; -======= use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\AddNullableForDefaultNull; ->>>>>>> ab2bbf24 (fix: keep nullability for params with default null value (fixes #9)) +use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\AddNullableScalarFromNullDefault; use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\KeepDateTimeInterface; use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\KeepNullableDateTimeInterface; use Rector\ArgTyper\Tests\Rector\Rector\ClassMethod\AddClassMethodParamTypeRector\Fixture\KeepNullableScalarParam; @@ -39,12 +36,9 @@ public function test(string $filePath): void new ClassMethodType(KeepNullableDateTimeInterface::class, 'record', 0, 'object:' . \DateTime::class), new ClassMethodType(KeepDateTimeInterface::class, 'record', 0, 'object:' . \DateTime::class), new ClassMethodType(SkipIntToFloatOverride::class, 'passInteger', 0, IntegerType::class), -<<<<<<< HEAD + new ClassMethodType(AddNullableForDefaultNull::class, 'run', 0, StringType::class), new ClassMethodType(KeepNullableScalarParam::class, 'translate', 0, StringType::class), new ClassMethodType(AddNullableScalarFromNullDefault::class, 'translate', 0, StringType::class), -======= - new ClassMethodType(AddNullableForDefaultNull::class, 'run', 0, StringType::class), ->>>>>>> ab2bbf24 (fix: keep nullability for params with default null value (fixes #9)) ]; $callLikeTypesConfigurationProvider->seedClassMethodTypes($classMethodTypes);