From fc600bf8f672e36d8c07fb5826e9b92038f04123 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 10 Aug 2026 23:03:23 +0200 Subject: [PATCH] [deprecation] Deprecate FuncCallToMethodCallRector, as it rarely works without breaking code --- composer.json | 1 - phpstan.neon | 1 + .../Fixture/another_view.php.inc | 36 --------- .../Fixture/fixture.php.inc | 30 ------- .../Fixture/re_use_translator.php.inc | 31 ------- .../re_use_translator_nullable.php.inc | 31 ------- .../re_use_translator_property.php.inc | 31 ------- .../Fixture/skip_bare_function.php.inc | 10 --- .../Fixture/skip_static_method.php.inc | 13 --- .../FuncCallToMethodCallRectorTest.php | 28 ------- .../Source/NullableTranslatorProvider.php | 15 ---- .../Source/PropertyTranslatorProvider.php | 13 --- .../Source/SomeTranslator.php | 12 --- .../Source/TranslatorProvider.php | 15 ---- .../Source/some_view_function.php | 14 ---- .../config/configured_rule.php | 26 ------ .../FuncCall/FuncCallToMethodCallRector.php | 80 ++----------------- .../ValueObject/FuncCallToMethodCall.php | 3 + src/PhpParser/Node/NodeFactory.php | 1 + 19 files changed, 13 insertions(+), 378 deletions(-) delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/another_view.php.inc delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/fixture.php.inc delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator.php.inc delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_nullable.php.inc delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_property.php.inc delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/skip_bare_function.php.inc delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/skip_static_method.php.inc delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/FuncCallToMethodCallRectorTest.php delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/NullableTranslatorProvider.php delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/PropertyTranslatorProvider.php delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/SomeTranslator.php delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/TranslatorProvider.php delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/some_view_function.php delete mode 100644 rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/config/configured_rule.php diff --git a/composer.json b/composer.json index 4213c34423b..33316169685 100644 --- a/composer.json +++ b/composer.json @@ -94,7 +94,6 @@ ], "files": [ "tests/debug_functions.php", - "rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/some_view_function.php", "rules-tests/TypeDeclaration/Rector/ClassMethod/ScalarParamTypeByMethodCallTypeRector/Source/FunctionTyped.php", "rules-tests/TypeDeclaration/Rector/StmtsAwareInterface/SafeDeclareStrictTypesRector/Source/functions.php", "rules-tests/Php70/Rector/ClassMethod/Php4ConstructorRector/Source/ParentClass.php" diff --git a/phpstan.neon b/phpstan.neon index 5e74f14907b..f4639a95787 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -469,6 +469,7 @@ parameters: - '#Class "Rector\\Assert\\Rector\\ClassMethod\\AddAssertArrayFromClassMethodDocblockRector" is missing @see annotation with test case class reference#' - '#Class "Rector\\TypeDeclarationDocblocks\\Rector\\ClassMethod\\AddParamArrayDocblockBasedOnArrayMapRector" is missing @see annotation with test case class reference#' - '#Class "Rector\\TypeDeclaration\\Rector\\ClassMethod\\AddReturnArrayDocblockBasedOnArrayMapRector" is missing @see annotation with test case class reference#' + - '#Class "Rector\\Transform\\Rector\\FuncCall\\FuncCallToMethodCallRector" is missing @see annotation with test case class reference#' # @todo fix in phpstan-rules - diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/another_view.php.inc b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/another_view.php.inc deleted file mode 100644 index 8a8db97b7e4..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/another_view.php.inc +++ /dev/null @@ -1,36 +0,0 @@ - ------ -someRenderer->render('template', []); - $this->someRenderer->render('template', []); - } -} - -?> diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/fixture.php.inc b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/fixture.php.inc deleted file mode 100644 index 40caaa6a949..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/fixture.php.inc +++ /dev/null @@ -1,30 +0,0 @@ - ------ -someTranslator->translateMethod('name'); - } -} - -?> diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator.php.inc b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator.php.inc deleted file mode 100644 index e9afd55e9f0..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator.php.inc +++ /dev/null @@ -1,31 +0,0 @@ - ------ -getTranslator()->translateMethod('name'); - } -} - -?> diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_nullable.php.inc b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_nullable.php.inc deleted file mode 100644 index a400294946c..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_nullable.php.inc +++ /dev/null @@ -1,31 +0,0 @@ - ------ -getTranslator()->translateMethod('name'); - } -} - -?> diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_property.php.inc b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_property.php.inc deleted file mode 100644 index 6630c077baf..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/re_use_translator_property.php.inc +++ /dev/null @@ -1,31 +0,0 @@ - ------ -existingTranslator->translateMethod('name'); - } -} - -?> diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/skip_bare_function.php.inc b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/skip_bare_function.php.inc deleted file mode 100644 index 742aa4cf9da..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Fixture/skip_bare_function.php.inc +++ /dev/null @@ -1,10 +0,0 @@ -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/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/NullableTranslatorProvider.php b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/NullableTranslatorProvider.php deleted file mode 100644 index 04272860bb1..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/NullableTranslatorProvider.php +++ /dev/null @@ -1,15 +0,0 @@ -translator; - } -} diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/PropertyTranslatorProvider.php b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/PropertyTranslatorProvider.php deleted file mode 100644 index 863034dff77..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/PropertyTranslatorProvider.php +++ /dev/null @@ -1,13 +0,0 @@ -translator; - } -} diff --git a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/some_view_function.php b/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/some_view_function.php deleted file mode 100644 index 3764f93b6e2..00000000000 --- a/rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/Source/some_view_function.php +++ /dev/null @@ -1,14 +0,0 @@ -phpVersion(PhpVersion::PHP_80); - - $rectorConfig - ->ruleWithConfiguration(FuncCallToMethodCallRector::class, [ - new FuncCallToMethodCall('view', 'Namespaced\SomeRenderer', 'render'), - - new FuncCallToMethodCall('translate', SomeTranslator::class, 'translateMethod'), - - new FuncCallToMethodCall( - 'Rector\Tests\Transform\Rector\Function_\FuncCallToMethodCallRector\Source\some_view_function', - 'Namespaced\SomeRenderer', - 'render' - ), - ]); -}; diff --git a/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php b/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php index c00c2c2ad50..c0a9cc19a75 100644 --- a/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php +++ b/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php @@ -5,31 +5,20 @@ namespace Rector\Transform\Rector\FuncCall; use PhpParser\Node; -use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Stmt\Class_; +use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; use Rector\Contract\Rector\ConfigurableRectorInterface; +use Rector\Exception\ShouldNotHappenException; use Rector\Rector\AbstractRector; -use Rector\Transform\NodeAnalyzer\FuncCallStaticCallToMethodCallAnalyzer; use Rector\Transform\ValueObject\FuncCallToMethodCall; use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; -use Webmozart\Assert\Assert; /** - * @see \Rector\Tests\Transform\Rector\FuncCall\FuncCallToMethodCallRector\FuncCallToMethodCallRectorTest + * @deprecated This rule is deprecated, as a function call can be turned to a method call in very few cases without breaking the code. The service has to be available in the class, the method signature has to match and the function must have no side effects. Use a custom rule for the exact project case instead. */ -final class FuncCallToMethodCallRector extends AbstractRector implements ConfigurableRectorInterface +final class FuncCallToMethodCallRector extends AbstractRector implements ConfigurableRectorInterface, DeprecatedInterface { - /** - * @var FuncCallToMethodCall[] - */ - private array $funcNameToMethodCallNames = []; - - public function __construct( - private readonly FuncCallStaticCallToMethodCallAnalyzer $funcCallStaticCallToMethodCallAnalyzer - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition('Turn defined function calls to local method calls', [ @@ -82,60 +71,10 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $hasChanged = false; - $class = $node; - - foreach ($node->getMethods() as $classMethod) { - if ($classMethod->isStatic()) { - continue; - } - - if ($classMethod->isAbstract()) { - continue; - } - - $this->traverseNodesWithCallable($classMethod, function (Node $node) use ( - $class, - $classMethod, - &$hasChanged - ): ?Node { - if (! $node instanceof FuncCall) { - return null; - } - - foreach ($this->funcNameToMethodCallNames as $funcNameToMethodCallName) { - if (! $this->isName($node->name, $funcNameToMethodCallName->getOldFuncName())) { - continue; - } - - $expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr( - $class, - $classMethod, - $funcNameToMethodCallName->getNewObjectType(), - ); - - if ($expr === null) { - return null; - } - - $hasChanged = true; - - return $this->nodeFactory->createMethodCall( - $expr, - $funcNameToMethodCallName->getNewMethodName(), - $node->args - ); - } - - return null; - }); - } - - if ($hasChanged) { - return $node; - } - - return null; + throw new ShouldNotHappenException(sprintf( + '"%s" rule is deprecated, as a function call can rarely be turned to a method call without breaking the code; use a custom rule for the exact project case instead', + self::class + )); } /** @@ -143,8 +82,5 @@ public function refactor(Node $node): ?Node */ public function configure(array $configuration): void { - Assert::allIsAOf($configuration, FuncCallToMethodCall::class); - - $this->funcNameToMethodCallNames = $configuration; } } diff --git a/rules/Transform/ValueObject/FuncCallToMethodCall.php b/rules/Transform/ValueObject/FuncCallToMethodCall.php index 98b93b933b4..d7ff6ad76fb 100644 --- a/rules/Transform/ValueObject/FuncCallToMethodCall.php +++ b/rules/Transform/ValueObject/FuncCallToMethodCall.php @@ -7,6 +7,9 @@ use PHPStan\Type\ObjectType; use Rector\Validation\RectorAssert; +/** + * @api used in deprecated FuncCallToMethodCallRector configs + */ final readonly class FuncCallToMethodCall { public function __construct( diff --git a/src/PhpParser/Node/NodeFactory.php b/src/PhpParser/Node/NodeFactory.php index 213894b865c..7066a6e736c 100644 --- a/src/PhpParser/Node/NodeFactory.php +++ b/src/PhpParser/Node/NodeFactory.php @@ -208,6 +208,7 @@ public function createLocalMethodCall(string $method, array $arguments = []): Me } /** + * @api symfony, doctrine, phpunit * @param mixed[] $arguments */ public function createMethodCall(Expr|string $exprOrVariableName, string $method, array $arguments = []): MethodCall