diff --git a/rules-tests/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector/Fixture/keep_create_component.php.inc b/rules-tests/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector/Fixture/keep_create_component.php.inc deleted file mode 100644 index e409c669546..00000000000 --- a/rules-tests/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector/Fixture/keep_create_component.php.inc +++ /dev/null @@ -1,10 +0,0 @@ -isFinal() || FeatureFlags::treatClassesAsFinal($node); + $scope = null; - $classReflection = null; + + $classReflection = $this->getClassReflection($node); + if (! $classReflection instanceof ClassReflection) { + return null; + } $this->traverseNodesWithCallable($node->stmts, function (Node $subNode) use ( &$hasChanged, - &$classReflection, + $classReflection, $isFinal, &$scope, $node, @@ -108,11 +113,6 @@ public function refactor(Node $node): ?Class_ } $scope ??= ScopeFetcher::fetch($node); - $classReflection ??= $scope->getClassReflection(); - - if (! $classReflection instanceof ClassReflection) { - return null; - } if ($this->shouldSkip($subNode, $classReflection, $isFinal, $scope)) { return null; diff --git a/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php b/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php index d685412baac..330fdd31624 100644 --- a/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php +++ b/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php @@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Enum_; use PHPStan\Reflection\ClassReflection; use Rector\NodeManipulator\ClassConstManipulator; -use Rector\PHPStan\ScopeFetcher; use Rector\Rector\AbstractRector; use Rector\Reflection\ReflectionResolver; use Rector\RuleDoc\CodeSample\CodeSample; @@ -78,7 +77,7 @@ public function refactor(Node $node): ?Node continue; } - if ($this->shouldSkipClassConst($stmt)) { + if ($this->shouldSkipClassConst($classReflection, $stmt)) { continue; } @@ -101,7 +100,7 @@ public function refactor(Node $node): ?Node return $node; } - private function shouldSkipClassConst(ClassConst $classConst): bool + private function shouldSkipClassConst(ClassReflection $classReflection, ClassConst $classConst): bool { if (! $classConst->isPrivate()) { return true; @@ -111,13 +110,6 @@ private function shouldSkipClassConst(ClassConst $classConst): bool return true; } - $scope = ScopeFetcher::fetch($classConst); - - $classReflection = $scope->getClassReflection(); - if (! $classReflection instanceof ClassReflection) { - return false; - } - return $this->hasParentClassOfEnumSuffix($classReflection); } diff --git a/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php b/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php index f5090fa8e30..75b53dad4be 100644 --- a/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php +++ b/rules/DeadCode/Rector/Class_/RemoveRefactorDuplicatedNodeInstanceCheckRector.php @@ -16,7 +16,6 @@ use PHPStan\Type\ObjectType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\PhpParser\Node\Value\ValueResolver; -use Rector\PHPStan\ScopeFetcher; use Rector\Rector\AbstractRector; use Rector\RuleDoc\CodeSample\CodeSample; use Rector\RuleDoc\RuleDefinition; @@ -91,9 +90,7 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $scope = ScopeFetcher::fetch($node); - $classReflection = $scope->getClassReflection(); - + $classReflection = $this->getClassReflection($node); if (! $classReflection instanceof ClassReflection) { return null; } diff --git a/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php b/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php index 89f6b18057b..fd77194b33c 100644 --- a/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php +++ b/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php @@ -92,7 +92,7 @@ public function refactor(Node $node): Class_|null return null; } - $classReflection = $scope->getClassReflection(); + $classReflection = $this->getClassReflection($node); if (! $classReflection instanceof ClassReflection) { return null; } diff --git a/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php b/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php index d7efe8e4e10..d0a07c813b7 100644 --- a/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php +++ b/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php @@ -16,7 +16,6 @@ use PHPStan\Reflection\Php\PhpMethodReflection; use Rector\Enum\ObjectReference; use Rector\NodeCollector\StaticAnalyzer; -use Rector\PHPStan\ScopeFetcher; use Rector\Rector\AbstractRector; use Rector\Reflection\ReflectionResolver; use Rector\RuleDoc\CodeSample\CodeSample; @@ -93,13 +92,11 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $scope = ScopeFetcher::fetch($node); - if (! $scope->isInClass()) { + $classReflection = $this->getClassReflection($node); + if (! $classReflection instanceof ClassReflection) { return null; } - $classReflection = $scope->getClassReflection(); - // skip PHPUnit calls, as they accept both self:: and $this-> formats if ($classReflection->is('PHPUnit\Framework\TestCase')) { return null; diff --git a/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php b/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php index 098ddfeb73e..cc6fe3f7d94 100644 --- a/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php +++ b/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php @@ -26,7 +26,6 @@ use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PhpParser\Node\BetterNodeFinder; use Rector\PhpParser\Printer\BetterStandardPrinter; -use Rector\PHPStan\ScopeFetcher; use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\Rector\AbstractRector; use Rector\RuleDoc\CodeSample\CodeSample; @@ -113,6 +112,11 @@ public function refactor(Node $node): ?Node $hasChanged = false; + $classReflection = $this->getClassReflection($node); + if (! $classReflection instanceof ClassReflection) { + return null; + } + foreach ($node->getMethods() as $classMethod) { if ($this->isName($classMethod, MethodName::CONSTRUCT)) { continue; @@ -127,14 +131,11 @@ public function refactor(Node $node): ?Node continue; } - $scope = ScopeFetcher::fetch($node); - $currentClassReflection = $scope->getClassReflection(); - // It relies on phpstorm stubs that define 2 kind of query method for both php 7.4 and php 8.0 // @see https://github.com/JetBrains/phpstorm-stubs/blob/e2e898a29929d2f520fe95bdb2109d8fa895ba4a/PDO/PDO.php#L1096-L1126 if ($parentMethodReflection->getName() === 'query' - && $currentClassReflection instanceof ClassReflection - && $currentClassReflection->is('PDO')) { + // && $classReflection instanceof ClassReflection + && $classReflection->is('PDO')) { continue; } diff --git a/rules/Privatization/Rector/ClassConst/PrivatizeFinalClassConstantRector.php b/rules/Privatization/Rector/ClassConst/PrivatizeFinalClassConstantRector.php index e9e3b439094..e9014daf360 100644 --- a/rules/Privatization/Rector/ClassConst/PrivatizeFinalClassConstantRector.php +++ b/rules/Privatization/Rector/ClassConst/PrivatizeFinalClassConstantRector.php @@ -8,7 +8,6 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassConst; use PHPStan\Reflection\ClassReflection; -use Rector\PHPStan\ScopeFetcher; use Rector\Privatization\Guard\OverrideByParentClassGuard; use Rector\Privatization\NodeManipulator\VisibilityManipulator; use Rector\Rector\AbstractRector; @@ -68,8 +67,7 @@ public function refactor(Node $node): ?Node return null; } - $scope = ScopeFetcher::fetch($node); - $classReflection = $scope->getClassReflection(); + $classReflection = $this->getClassReflection($node); if (! $classReflection instanceof ClassReflection) { return null; } diff --git a/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php b/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php index e333ee3629b..e0c7e1900a7 100644 --- a/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php +++ b/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php @@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\ClassMethod; use PHPStan\Reflection\ClassReflection; use Rector\PhpParser\Node\BetterNodeFinder; -use Rector\PHPStan\ScopeFetcher; use Rector\Privatization\Guard\LaravelModelGuard; use Rector\Privatization\Guard\OverrideByParentClassGuard; use Rector\Privatization\Guard\ParentClassMagicCallGuard; @@ -80,14 +79,12 @@ public function refactor(Node $node): ?Node return null; } - if (! $this->overrideByParentClassGuard->isLegal($node)) { + $classReflection = $this->getClassReflection($node); + if (! $classReflection instanceof ClassReflection) { return null; } - $scope = ScopeFetcher::fetch($node); - - $classReflection = $scope->getClassReflection(); - if (! $classReflection instanceof ClassReflection) { + if (! $this->overrideByParentClassGuard->isLegal($node)) { return null; } @@ -133,13 +130,6 @@ public function refactor(Node $node): ?Node private function shouldSkipClassMethod(ClassMethod $classMethod): bool { - // edge case in nette framework - /** @var string $methodName */ - $methodName = $this->getName($classMethod->name); - if (str_starts_with($methodName, 'createComponent')) { - return true; - } - if (! $classMethod->isProtected()) { return true; } @@ -149,7 +139,7 @@ private function shouldSkipClassMethod(ClassMethod $classMethod): bool } // if has parent call, its probably overriding parent one → skip it - $hasParentCall = (bool) $this->betterNodeFinder->findFirst( + return (bool) $this->betterNodeFinder->findFirst( (array) $classMethod->stmts, function (Node $node): bool { if (! $node instanceof StaticCall) { @@ -159,7 +149,5 @@ function (Node $node): bool { return $this->isName($node->class, 'parent'); } ); - - return $hasParentCall; } } diff --git a/rules/TypeDeclaration/Rector/Class_/ObjectTypedPropertyFromJMSSerializerAttributeTypeRector.php b/rules/TypeDeclaration/Rector/Class_/ObjectTypedPropertyFromJMSSerializerAttributeTypeRector.php index 80e8764dbe7..b3c3fa16b31 100644 --- a/rules/TypeDeclaration/Rector/Class_/ObjectTypedPropertyFromJMSSerializerAttributeTypeRector.php +++ b/rules/TypeDeclaration/Rector/Class_/ObjectTypedPropertyFromJMSSerializerAttributeTypeRector.php @@ -12,7 +12,6 @@ use PhpParser\Node\Stmt\Property; use PHPStan\Reflection\ClassReflection; use Rector\Php74\Guard\MakePropertyTypedGuard; -use Rector\PHPStan\ScopeFetcher; use Rector\Rector\AbstractRector; use Rector\RuleDoc\CodeSample\CodeSample; use Rector\RuleDoc\RuleDefinition; @@ -83,9 +82,7 @@ public function refactor(Node $node): ?Node return null; } - $scope = ScopeFetcher::fetch($node); - - $classReflection = $scope->getClassReflection(); + $classReflection = $this->getClassReflection($node); if (! $classReflection instanceof ClassReflection) { return null; } diff --git a/rules/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector.php b/rules/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector.php index 598f454ab7a..2d68f1bb916 100644 --- a/rules/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector.php @@ -16,7 +16,6 @@ use PHPStan\Reflection\Php\PhpPropertyReflection; use PHPStan\Type\Type; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; -use Rector\PHPStan\ScopeFetcher; use Rector\Rector\AbstractRector; use Rector\RuleDoc\CodeSample\CodeSample; use Rector\RuleDoc\RuleDefinition; @@ -71,6 +70,11 @@ public function refactor(Node $node): ?Node { $hasChanged = false; + $classReflection = $this->getClassReflection($node); + if (! $classReflection instanceof ClassReflection) { + return null; + } + foreach ($node->getProperties() as $property) { if (! $property->type instanceof Identifier) { continue; @@ -103,7 +107,7 @@ public function refactor(Node $node): ?Node continue; } - if ($this->hasUsefulParentPropertyVarTag($node, $property, $propertyDefaultType)) { + if ($this->hasUsefulParentPropertyVarTag($classReflection, $property, $propertyDefaultType)) { continue; } @@ -123,7 +127,7 @@ public function refactor(Node $node): ?Node return $node; } - private function hasUsefulParentPropertyVarTag(Class_ $class, Property $property, Type $propertyDefaultType): bool + private function hasUsefulParentPropertyVarTag(ClassReflection $classReflection, Property $property, Type $propertyDefaultType): bool { $propertyName = $this->getName($property); if ($propertyName === null) { @@ -135,13 +139,6 @@ private function hasUsefulParentPropertyVarTag(Class_ $class, Property $property return false; } - $scope = ScopeFetcher::fetch($class); - - $classReflection = $scope->getClassReflection(); - if (! $classReflection instanceof ClassReflection) { - return false; - } - foreach ($classReflection->getParents() as $parentClassReflection) { if (! $parentClassReflection->hasNativeProperty($propertyName)) { continue; diff --git a/src/DependencyInjection/LazyContainerFactory.php b/src/DependencyInjection/LazyContainerFactory.php index 7792d983428..5eb1336e040 100644 --- a/src/DependencyInjection/LazyContainerFactory.php +++ b/src/DependencyInjection/LazyContainerFactory.php @@ -241,6 +241,7 @@ static function (AbstractRector $rector) use ($rectorConfig): void { $rectorConfig->get(NodeComparator::class), $rectorConfig->get(CurrentFileProvider::class), $rectorConfig->get(CommentsMerger::class), + $rectorConfig->get(ReflectionProvider::class) ); } ); diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index 9537234b943..4aa2c2b04cb 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -8,11 +8,14 @@ use PhpParser\Node\Expr; use PhpParser\Node\Name; use PhpParser\Node\PropertyItem; +use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Const_; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Trait_; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use Rector\Application\Provider\CurrentFileProvider; @@ -42,6 +45,8 @@ abstract class AbstractRector implements RectorInterface private CommentsMerger $commentsMerger; + private ReflectionProvider $reflectionProvider; + public function autowire( NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, @@ -49,7 +54,8 @@ public function autowire( NodeFactory $nodeFactory, NodeComparator $nodeComparator, CurrentFileProvider $currentFileProvider, - CommentsMerger $commentsMerger + CommentsMerger $commentsMerger, + ReflectionProvider $reflectionProvider ): void { $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; @@ -58,6 +64,21 @@ public function autowire( $this->nodeComparator = $nodeComparator; $this->currentFileProvider = $currentFileProvider; $this->commentsMerger = $commentsMerger; + $this->reflectionProvider = $reflectionProvider; + } + + protected function getClassReflection(ClassLike $classLike): ?ClassReflection + { + $className = $this->getName($classLike); + if ($className === null) { + return null; + } + + if (! $this->reflectionProvider->hasClass($className)) { + throw new ShouldNotHappenException(sprintf('Class "%s" should be known at this point', $className)); + } + + return $this->reflectionProvider->getClass($className); } protected function getFile(): File