From 17eb5f4209c2798b51a5d0726df5b6d2b78ff0f8 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 8 Dec 2025 13:00:34 +0100 Subject: [PATCH 1/2] [coding-style] Decouple ArrowFunctionToFirstClassCallableRector to allow step-by-step upgrade --- config/set/php81.php | 4 + ...FunctionToFirstClassCallableRectorTest.php | 28 ++ .../Fixture/array_map.php.inc | 51 ++++ ...th_in_method_doc_and_native_method.php.inc | 6 +- .../Fixture/fixture.php.inc | 19 ++ .../Fixture/multiple_params.php.inc | 4 +- .../Fixture/skip_assigned_early.php.inc | 2 +- .../skip_call_dependency_on_arg.php.inc | 5 + ...assign_with_signature_multi_params.php.inc | 2 +- .../Fixture/skip_callable_param_union.php.inc | 16 ++ .../Fixture/skip_chained_calls.php.inc | 2 +- .../Fixture/skip_closure_bind_to.php.inc | 2 +- ...functions_with_too_many_statements.php.inc | 2 +- .../skip_functions_without_calls.php.inc | 12 + .../skip_mismatched_args_and_params.php.inc | 21 ++ .../Fixture/skip_multi_param.php.inc | 4 +- .../Fixture/skip_no_args_passed.php.inc | 17 ++ .../Fixture/skip_null_variable_call.php.inc | 12 + .../skip_param_used_as_invokable.php.inc | 2 +- ...p_param_used_as_invokable_from_new.php.inc | 2 +- ...skip_target_method_from_method_doc.php.inc | 2 +- ...ip_target_native_method_not_exists.php.inc | 2 +- .../skip_using_this_outside_object.php.inc | 2 +- .../skip_variadic_in_array_all.php.inc | 2 +- .../supports_variadic_and_unpack.php.inc | 19 ++ .../using_this_in_instance_method.php.inc | 4 +- .../Source/FooBar.php | 14 + .../Source/SomeCacheInterface.php | 5 +- .../config/configured_rule.php | 9 + .../ArrowFunction/skip_no_args_passed.php.inc | 17 -- .../Fixture/array_map.php.inc | 27 -- .../Fixture/fixture.php.inc | 4 - .../Fixture/skip_callable_param_union.php.inc | 16 -- .../skip_functions_without_calls.php.inc | 4 - .../skip_mismatched_args_and_params.php.inc | 6 - .../Fixture/skip_null_variable_call.php.inc | 2 - .../Fixture/with_trailing_comma.php.inc | 41 --- ...ctionAndClosureFirstClassCallableGuard.php | 241 ++++++++++++++++++ ...rrowFunctionToFirstClassCallableRector.php | 90 +++++++ .../SimpleCallableNodeTraverser.php | 15 +- 40 files changed, 595 insertions(+), 140 deletions(-) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.php create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/array_map.php.inc rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/exists_both_in_method_doc_and_native_method.php.inc (75%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/multiple_params.php.inc (56%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_assigned_early.php.inc (81%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc (84%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_callable_param_union.php.inc rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_chained_calls.php.inc (50%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_closure_bind_to.php.inc (79%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_functions_with_too_many_statements.php.inc (66%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_multi_param.php.inc (83%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_param_used_as_invokable.php.inc (79%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_param_used_as_invokable_from_new.php.inc (78%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_target_method_from_method_doc.php.inc (69%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_target_native_method_not_exists.php.inc (65%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_using_this_outside_object.php.inc (73%) rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/skip_variadic_in_array_all.php.inc (78%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Fixture/using_this_in_instance_method.php.inc (66%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Source/FooBar.php rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector => ArrowFunction/ArrowFunctionToFirstClassCallableRector}/Source/SomeCacheInterface.php (61%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/config/configured_rule.php delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/ArrowFunction/skip_no_args_passed.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/array_map.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_callable_param_union.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/with_trailing_comma.php.inc create mode 100644 rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php create mode 100644 rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector.php diff --git a/config/set/php81.php b/config/set/php81.php index 4ec7f14cd08..5cebb809ea2 100644 --- a/config/set/php81.php +++ b/config/set/php81.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionToFirstClassCallableRector; use Rector\CodingStyle\Rector\FuncCall\ClosureFromCallableToFirstClassCallableRector; use Rector\CodingStyle\Rector\FuncCall\FunctionFirstClassCallableRector; use Rector\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassCallableRector; @@ -32,7 +33,10 @@ NullToStrictIntPregSlitFuncCallLimitArgRector::class, // array of local method call ArrayToFirstClassCallableRector::class, + // closure/arrow function + ArrowFunctionToFirstClassCallableRector::class, + FunctionLikeToFirstClassCallableRector::class, ClosureFromCallableToFirstClassCallableRector::class, FunctionFirstClassCallableRector::class, diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.php b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.php new file mode 100644 index 00000000000..cb44307af4c --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.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/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/array_map.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/array_map.php.inc new file mode 100644 index 00000000000..f1a9810ce63 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/array_map.php.inc @@ -0,0 +1,51 @@ + strlen($x), $items); + } + + public function run(): void + { + $array = [1, 2, 3]; + + array_map( + fn($item) => var_dump( + $item, + ), + $array + ); + } +} + +?> +----- + diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc similarity index 75% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc index 050f68d8db1..32ebe7e0798 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc @@ -1,6 +1,6 @@ \ No newline at end of file +?> diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..7276f365a3f --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc @@ -0,0 +1,19 @@ + FooBar::foo($foo); + +?> +----- + diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/multiple_params.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/multiple_params.php.inc similarity index 56% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/multiple_params.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/multiple_params.php.inc index 7a1c1c897d7..9399ed4a961 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/multiple_params.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/multiple_params.php.inc @@ -1,6 +1,6 @@ $foo->foo(); diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc similarity index 84% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc index d6cad61df0c..579061a7e9a 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc @@ -1,6 +1,6 @@ cache->get('bar', fn() => time()); + } +} diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc similarity index 50% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc index 6f97a27cede..4fe00396bd3 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc @@ -1,6 +1,6 @@ $foo; + +?> diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc new file mode 100644 index 00000000000..3c4986da129 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc @@ -0,0 +1,21 @@ + FooBar::foo($bar, $foo); + +$bar = null; + +fn ($foo, $bar) => $bar->foo($bar, $foo); + +function ($foo, $barFoo) use ($bar) +{ + return $bar->foo($barFoo, $foo); +}; + +?> diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_multi_param.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_multi_param.php.inc similarity index 83% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_multi_param.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_multi_param.php.inc index d15ee32e559..6147408e724 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_multi_param.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_multi_param.php.inc @@ -1,6 +1,6 @@ fn ($foo) => FooBar::optionalArgs() + ]; + + return $data; + } +} diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc new file mode 100644 index 00000000000..f94d7e1ec5f --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc @@ -0,0 +1,12 @@ + $bar->foo($foo); + +function ($foo) use ($bar) +{ + return $bar->foo($foo); +}; diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc similarity index 79% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc index 381d53d883a..9960a1bfbff 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc @@ -1,6 +1,6 @@ FooBar::foo(...$foo); + +?> +----- + diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc similarity index 66% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc index 8ba70f768d3..d0090e3cb6c 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc @@ -1,6 +1,6 @@ withRules([ArrowFunctionToFirstClassCallableRector::class]); diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/ArrowFunction/skip_no_args_passed.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/ArrowFunction/skip_no_args_passed.php.inc deleted file mode 100644 index 57e446ddc66..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/ArrowFunction/skip_no_args_passed.php.inc +++ /dev/null @@ -1,17 +0,0 @@ - fn ($foo) => FooBar::optionalArgs() - ]; - - return $data; - } -} diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/array_map.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/array_map.php.inc deleted file mode 100644 index 199f05c1b53..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/array_map.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - strlen($x), $items); - } -} - -?> ------ - diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc index edbc2736abc..9d87e43dd9e 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc +++ b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc @@ -9,8 +9,6 @@ function ($foo) return FooBar::foo($foo); }; -fn ($foo) => FooBar::foo($foo); - ?> ----- diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_callable_param_union.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_callable_param_union.php.inc deleted file mode 100644 index 5d3b3e485ce..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_callable_param_union.php.inc +++ /dev/null @@ -1,16 +0,0 @@ -cache->get('bar', fn() => time()); - } -} diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc index f4d0f780fab..e3f60adff77 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc +++ b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc @@ -6,7 +6,3 @@ function ($foo) { return $foo; }; - -fn ($foo) => $foo; - -?> diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc index d7b5d0b6314..0ec85c6e9a2 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc +++ b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc @@ -7,15 +7,9 @@ function ($foo, $bar) return FooBar::foo($bar, $foo); }; -fn ($foo, $bar) => FooBar::foo($bar, $foo); - $bar = null; -fn ($foo, $bar) => $bar->foo($bar, $foo); - function ($foo, $barFoo) use ($bar) { return $bar->foo($barFoo, $foo); }; - -?> diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc index 4a877680162..a5c35732bcb 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc +++ b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc @@ -4,8 +4,6 @@ namespace Rector\Tests\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassC $bar = null; -fn ($foo) => $bar->foo($foo); - function ($foo) use ($bar) { return $bar->foo($foo); diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/with_trailing_comma.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/with_trailing_comma.php.inc deleted file mode 100644 index a488b915937..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/with_trailing_comma.php.inc +++ /dev/null @@ -1,41 +0,0 @@ - var_dump( - $item, - ), - $array - ); - } -} - -?> ------ - diff --git a/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php b/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php new file mode 100644 index 00000000000..5f093a6e3ca --- /dev/null +++ b/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php @@ -0,0 +1,241 @@ +isFirstClassCallable()) { + return true; + } + + // use cheap checks first + if ($arrowFunctionOrClosure->getAttribute(AttributeKey::HAS_CLOSURE_WITH_VARIADIC_ARGS) === true) { + return true; + } + + if ($arrowFunctionOrClosure->getAttribute( + AttributeKey::IS_ASSIGNED_TO + ) === true || $arrowFunctionOrClosure->getAttribute(AttributeKey::IS_BEING_ASSIGNED)) { + return true; + } + + $params = $arrowFunctionOrClosure->getParams(); + + if (count($params) !== count($callLike->getArgs())) { + return true; + } + + $args = $callLike->getArgs(); + if ($this->isChainedCall($callLike)) { + return true; + } + + if ($this->isUsingNamedArgs($args)) { + return true; + } + + if ($this->isUsingByRef($params)) { + return true; + } + + if ($this->isNotUsingSameParamsForArgs($params, $args)) { + return true; + } + + if ($this->isDependantMethod($callLike, $params)) { + return true; + } + + if ($this->isUsingThisInNonObjectContext($callLike, $scope)) { + return true; + } + + $reflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($callLike); + + // does not exists, probably by magic method + if ($reflection === null) { + return true; + } + + // exists, but by @method annotation + if ($reflection instanceof AnnotationMethodReflection && ! $reflection->getDeclaringClass()->hasNativeMethod( + $reflection->getName() + )) { + return true; + } + + $functionLike = $this->astResolver->resolveClassMethodOrFunctionFromCall($callLike); + if (! $functionLike instanceof FunctionLike) { + return false; + } + + return count($functionLike->getParams()) > 1; + } + + /** + * @param Param[] $params + */ + private function isDependantMethod(StaticCall|MethodCall|FuncCall $expr, array $params): bool + { + if ($expr instanceof FuncCall) { + return false; + } + + $found = false; + $parentNode = $expr instanceof MethodCall ? $expr->var : $expr->class; + + foreach ($params as $param) { + SimpleCallableNodeTraverser::traverse($parentNode, function (Node $node) use ($param, &$found) { + if ($this->nodeComparator->areNodesEqual($node, $param->var)) { + $found = true; + return NodeVisitor::STOP_TRAVERSAL; + } + + return null; + }); + + if ($found) { + return true; + } + } + + return false; + } + + private function isUsingThisInNonObjectContext(FuncCall|MethodCall|StaticCall $callLike, Scope $scope): bool + { + if (! $callLike instanceof MethodCall) { + return false; + } + + if (in_array('this', $scope->getDefinedVariables(), true)) { + return false; + } + + $found = false; + + SimpleCallableNodeTraverser::traverse($callLike, function (Node $node) use (&$found) { + if ($this->nodeNameResolver->isName($node, 'this')) { + $found = true; + return NodeVisitor::STOP_TRAVERSAL; + } + + return null; + }); + + return $found; + } + + /** + * @param Param[] $params + */ + private function isUsingByRef(array $params): bool + { + foreach ($params as $param) { + if ($param->byRef) { + return true; + } + } + + return false; + } + + /** + * @param Arg[] $args + */ + private function isUsingNamedArgs(array $args): bool + { + foreach ($args as $arg) { + if ($arg->name instanceof Identifier) { + return true; + } + } + + return false; + } + + private function isChainedCall(FuncCall|MethodCall|StaticCall $callLike): bool + { + if (! $callLike instanceof MethodCall) { + return false; + } + + return $callLike->var instanceof CallLike; + } + + /** + * @param Param[] $params + * @param Arg[] $args + */ + private function isNotUsingSameParamsForArgs(array $params, array $args): bool + { + if (count($args) > count($params)) { + return true; + } + + if (count($args) === 1 && $args[0]->unpack) { + return ! $params[0]->variadic; + } + + foreach ($args as $key => $arg) { + if (! $this->nodeComparator->areNodesEqual($arg->value, $params[$key]->var)) { + return true; + } + + if (! $arg->value instanceof Variable) { + continue; + } + + $variableName = (string) $this->nodeNameResolver->getName($arg->value); + + foreach ($params as $param) { + if ($param->var instanceof Variable + && $this->nodeNameResolver->isName($param->var, $variableName) + && $param->variadic + && ! $arg->unpack) { + return true; + } + } + } + + return false; + } +} diff --git a/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector.php b/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector.php new file mode 100644 index 00000000000..87cd1c7a0c8 --- /dev/null +++ b/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector.php @@ -0,0 +1,90 @@ + Call::to($parameter); +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +Call::to(...); +CODE_SAMPLE + , + )] + ); + } + + public function getNodeTypes(): array + { + return [ArrowFunction::class]; + } + + /** + * @param ArrowFunction $node + */ + public function refactor(Node $node): null|CallLike + { + if (! $node->expr instanceof FuncCall && ! $node->expr instanceof MethodCall && ! $node->expr instanceof StaticCall) { + return null; + } + + $callLike = $node->expr; + + // dynamic name? skip + if ($callLike->name instanceof Expr) { + return null; + } + + if ($this->arrowFunctionAndCLosureFirstClassCallableGuard->shouldSkip( + $node, + $callLike, + ScopeFetcher::fetch($node) + )) { + return null; + } + + // turn into first class callable + $callLike->args = [new VariadicPlaceholder()]; + + return $callLike; + } + + public function provideMinPhpVersion(): int + { + return PhpVersionFeature::FIRST_CLASS_CALLABLE_SYNTAX; + } +} diff --git a/src/PhpDocParser/NodeTraverser/SimpleCallableNodeTraverser.php b/src/PhpDocParser/NodeTraverser/SimpleCallableNodeTraverser.php index 667659bb9df..1c19421e2e2 100644 --- a/src/PhpDocParser/NodeTraverser/SimpleCallableNodeTraverser.php +++ b/src/PhpDocParser/NodeTraverser/SimpleCallableNodeTraverser.php @@ -14,10 +14,21 @@ final class SimpleCallableNodeTraverser { /** - * @param callable(Node): (int|Node|null|Node[]) $callable * @param Node|Node[]|null $node + * + * @param callable(Node $node): (int|Node|null|Node[]) $callable + * @api shortcut helper */ - public function traverseNodesWithCallable(Node | array | null $node, callable $callable): void + public static function traverse(Node | array | null $node, callable $callable): void + { + self::traverseNodesWithCallable($node, $callable); + } + + /** + * @param callable(Node $node): (int|Node|null|Node[]) $callable + * @param Node|Node[]|null $node + */ + public static function traverseNodesWithCallable(Node | array | null $node, callable $callable): void { if ($node === null || $node === []) { return; From 1b8206ae32d3591aca053401c60aebc19a0907dc Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 8 Dec 2025 13:24:56 +0100 Subject: [PATCH 2/2] decouple ClosureDelegatingCallToFirstClassCallableRector, deprecate FunctionLikeToFirstClassCallableRector as split into 2 rules now --- config/set/php81.php | 10 +- ...ingCallToFirstClassCallableRectorTest.php} | 4 +- .../Fixture/array_map.php.inc | 4 +- ...th_in_method_doc_and_native_method.php.inc | 4 +- .../Fixture/multiple_params.php.inc | 4 +- .../Fixture/simple_call.php.inc | 31 ++ .../Fixture/skip_assigned_early.php.inc | 2 +- .../skip_call_dependency_on_arg.php.inc | 11 + ...assign_with_signature_multi_params.php.inc | 2 +- .../Fixture/skip_callable_param_union.php.inc | 4 +- .../Fixture/skip_chained_calls.php.inc | 16 + .../Fixture/skip_closure_bind_to.php.inc | 2 +- ...functions_with_too_many_statements.php.inc | 2 +- .../skip_mismatched_args_and_params.php.inc | 2 +- .../Fixture/skip_multi_param.php.inc | 26 ++ .../Fixture/skip_no_args_passed.php.inc | 4 +- .../Fixture/skip_null_variable_call.php.inc | 18 ++ .../skip_param_used_as_invokable.php.inc | 2 +- ...p_param_used_as_invokable_from_new.php.inc | 2 +- ...skip_target_method_from_method_doc.php.inc | 2 +- ...ip_target_native_method_not_exists.php.inc | 2 +- .../skip_using_this_outside_object.php.inc | 2 +- .../skip_variadic_in_array_all.php.inc | 2 +- .../supports_variadic_and_unpack.php.inc | 19 ++ .../using_this_in_instance_method.php.inc | 4 +- .../Source/FooBar.php | 2 +- .../Source/SomeCacheInterface.php | 6 +- .../config/configured_rule.php | 11 + .../Fixture/fixture.php.inc | 19 -- .../skip_call_dependency_on_arg.php.inc | 5 - .../Fixture/skip_chained_calls.php.inc | 10 - .../skip_functions_without_calls.php.inc | 12 - .../Fixture/skip_multi_param.php.inc | 20 -- .../Fixture/skip_null_variable_call.php.inc | 12 - .../supports_variadic_and_unpack.php.inc | 19 -- .../config/configured_rule.php | 9 - .../skip_any_call_like_with_args.php.inc | 2 +- .../Fixture/two_bare_getters.php.inc | 4 +- .../Source/SomeGetter.php | 2 +- ...ingCallToFirstClassCallableRectorTest.php} | 4 +- .../Fixture/another_simple_call.php.inc | 34 +++ .../skip_already_first_class_callable.php.inc | 12 + .../Fixture/skip_byref_usage.php.inc | 14 + .../skip_call_dependency_on_arg.php.inc | 29 ++ .../skip_functions_with_no_return.php.inc | 21 ++ .../skip_functions_without_calls.php.inc | 8 + .../skip_mismatched_args_and_params.php.inc | 21 ++ .../Fixture/skip_named_args.php.inc | 19 ++ .../Fixture/skip_null_variable_call.php.inc | 16 + .../skip_used_by_caller_variable.php.inc | 16 + .../Fixture/skip_variadic.php.inc | 16 + .../supports_variadic_and_unpack.php.inc | 34 +++ .../Source/SomeClassWithArgs.php | 14 + .../config/configured_rule.php | 11 + .../Fixture/fixture.php.inc | 22 -- .../skip_already_first_class_callable.php.inc | 5 - .../Fixture/skip_byref_usage.php.inc | 10 - .../skip_call_dependency_on_arg.php.inc | 27 -- .../skip_functions_with_no_return.php.inc | 17 -- .../skip_functions_without_calls.php.inc | 8 - .../skip_mismatched_args_and_params.php.inc | 15 - .../Fixture/skip_named_args.php.inc | 17 -- .../Fixture/skip_null_variable_call.php.inc | 10 - .../skip_used_by_caller_variable.php.inc | 12 - .../Fixture/skip_variadic.php.inc | 9 - .../supports_variadic_and_unpack.php.inc | 26 -- .../Source/FooBar.php | 14 - .../config/configured_rule.php | 9 - ...ctionAndClosureFirstClassCallableGuard.php | 14 +- ...egatingCallToFirstClassCallableRector.php} | 5 +- ...legatingCallToFirstClassCallableRector.php | 97 +++++++ ...FunctionLikeToFirstClassCallableRector.php | 274 +----------------- 72 files changed, 557 insertions(+), 617 deletions(-) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.php => ArrowFunctionDelegatingCallToFirstClassCallableRector/ArrowFunctionDelegatingCallToFirstClassCallableRectorTest.php} (80%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/array_map.php.inc (87%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/exists_both_in_method_doc_and_native_method.php.inc (87%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/multiple_params.php.inc (78%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/simple_call.php.inc rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_assigned_early.php.inc (90%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc (92%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_callable_param_union.php.inc (60%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_closure_bind_to.php.inc (89%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_functions_with_too_many_statements.php.inc (83%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_mismatched_args_and_params.php.inc (85%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_multi_param.php.inc rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_no_args_passed.php.inc (59%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_param_used_as_invokable.php.inc (89%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_param_used_as_invokable_from_new.php.inc (89%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_target_method_from_method_doc.php.inc (84%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_target_native_method_not_exists.php.inc (82%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_using_this_outside_object.php.inc (86%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/skip_variadic_in_array_all.php.inc (89%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Fixture/using_this_in_instance_method.php.inc (83%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Source/FooBar.php (79%) rename rules-tests/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector => ArrowFunctionDelegatingCallToFirstClassCallableRector}/Source/SomeCacheInterface.php (59%) create mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/config/configured_rule.php delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_multi_param.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/config/configured_rule.php rename rules-tests/CodingStyle/Rector/{FunctionLike/FunctionLikeToFirstClassCallableRector/FunctionLikeToFirstClassCallableRectorTest.php => Closure/ClosureDelegatingCallToFirstClassCallableRector/ClosureDelegatingCallToFirstClassCallableRectorTest.php} (73%) create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/another_simple_call.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_byref_usage.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_named_args.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_variadic.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Source/SomeClassWithArgs.php create mode 100644 rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/config/configured_rule.php delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_byref_usage.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_mismatched_args_and_params.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_named_args.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_variadic.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Source/FooBar.php delete mode 100644 rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/config/configured_rule.php rename rules/CodingStyle/Rector/ArrowFunction/{ArrowFunctionToFirstClassCallableRector.php => ArrowFunctionDelegatingCallToFirstClassCallableRector.php} (91%) create mode 100644 rules/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector.php diff --git a/config/set/php81.php b/config/set/php81.php index 5cebb809ea2..d73299ea7da 100644 --- a/config/set/php81.php +++ b/config/set/php81.php @@ -2,10 +2,10 @@ declare(strict_types=1); -use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionToFirstClassCallableRector; +use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector; +use Rector\CodingStyle\Rector\Closure\ClosureDelegatingCallToFirstClassCallableRector; use Rector\CodingStyle\Rector\FuncCall\ClosureFromCallableToFirstClassCallableRector; use Rector\CodingStyle\Rector\FuncCall\FunctionFirstClassCallableRector; -use Rector\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassCallableRector; use Rector\Config\RectorConfig; use Rector\Php81\Rector\Array_\ArrayToFirstClassCallableRector; use Rector\Php81\Rector\Class_\MyCLabsClassToEnumRector; @@ -31,13 +31,13 @@ SpatieEnumMethodCallToEnumConstRector::class, NullToStrictStringFuncCallArgRector::class, NullToStrictIntPregSlitFuncCallLimitArgRector::class, - // array of local method call + ArrayToFirstClassCallableRector::class, // closure/arrow function - ArrowFunctionToFirstClassCallableRector::class, + ArrowFunctionDelegatingCallToFirstClassCallableRector::class, + ClosureDelegatingCallToFirstClassCallableRector::class, - FunctionLikeToFirstClassCallableRector::class, ClosureFromCallableToFirstClassCallableRector::class, FunctionFirstClassCallableRector::class, RemoveReflectionSetAccessibleCallsRector::class, diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.php b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/ArrowFunctionDelegatingCallToFirstClassCallableRectorTest.php similarity index 80% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.php rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/ArrowFunctionDelegatingCallToFirstClassCallableRectorTest.php index cb44307af4c..ed1a47462d3 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/ArrowFunctionToFirstClassCallableRectorTest.php +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/ArrowFunctionDelegatingCallToFirstClassCallableRectorTest.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Rector\Tests\CodingStyle\Rector\ArrowFunction\ArrowFunctionToFirstClassCallableRector; +namespace Rector\Tests\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector; use Iterator; use PHPUnit\Framework\Attributes\DataProvider; use Rector\Testing\PHPUnit\AbstractRectorTestCase; -final class ArrowFunctionToFirstClassCallableRectorTest extends AbstractRectorTestCase +final class ArrowFunctionDelegatingCallToFirstClassCallableRectorTest extends AbstractRectorTestCase { #[DataProvider('provideData')] public function test(string $filePath): void diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/array_map.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/array_map.php.inc similarity index 87% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/array_map.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/array_map.php.inc index f1a9810ce63..07810412f6a 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/array_map.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/array_map.php.inc @@ -1,6 +1,6 @@ FooBar::foo($foo); + } +} + +?> +----- + diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc similarity index 90% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc index 72684ba3b06..6de70a4eb9f 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc @@ -1,6 +1,6 @@ $foo->foo(); + } +} diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc similarity index 92% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc index 579061a7e9a..ea5c129f6b0 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc @@ -1,6 +1,6 @@ bar($foo); + }; + + fn ($foo) => FooBar::foo()->bar($foo); + } +} diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc similarity index 89% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc index dba8a3fe28e..f916c7e2496 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc @@ -1,6 +1,6 @@ makeInstance($className), + $items + ); + + // This FAILS - first-class callable receives BOTH value and key + // array_map passes: $className (string) and $key (int) + // But makeInstance expects: $className (string) and $options (array) + $result2 = array_map(makeInstance(...), $items, array_keys($items)); + // TypeError: makeInstance(): Argument #2 ($options) must be of type array, int give + } +} diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc similarity index 59% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc index f1cfdcd0889..3a68a124673 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc @@ -1,8 +1,8 @@ $bar->foo($foo); + + function ($foo) use ($bar) + { + return $bar->foo($foo); + }; + } +} diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc similarity index 89% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc index 9960a1bfbff..e4308825bed 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc @@ -1,6 +1,6 @@ FooBar::foo(...$foo); + +?> +----- + diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc similarity index 83% rename from rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc index d0090e3cb6c..52dc2d966cb 100644 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/using_this_in_instance_method.php.inc @@ -1,6 +1,6 @@ withRules([ArrowFunctionDelegatingCallToFirstClassCallableRector::class]) + ->withPhpVersion(PhpVersionFeature::FIRST_CLASS_CALLABLE_SYNTAX); diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc deleted file mode 100644 index 7276f365a3f..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/fixture.php.inc +++ /dev/null @@ -1,19 +0,0 @@ - FooBar::foo($foo); - -?> ------ - diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc deleted file mode 100644 index 70b7c8ef923..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc +++ /dev/null @@ -1,5 +0,0 @@ - $foo->foo(); diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc deleted file mode 100644 index 4fe00396bd3..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc +++ /dev/null @@ -1,10 +0,0 @@ -bar($foo); -}; - -fn ($foo) => FooBar::foo()->bar($foo); diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc deleted file mode 100644 index cb8d924b7ea..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc +++ /dev/null @@ -1,12 +0,0 @@ - $foo; - -?> diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_multi_param.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_multi_param.php.inc deleted file mode 100644 index 6147408e724..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_multi_param.php.inc +++ /dev/null @@ -1,20 +0,0 @@ - makeInstance($className), - $items -); - -// This FAILS - first-class callable receives BOTH value and key -// array_map passes: $className (string) and $key (int) -// But makeInstance expects: $className (string) and $options (array) -$result2 = array_map(makeInstance(...), $items, array_keys($items)); -// TypeError: makeInstance(): Argument #2 ($options) must be of type array, int give diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc deleted file mode 100644 index f94d7e1ec5f..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc +++ /dev/null @@ -1,12 +0,0 @@ - $bar->foo($foo); - -function ($foo) use ($bar) -{ - return $bar->foo($foo); -}; diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc deleted file mode 100644 index 5f372f8297c..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/Fixture/supports_variadic_and_unpack.php.inc +++ /dev/null @@ -1,19 +0,0 @@ - FooBar::foo(...$foo); - -?> ------ - diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/config/configured_rule.php b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/config/configured_rule.php deleted file mode 100644 index 735c43542a9..00000000000 --- a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector/config/configured_rule.php +++ /dev/null @@ -1,9 +0,0 @@ -withRules([ArrowFunctionToFirstClassCallableRector::class]); diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_any_call_like_with_args.php.inc b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_any_call_like_with_args.php.inc index ed1572c35cf..5d481afcc1e 100644 --- a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_any_call_like_with_args.php.inc +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/skip_any_call_like_with_args.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture; -use CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Source\SomeGetter; +use Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Source\SomeGetter; final class SkipAnyCallLikeWithArgs { diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/two_bare_getters.php.inc b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/two_bare_getters.php.inc index 69d53d06a79..3bd4dc89b43 100644 --- a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/two_bare_getters.php.inc +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Fixture/two_bare_getters.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture; -use CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Source\SomeGetter; +use Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Source\SomeGetter; final class TwoBareGetters { @@ -21,7 +21,7 @@ final class TwoBareGetters namespace Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Fixture; -use CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Source\SomeGetter; +use Rector\Tests\CodingStyle\Rector\ClassMethod\BinaryOpStandaloneAssignsToDirectRector\Source\SomeGetter; final class TwoBareGetters { diff --git a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Source/SomeGetter.php b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Source/SomeGetter.php index fcc9329bcac..789f2bd6288 100644 --- a/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Source/SomeGetter.php +++ b/rules-tests/CodingStyle/Rector/ClassMethod/BinaryOpStandaloneAssignsToDirectRector/Source/SomeGetter.php @@ -1,6 +1,6 @@ +----- + diff --git a/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc new file mode 100644 index 00000000000..5f42b9d9daf --- /dev/null +++ b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc @@ -0,0 +1,12 @@ +foo(); + }; + + function ($foo) + { + return (new $foo)->foo(); + }; + + function ($foo) + { + return $foo::foo(); + }; + + function ($foo) + { + return ($foo . '\\Foo')::foo(); + }; + } +} diff --git a/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc new file mode 100644 index 00000000000..2374638f3a2 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc @@ -0,0 +1,21 @@ +foo($foo); + }; + } +} diff --git a/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc new file mode 100644 index 00000000000..247d883b4ba --- /dev/null +++ b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc @@ -0,0 +1,8 @@ +foo($barFoo, $foo); + }; + } +} diff --git a/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_named_args.php.inc b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_named_args.php.inc new file mode 100644 index 00000000000..66131f4f959 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_named_args.php.inc @@ -0,0 +1,19 @@ +foo(foo: $foo); + }; + + function ($foo) + { + return Foo::foo(foo: $foo); + }; + } +} diff --git a/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc new file mode 100644 index 00000000000..f454eba7cdb --- /dev/null +++ b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc @@ -0,0 +1,16 @@ +foo($foo); + }; + } +} diff --git a/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc new file mode 100644 index 00000000000..c93b29f0f08 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc @@ -0,0 +1,16 @@ + +----- + diff --git a/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Source/SomeClassWithArgs.php b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Source/SomeClassWithArgs.php new file mode 100644 index 00000000000..2ec4634fafb --- /dev/null +++ b/rules-tests/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector/Source/SomeClassWithArgs.php @@ -0,0 +1,14 @@ +withRules([ClosureDelegatingCallToFirstClassCallableRector::class]) + ->withPhpVersion(PhpVersionFeature::FIRST_CLASS_CALLABLE_SYNTAX); diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc deleted file mode 100644 index 9d87e43dd9e..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc +++ /dev/null @@ -1,22 +0,0 @@ - ------ - diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc deleted file mode 100644 index 565aa4860ca..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_already_first_class_callable.php.inc +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc deleted file mode 100644 index b00a25bf272..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_call_dependency_on_arg.php.inc +++ /dev/null @@ -1,27 +0,0 @@ -foo(); -}; - -function ($foo) -{ - return (new $foo)->foo(); -}; - -fn ($foo) => $foo->foo(); - -function ($foo) -{ - return $foo::foo(); -}; - -function ($foo) -{ - return ($foo . '\\Foo')::foo(); -}; - -?> diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc deleted file mode 100644 index 6003c33b089..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_with_no_return.php.inc +++ /dev/null @@ -1,17 +0,0 @@ -foo($foo); -}; - -?> diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc deleted file mode 100644 index e3f60adff77..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc +++ /dev/null @@ -1,8 +0,0 @@ -foo($barFoo, $foo); -}; diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_named_args.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_named_args.php.inc deleted file mode 100644 index b0ff698a033..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_named_args.php.inc +++ /dev/null @@ -1,17 +0,0 @@ -foo(foo: $foo); -}; - -function ($foo) -{ - return Foo::foo(foo: $foo); -}; - -?> diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc deleted file mode 100644 index a5c35732bcb..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc +++ /dev/null @@ -1,10 +0,0 @@ -foo($foo); -}; diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc deleted file mode 100644 index a37ea7c689f..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_used_by_caller_variable.php.inc +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_variadic.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_variadic.php.inc deleted file mode 100644 index b335228dc87..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_variadic.php.inc +++ /dev/null @@ -1,9 +0,0 @@ - FooBar::foo(...$foo); - -?> ------ - diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Source/FooBar.php b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Source/FooBar.php deleted file mode 100644 index fe98e046107..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Source/FooBar.php +++ /dev/null @@ -1,14 +0,0 @@ -withRules([FunctionLikeToFirstClassCallableRector::class]); diff --git a/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php b/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php index 5f093a6e3ca..661f7482c00 100644 --- a/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php +++ b/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php @@ -26,13 +26,13 @@ use Rector\PhpParser\Comparing\NodeComparator; use Rector\Reflection\ReflectionResolver; -final class ArrowFunctionAndClosureFirstClassCallableGuard +final readonly class ArrowFunctionAndClosureFirstClassCallableGuard { public function __construct( - private readonly ReflectionResolver $reflectionResolver, - private readonly AstResolver $astResolver, - private readonly NodeComparator $nodeComparator, - private readonly NodeNameResolver $nodeNameResolver, + private ReflectionResolver $reflectionResolver, + private AstResolver $astResolver, + private NodeComparator $nodeComparator, + private NodeNameResolver $nodeNameResolver, ) { } @@ -123,7 +123,7 @@ private function isDependantMethod(StaticCall|MethodCall|FuncCall $expr, array $ $parentNode = $expr instanceof MethodCall ? $expr->var : $expr->class; foreach ($params as $param) { - SimpleCallableNodeTraverser::traverse($parentNode, function (Node $node) use ($param, &$found) { + SimpleCallableNodeTraverser::traverse($parentNode, function (Node $node) use ($param, &$found): ?int { if ($this->nodeComparator->areNodesEqual($node, $param->var)) { $found = true; return NodeVisitor::STOP_TRAVERSAL; @@ -152,7 +152,7 @@ private function isUsingThisInNonObjectContext(FuncCall|MethodCall|StaticCall $c $found = false; - SimpleCallableNodeTraverser::traverse($callLike, function (Node $node) use (&$found) { + SimpleCallableNodeTraverser::traverse($callLike, function (Node $node) use (&$found): ?int { if ($this->nodeNameResolver->isName($node, 'this')) { $found = true; return NodeVisitor::STOP_TRAVERSAL; diff --git a/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector.php b/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector.php similarity index 91% rename from rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector.php rename to rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector.php index 87cd1c7a0c8..68dac2a5001 100644 --- a/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionToFirstClassCallableRector.php +++ b/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector.php @@ -11,7 +11,6 @@ use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Param; use PhpParser\Node\VariadicPlaceholder; use Rector\CodingStyle\Guard\ArrowFunctionAndClosureFirstClassCallableGuard; use Rector\PHPStan\ScopeFetcher; @@ -22,9 +21,9 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Tests\CodingStyle\Rector\ArrowFunction\ArrowFunctionToFirstClassCallableRector\ArrowFunctionToFirstClassCallableRectorTest + * @see \Rector\Tests\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector\ArrowFunctionDelegatingCallToFirstClassCallableRectorTest */ -final class ArrowFunctionToFirstClassCallableRector extends AbstractRector implements MinPhpVersionInterface +final class ArrowFunctionDelegatingCallToFirstClassCallableRector extends AbstractRector implements MinPhpVersionInterface { public function __construct( private readonly ArrowFunctionAndClosureFirstClassCallableGuard $arrowFunctionAndCLosureFirstClassCallableGuard diff --git a/rules/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector.php b/rules/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector.php new file mode 100644 index 00000000000..78efe5155e2 --- /dev/null +++ b/rules/CodingStyle/Rector/Closure/ClosureDelegatingCallToFirstClassCallableRector.php @@ -0,0 +1,97 @@ +stmts) !== 1 || ! $node->stmts[0] instanceof Return_) { + return null; + } + + $callLike = $node->stmts[0]->expr; + if (! $callLike instanceof FuncCall + && ! $callLike instanceof MethodCall + && ! $callLike instanceof StaticCall + ) { + return null; + } + + // dynamic name? skip + if ($callLike->name instanceof Expr) { + return null; + } + + if ($this->arrowFunctionAndClosureFirstClassCallableGuard->shouldSkip( + $node, + $callLike, + ScopeFetcher::fetch($node) + )) { + return null; + } + + $callLike->args = [new VariadicPlaceholder()]; + + return $callLike; + } + + public function provideMinPhpVersion(): int + { + return PhpVersionFeature::FIRST_CLASS_CALLABLE_SYNTAX; + } +} diff --git a/rules/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector.php b/rules/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector.php index fdcedda052a..b54925dbbfd 100644 --- a/rules/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector.php +++ b/rules/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector.php @@ -5,44 +5,26 @@ namespace Rector\CodingStyle\Rector\FunctionLike; use PhpParser\Node; -use PhpParser\Node\Arg; -use PhpParser\Node\Expr; use PhpParser\Node\Expr\ArrowFunction; use PhpParser\Node\Expr\CallLike; use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\FunctionLike; -use PhpParser\Node\Identifier; -use PhpParser\Node\Param; -use PhpParser\Node\Stmt\Return_; -use PhpParser\Node\VariadicPlaceholder; -use PhpParser\NodeVisitor; -use PHPStan\Analyser\Scope; -use PHPStan\Reflection\Annotations\AnnotationMethodReflection; -use Rector\NodeTypeResolver\Node\AttributeKey; -use Rector\PhpParser\AstResolver; -use Rector\PHPStan\ScopeFetcher; +use Rector\CodingStyle\Rector\ArrowFunction\ArrowFunctionDelegatingCallToFirstClassCallableRector; +use Rector\CodingStyle\Rector\Closure\ClosureDelegatingCallToFirstClassCallableRector; +use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; +use Rector\Exception\ShouldNotHappenException; use Rector\Rector\AbstractRector; -use Rector\Reflection\ReflectionResolver; use Rector\ValueObject\PhpVersionFeature; use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Tests\CodingStyle\Rector\FunctionLike\FunctionLikeToFirstClassCallableRector\FunctionLikeToFirstClassCallableRectorTest + * @deprecated This rule was split into + * @see ClosureDelegatingCallToFirstClassCallableRector and + * @see ArrowFunctionDelegatingCallToFirstClassCallableRector */ -final class FunctionLikeToFirstClassCallableRector extends AbstractRector implements MinPhpVersionInterface +final class FunctionLikeToFirstClassCallableRector extends AbstractRector implements MinPhpVersionInterface, DeprecatedInterface { - public function __construct( - private readonly AstResolver $astResolver, - private readonly ReflectionResolver $reflectionResolver - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -72,244 +54,16 @@ public function getNodeTypes(): array */ public function refactor(Node $node): null|CallLike { - $callLike = $this->extractCallLike($node); - if ($callLike === null) { - return null; - } - - if ($this->shouldSkip($node, $callLike, ScopeFetcher::fetch($node))) { - return null; - } - - $callLike->args = [new VariadicPlaceholder()]; - - return $callLike; + throw new ShouldNotHappenException(sprintf( + '"%s" rule is deprecated. It was split into "%s" and "%s" rules.', + self::class, + ClosureDelegatingCallToFirstClassCallableRector::class, + ArrowFunctionDelegatingCallToFirstClassCallableRector::class + )); } public function provideMinPhpVersion(): int { return PhpVersionFeature::FIRST_CLASS_CALLABLE_SYNTAX; } - - private function shouldSkip( - ArrowFunction|Closure $node, - FuncCall|MethodCall|StaticCall $callLike, - Scope $scope - ): bool { - if ($callLike->isFirstClassCallable()) { - return true; - } - - $params = $node->getParams(); - - if (count($params) !== count($callLike->getArgs())) { - return true; - } - - $args = $callLike->getArgs(); - if ($this->isChainedCall($callLike)) { - return true; - } - - if ($this->isUsingNamedArgs($args)) { - return true; - } - - if ($this->isUsingByRef($params)) { - return true; - } - - if ($this->isNotUsingSameParamsForArgs($params, $args)) { - return true; - } - - if ($this->isDependantMethod($callLike, $params)) { - return true; - } - - if ($this->isUsingThisInNonObjectContext($callLike, $scope)) { - return true; - } - - if ($node->getAttribute(AttributeKey::HAS_CLOSURE_WITH_VARIADIC_ARGS) === true) { - return true; - } - - if ($node->getAttribute(AttributeKey::IS_ASSIGNED_TO) === true || $node->getAttribute( - AttributeKey::IS_BEING_ASSIGNED - )) { - return true; - } - - $reflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($callLike); - - // not exists, probably by magic method - if ($reflection === null) { - return true; - } - - // exists, but by @method annotation - if ($reflection instanceof AnnotationMethodReflection && ! $reflection->getDeclaringClass()->hasNativeMethod( - $reflection->getName() - )) { - return true; - } - - $functionLike = $this->astResolver->resolveClassMethodOrFunctionFromCall($callLike); - if (! $functionLike instanceof FunctionLike) { - return false; - } - - return count($functionLike->getParams()) > 1; - } - - private function extractCallLike(Closure|ArrowFunction $node): FuncCall|MethodCall|StaticCall|null - { - if ($node instanceof Closure) { - if (count($node->stmts) !== 1 || ! $node->stmts[0] instanceof Return_) { - return null; - } - - $callLike = $node->stmts[0]->expr; - } else { - $callLike = $node->expr; - } - - if ( - ! $callLike instanceof FuncCall - && ! $callLike instanceof MethodCall - && ! $callLike instanceof StaticCall - ) { - return null; - } - - // dynamic name? skip - if ($callLike->name instanceof Expr) { - return null; - } - - return $callLike; - } - - /** - * @param Param[] $params - * @param Arg[] $args - */ - private function isNotUsingSameParamsForArgs(array $params, array $args): bool - { - if (count($args) > count($params)) { - return true; - } - - if (count($args) === 1 && $args[0]->unpack) { - return ! $params[0]->variadic; - } - - foreach ($args as $key => $arg) { - if (! $this->nodeComparator->areNodesEqual($arg->value, $params[$key]->var)) { - return true; - } - - if ($arg->value instanceof Variable) { - $variableName = (string) $this->getName($arg->value); - foreach ($params as $param) { - if ($param->var instanceof Variable - && $this->isName($param->var, $variableName) - && $param->variadic - && ! $arg->unpack) { - return true; - } - } - } - } - - return false; - } - - /** - * @param Param[] $params - */ - private function isDependantMethod(StaticCall|MethodCall|FuncCall $expr, array $params): bool - { - if ($expr instanceof FuncCall) { - return false; - } - - $found = false; - $parentNode = $expr instanceof MethodCall ? $expr->var : $expr->class; - - foreach ($params as $param) { - $this->traverseNodesWithCallable($parentNode, function (Node $node) use ($param, &$found) { - if ($this->nodeComparator->areNodesEqual($node, $param->var)) { - $found = true; - return NodeVisitor::STOP_TRAVERSAL; - } - }); - - if ($found) { - return true; - } - } - - return false; - } - - private function isUsingThisInNonObjectContext(FuncCall|MethodCall|StaticCall $callLike, Scope $scope): bool - { - if (! $callLike instanceof MethodCall) { - return false; - } - - if (in_array('this', $scope->getDefinedVariables(), true)) { - return false; - } - - $found = false; - - $this->traverseNodesWithCallable($callLike, function (Node $node) use (&$found) { - if ($this->isName($node, 'this')) { - $found = true; - return NodeVisitor::STOP_TRAVERSAL; - } - }); - - return $found; - } - - /** - * @param Param[] $params - */ - private function isUsingByRef(array $params): bool - { - foreach ($params as $param) { - if ($param->byRef) { - return true; - } - } - - return false; - } - - /** - * @param Arg[] $args - */ - private function isUsingNamedArgs(array $args): bool - { - foreach ($args as $arg) { - if ($arg->name instanceof Identifier) { - return true; - } - } - - return false; - } - - private function isChainedCall(FuncCall|MethodCall|StaticCall $callLike): bool - { - if (! $callLike instanceof MethodCall) { - return false; - } - - return $callLike->var instanceof CallLike; - } }