diff --git a/config/set/php81.php b/config/set/php81.php index 4ec7f14cd08..d73299ea7da 100644 --- a/config/set/php81.php +++ b/config/set/php81.php @@ -2,9 +2,10 @@ declare(strict_types=1); +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; @@ -30,10 +31,13 @@ SpatieEnumMethodCallToEnumConstRector::class, NullToStrictStringFuncCallArgRector::class, NullToStrictIntPregSlitFuncCallLimitArgRector::class, - // array of local method call + ArrayToFirstClassCallableRector::class, + // closure/arrow function - FunctionLikeToFirstClassCallableRector::class, + ArrowFunctionDelegatingCallToFirstClassCallableRector::class, + ClosureDelegatingCallToFirstClassCallableRector::class, + ClosureFromCallableToFirstClassCallableRector::class, FunctionFirstClassCallableRector::class, RemoveReflectionSetAccessibleCallsRector::class, diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/ArrowFunctionDelegatingCallToFirstClassCallableRectorTest.php b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/ArrowFunctionDelegatingCallToFirstClassCallableRectorTest.php new file mode 100644 index 00000000000..ed1a47462d3 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/ArrowFunctionDelegatingCallToFirstClassCallableRectorTest.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/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/array_map.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/array_map.php.inc new file mode 100644 index 00000000000..07810412f6a --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/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/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc similarity index 73% 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/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/exists_both_in_method_doc_and_native_method.php.inc index 050f68d8db1..07b666770f7 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/ArrowFunctionDelegatingCallToFirstClassCallableRector/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/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/multiple_params.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/multiple_params.php.inc similarity index 53% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/multiple_params.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/multiple_params.php.inc index 7a1c1c897d7..fcabc9fe0be 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/multiple_params.php.inc +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/multiple_params.php.inc @@ -1,6 +1,6 @@ FooBar::foo($foo); + } +} + +?> +----- + diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc similarity index 79% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_assigned_early.php.inc index 2d8a9451f7b..6de70a4eb9f 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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/FunctionLike/FunctionLikeToFirstClassCallableRector/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 83% 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/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_callable_param_assign_with_signature_multi_params.php.inc index d6cad61df0c..ea5c129f6b0 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/ArrowFunctionDelegatingCallToFirstClassCallableRector/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/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc new file mode 100644 index 00000000000..15b25385a57 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc @@ -0,0 +1,16 @@ +bar($foo); + }; + + fn ($foo) => FooBar::foo()->bar($foo); + } +} diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc similarity index 77% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc rename to rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_closure_bind_to.php.inc index 47d35b3645f..f916c7e2496 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc new file mode 100644 index 00000000000..3a68a124673 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_no_args_passed.php.inc @@ -0,0 +1,17 @@ + fn ($foo) => FooBar::optionalArgs() + ]; + + return $data; + } +} diff --git a/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc new file mode 100644 index 00000000000..708b0e9530e --- /dev/null +++ b/rules-tests/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_null_variable_call.php.inc @@ -0,0 +1,18 @@ + $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/ArrowFunctionDelegatingCallToFirstClassCallableRector/Fixture/skip_param_used_as_invokable.php.inc similarity index 77% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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 381d53d883a..e4308825bed 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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/FunctionLike/FunctionLikeToFirstClassCallableRector/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 63% rename from rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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 8ba70f768d3..52dc2d966cb 100644 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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/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/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 deleted file mode 100644 index edbc2736abc..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/fixture.php.inc +++ /dev/null @@ -1,26 +0,0 @@ - FooBar::foo($foo); - -?> ------ - 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_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_chained_calls.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_chained_calls.php.inc deleted file mode 100644 index 6f97a27cede..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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/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 f4d0f780fab..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_functions_without_calls.php.inc +++ /dev/null @@ -1,12 +0,0 @@ - $foo; - -?> diff --git a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_multi_param.php.inc b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/Fixture/skip_multi_param.php.inc deleted file mode 100644 index d15ee32e559..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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 \ No newline at end of file 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 4a877680162..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/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/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/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-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/config/configured_rule.php b/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/config/configured_rule.php deleted file mode 100644 index 0a8dd0b84a6..00000000000 --- a/rules-tests/CodingStyle/Rector/FunctionLike/FunctionLikeToFirstClassCallableRector/config/configured_rule.php +++ /dev/null @@ -1,9 +0,0 @@ -withRules([FunctionLikeToFirstClassCallableRector::class]); diff --git a/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php b/rules/CodingStyle/Guard/ArrowFunctionAndClosureFirstClassCallableGuard.php new file mode 100644 index 00000000000..661f7482c00 --- /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): ?int { + 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): ?int { + 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/ArrowFunctionDelegatingCallToFirstClassCallableRector.php b/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector.php new file mode 100644 index 00000000000..68dac2a5001 --- /dev/null +++ b/rules/CodingStyle/Rector/ArrowFunction/ArrowFunctionDelegatingCallToFirstClassCallableRector.php @@ -0,0 +1,89 @@ + 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/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; - } } 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;