diff --git a/config/set/php70.php b/config/set/php70.php index b16c79ef7a4..6288dbe56cd 100644 --- a/config/set/php70.php +++ b/config/set/php70.php @@ -16,7 +16,6 @@ use Rector\Php70\Rector\If_\IfToSpaceshipRector; use Rector\Php70\Rector\List_\EmptyListRector; use Rector\Php70\Rector\MethodCall\ThisCallOnStaticMethodToStaticCallRector; -use Rector\Php70\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector; use Rector\Php70\Rector\StmtsAwareInterface\IfIssetToCoalescingRector; use Rector\Php70\Rector\Switch_\ReduceMultipleDefaultSwitchRector; use Rector\Php70\Rector\Ternary\TernaryToNullCoalescingRector; @@ -32,7 +31,6 @@ MultiDirnameRector::class, ListSplitStringRector::class, EmptyListRector::class, - // be careful, run this just once, since it can keep swapping order back and forth ListSwapArrayOrderRector::class, CallUserMethodRector::class, EregToPregMatchRector::class, @@ -40,7 +38,6 @@ TernaryToSpaceshipRector::class, WrapVariableVariableNameInCurlyBracesRector::class, IfToSpaceshipRector::class, - StaticCallOnNonStaticToInstanceCallRector::class, ThisCallOnStaticMethodToStaticCallRector::class, BreakNotInLoopOrSwitchToReturnRector::class, RenameMktimeWithoutArgsToTimeRector::class, diff --git a/phpstan.neon b/phpstan.neon index cf5840b5707..59b80e31808 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -415,8 +415,10 @@ parameters: - '#Rule Rector\\Php81\\Rector\\Array_\\FirstClassCallableRector must implements Rector\\VersionBonding\\Contract\\MinPhpVersionInterface#' - '#Register "Rector\\Php81\\Rector\\Array_\\FirstClassCallableRector" service to "php81\.php" config set#' - '#Register "Rector\\Php81\\Rector\\ClassMethod\\NewInInitializerRector" service to "php81\.php" config set#' + - '#Register "Rector\\Php70\\Rector\\StaticCall\\StaticCallOnNonStaticToInstanceCallRector" service to "php70\.php" config set#' - '#Class "Rector\\CodingStyle\\Rector\\String_\\SymplifyQuoteEscapeRector" is missing @see annotation with test case class reference#' - '#Class "Rector\\Php81\\Rector\\ClassMethod\\NewInInitializerRector" is missing @see annotation with test case class reference#' + - '#Class "Rector\\Php70\\Rector\\StaticCall\\StaticCallOnNonStaticToInstanceCallRector" is missing @see annotation with test case class reference#' - '#Class "Rector\\TypeDeclaration\\Rector\\ClassMethod\\StrictStringParamConcatRector" is missing @see annotation with test case class reference#' # false positive diff --git a/rules-tests/Php70/Rector/Assign/ListSwapArrayOrderRector/Fixture/skip_already_array_reverse.php.inc b/rules-tests/Php70/Rector/Assign/ListSwapArrayOrderRector/Fixture/skip_already_array_reverse.php.inc new file mode 100644 index 00000000000..4f8352347d4 --- /dev/null +++ b/rules-tests/Php70/Rector/Assign/ListSwapArrayOrderRector/Fixture/skip_already_array_reverse.php.inc @@ -0,0 +1,11 @@ + ------ -__customMagicMethod(); - } -} - -?> diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/fixture.php.inc b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/fixture.php.inc deleted file mode 100644 index 93abdb09ccc..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/fixture.php.inc +++ /dev/null @@ -1,41 +0,0 @@ - ------ -doWork(1); - } -} - -?> diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/keep.php.inc b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/keep.php.inc deleted file mode 100644 index 24ddd2f65a5..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/keep.php.inc +++ /dev/null @@ -1,29 +0,0 @@ -foo(); - } - - public function foo() - { - - } - - public function runnaways($value) - { - $name = 'hi' . $value; - self::$name(); - } -} - -class B extends A { - public function method() { - // This call is allowed, because it's not a static call (it only looks like one) - parent::method(); - // This call is also allowed, for the same reason - A::method(); - } -} diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/keep_annotated.php.inc b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/keep_annotated.php.inc deleted file mode 100644 index 32a90443ae0..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/keep_annotated.php.inc +++ /dev/null @@ -1,18 +0,0 @@ - ------ -doWork(); - } - - public function doWork() - { - return 'work done'; - } -} - -?> diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_abstract_class.php.inc b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_abstract_class.php.inc deleted file mode 100644 index 6816d2b0b5a..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_abstract_class.php.inc +++ /dev/null @@ -1,23 +0,0 @@ -getMethod(); - $store::foo(); - } -} diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_non_existing_method.php.inc b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_non_existing_method.php.inc deleted file mode 100644 index e803bb05463..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_non_existing_method.php.inc +++ /dev/null @@ -1,13 +0,0 @@ -withOnlyStaticMethods = $withOnlyStaticMethods; - } - - public function cast() - { - $this->withOnlyStaticMethods::aBoolMethod(); - } -} diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_static_closure_same_class_call.php.inc b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_static_closure_same_class_call.php.inc deleted file mode 100644 index 62286271fdf..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_static_closure_same_class_call.php.inc +++ /dev/null @@ -1,18 +0,0 @@ -required = $required; - } - - public function doWork() - { - $this->required = 5; - return 5; - } -} - -class TryWithConstructor -{ - public function run() - { - return SkipWithConstructor::doWork(); - } -} diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_with_only_static_methods.php.inc b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_with_only_static_methods.php.inc deleted file mode 100644 index 1dd12b756ee..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Fixture/skip_with_only_static_methods.php.inc +++ /dev/null @@ -1,16 +0,0 @@ - WithOnlyStaticMethods::aBoolMethod(), - 'string' => WithOnlyStaticMethods::aStringMethod() - ]; - } -} diff --git a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Source/AbstractClassHello.php b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Source/AbstractClassHello.php deleted file mode 100644 index 1ac63ac1e36..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Source/AbstractClassHello.php +++ /dev/null @@ -1,12 +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/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/config/configured_rule.php b/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/config/configured_rule.php deleted file mode 100644 index d58fdbff18b..00000000000 --- a/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/config/configured_rule.php +++ /dev/null @@ -1,9 +0,0 @@ -withRules([StaticCallOnNonStaticToInstanceCallRector::class]); diff --git a/rules/CodeQuality/Rector/Coalesce/CoalesceToTernaryRector.php b/rules/CodeQuality/Rector/Coalesce/CoalesceToTernaryRector.php index 2f57dc6ee5f..c0b3e2acb68 100644 --- a/rules/CodeQuality/Rector/Coalesce/CoalesceToTernaryRector.php +++ b/rules/CodeQuality/Rector/Coalesce/CoalesceToTernaryRector.php @@ -20,6 +20,8 @@ /** * @see \Rector\Tests\CodeQuality\Rector\Coalesce\CoalesceToTernaryRector\CoalesceToTernaryRectorTest + * + * @see https://github.com/rectorphp/rector/issues/9730 */ final class CoalesceToTernaryRector extends AbstractRector { diff --git a/rules/CodingStyle/ValueObject/ObjectMagicMethods.php b/rules/CodingStyle/ValueObject/ObjectMagicMethods.php index b4b9a9cfa48..1b334ce9bec 100644 --- a/rules/CodingStyle/ValueObject/ObjectMagicMethods.php +++ b/rules/CodingStyle/ValueObject/ObjectMagicMethods.php @@ -6,6 +6,9 @@ use Rector\ValueObject\MethodName; +/** + * @api designed for public use + */ final class ObjectMagicMethods { /** diff --git a/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php b/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php index e506376819b..6d48a8668a1 100644 --- a/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php +++ b/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php @@ -5,43 +5,20 @@ namespace Rector\Php70\Rector\StaticCall; use PhpParser\Node; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\Variable; -use PHPStan\Analyser\Scope; -use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\MethodReflection; -use PHPStan\Reflection\ReflectionProvider; -use PHPStan\Type\ObjectType; -use Rector\CodingStyle\ValueObject\ObjectMagicMethods; -use Rector\Enum\ObjectReference; -use Rector\NodeCollector\ScopeResolver\ParentClassScopeResolver; -use Rector\NodeCollector\StaticAnalyzer; -use Rector\PHPStan\ScopeFetcher; +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 ReflectionMethod; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Tests\Php70\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector\StaticCallOnNonStaticToInstanceCallRectorTest + * @deprecated as risky change with little value. Use manually or custom rule where needed instead. */ -final class StaticCallOnNonStaticToInstanceCallRector extends AbstractRector implements MinPhpVersionInterface +final class StaticCallOnNonStaticToInstanceCallRector extends AbstractRector implements MinPhpVersionInterface, DeprecatedInterface { - public function __construct( - private readonly StaticAnalyzer $staticAnalyzer, - private readonly ReflectionProvider $reflectionProvider, - private readonly ReflectionResolver $reflectionResolver, - private readonly ParentClassScopeResolver $parentClassScopeResolver - ) { - } - public function provideMinPhpVersion(): int { return PhpVersionFeature::INSTANCE_CALL; @@ -104,126 +81,9 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - if ($node->name instanceof Expr) { - return null; - } - - $methodName = $this->getName($node->name); - - $className = $this->resolveStaticCallClassName($node); - if ($methodName === null) { - return null; - } - - if ($className === null) { - return null; - } - - $scope = ScopeFetcher::fetch($node); - if ($this->shouldSkip($methodName, $className, $node, $scope)) { - return null; - } - - $classReflection = $scope->getClassReflection(); - if ($classReflection instanceof ClassReflection && $classReflection->getName() === $className) { - // detect any scope where $this is unavailable or possibly unavailable - if (! $scope->hasVariableType('this')->yes()) { - return null; - } - - return new MethodCall(new Variable('this'), $node->name, $node->args); - } - - if ($this->isInstantiable($className, $scope)) { - $new = new New_($node->class); - return new MethodCall($new, $node->name, $node->args); - } - - return null; - } - - private function resolveStaticCallClassName(StaticCall $staticCall): ?string - { - if ($staticCall->class instanceof PropertyFetch) { - $objectType = $this->getType($staticCall->class); - if ($objectType instanceof ObjectType) { - return $objectType->getClassName(); - } - } - - return $this->getName($staticCall->class); - } - - private function shouldSkip(string $methodName, string $className, StaticCall $staticCall, Scope $scope): bool - { - if (in_array($methodName, ObjectMagicMethods::METHOD_NAMES, true)) { - return true; - } - - if (! $this->reflectionProvider->hasClass($className)) { - return true; - } - - $classReflection = $this->reflectionProvider->getClass($className); - if ($classReflection->isAbstract()) { - return true; - } - - // does the method even exist? - if (! $classReflection->hasMethod($methodName)) { - return true; - } - - $isStaticMethod = $this->staticAnalyzer->isStaticMethod($classReflection, $methodName); - if ($isStaticMethod) { - return true; - } - - $currentClassReflection = $scope->getClassReflection(); - if ($currentClassReflection instanceof ClassReflection - && $this->reflectionProvider->hasClass($className) - && $currentClassReflection->isSubclassOfClass($this->reflectionProvider->getClass($className)) - ) { - return true; - } - - $className = $this->getName($staticCall->class); - if (in_array($className, [ObjectReference::PARENT, ObjectReference::SELF, ObjectReference::STATIC], true)) { - return true; - } - - if ($className === 'class') { - return true; - } - - $parentClassName = $this->parentClassScopeResolver->resolveParentClassName($scope); - return $className === $parentClassName; - } - - private function isInstantiable(string $className, Scope $scope): bool - { - if (! $this->reflectionProvider->hasClass($className)) { - return false; - } - - $methodReflection = $this->reflectionResolver->resolveMethodReflection($className, '__callStatic', $scope); - if ($methodReflection instanceof MethodReflection) { - return false; - } - - $classReflection = $this->reflectionProvider->getClass($className); - $nativeReflection = $classReflection->getNativeReflection(); - - $reflectionMethod = $nativeReflection->getConstructor(); - if (! $reflectionMethod instanceof ReflectionMethod) { - return true; - } - - if (! $reflectionMethod->isPublic()) { - return false; - } - - // required parameters in constructor, nothing we can do - return ! (bool) $reflectionMethod->getNumberOfRequiredParameters(); + throw new ShouldNotHappenException(sprintf( + '"%s" is deprecated as risky change with little value. Use manually or custom rule where needed instead', + self::class + )); } } diff --git a/structarmed.php b/structarmed.php index 52f85be4820..61913483c8d 100644 --- a/structarmed.php +++ b/structarmed.php @@ -16,9 +16,6 @@ // no namespace on purpose __DIR__ . '/rules-tests/Php70/Rector/ClassMethod/Php4ConstructorRector/Source/ParentClass.php', - // multi classes in one file on purpose - __DIR__ . '/rules-tests/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector/Source/Service.php', - // simulate under phpstan.phar __DIR__ . '/rules-tests/Php71/Rector/FuncCall/RemoveExtraParametersRector/Source/phpstan.phar', ], diff --git a/tests/Bridge/SetRectorsResolverTest.php b/tests/Bridge/SetRectorsResolverTest.php index 5aed8f87991..957e9188032 100644 --- a/tests/Bridge/SetRectorsResolverTest.php +++ b/tests/Bridge/SetRectorsResolverTest.php @@ -45,7 +45,7 @@ public function testResolveFromFilePathForPhpLevel(): void $rectorRulesWithConfiguration = $this->setRectorsResolver->resolveFromFilePathsIncludingConfiguration( $configFilePaths ); - $this->assertCount(62, $rectorRulesWithConfiguration); + $this->assertCount(61, $rectorRulesWithConfiguration); } public function testResolveWithConfiguration(): void