diff --git a/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php b/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php index 74d1e8c22044..34648318545b 100644 --- a/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php +++ b/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php @@ -10,6 +10,9 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; +use PHPStan\Reflection\Php\PhpPropertyReflection; +use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ReflectionProvider; use Rector\DoctrineAnnotationGenerated\PhpDocNode\ConstantReferenceIdentifierRestorer; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\ClassExistenceStaticHelper; @@ -40,15 +43,21 @@ final class NodeAnnotationReader * @var ConstantReferenceIdentifierRestorer */ private $constantReferenceIdentifierRestorer; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; public function __construct( ConstantReferenceIdentifierRestorer $constantReferenceIdentifierRestorer, NodeNameResolver $nodeNameResolver, - Reader $reader + Reader $reader, + ReflectionProvider $reflectionProvider ) { $this->reader = $reader; $this->nodeNameResolver = $nodeNameResolver; $this->constantReferenceIdentifierRestorer = $constantReferenceIdentifierRestorer; + $this->reflectionProvider = $reflectionProvider; } public function readAnnotation(Node $node, string $annotationClass): ?object @@ -87,13 +96,14 @@ public function readClassAnnotation(Class_ $class, string $annotationClassName): public function readPropertyAnnotation(Property $property, string $annotationClassName): ?object { $propertyReflection = $this->createPropertyReflectionFromPropertyNode($property); - if (! $propertyReflection instanceof ReflectionProperty) { + if (! $propertyReflection instanceof PhpPropertyReflection) { return null; } try { // covers cases like https://github.com/rectorphp/rector/issues/3046 + // @todo this will require original reflection /** @var object[] $propertyAnnotations */ $propertyAnnotations = $this->reader->getPropertyAnnotations($propertyReflection); return $this->matchNextAnnotation($propertyAnnotations, $annotationClassName, $property); @@ -175,7 +185,7 @@ private function matchNextAnnotation(array $annotations, string $annotationClass return null; } - private function createPropertyReflectionFromPropertyNode(Property $property): ?ReflectionProperty + private function createPropertyReflectionFromPropertyNode(Property $property): ?PropertyReflection { /** @var string $propertyName */ $propertyName = $this->nodeNameResolver->getName($property); @@ -186,13 +196,16 @@ private function createPropertyReflectionFromPropertyNode(Property $property): ? // probably fresh node return null; } - if (! ClassExistenceStaticHelper::doesClassLikeExist($className)) { + + if (! $this->reflectionProvider->hasClass($className)) { // probably fresh node return null; } try { - return new ReflectionProperty($className, $propertyName); + $classReflection = $this->reflectionProvider->getClass($className); + return $classReflection->getProperty($propertyName); + // return new ReflectionProperty($className, $propertyName); } catch (Throwable $throwable) { // in case of PHPUnit property or just-added property return null; diff --git a/packages/static-type-mapper/src/PhpParser/NameNodeMapper.php b/packages/static-type-mapper/src/PhpParser/NameNodeMapper.php index 1cbf7967acb2..f0da696b7513 100644 --- a/packages/static-type-mapper/src/PhpParser/NameNodeMapper.php +++ b/packages/static-type-mapper/src/PhpParser/NameNodeMapper.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Name; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; use PHPStan\Type\FloatType; @@ -29,9 +30,15 @@ final class NameNodeMapper implements PhpParserNodeMapperInterface */ private $renamedClassesCollector; - public function __construct(RenamedClassesCollector $renamedClassesCollector) + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(RenamedClassesCollector $renamedClassesCollector, ReflectionProvider $reflectionProvider) { $this->renamedClassesCollector = $renamedClassesCollector; + $this->reflectionProvider = $reflectionProvider; } public function getNodeType(): string @@ -58,7 +65,7 @@ public function mapToPHPStan(Node $node): Type private function isExistingClass(string $name): bool { - if (ClassExistenceStaticHelper::doesClassLikeExist($name)) { + if ($this->reflectionProvider->hasClass($name)) { return true; } diff --git a/rules/renaming/src/NodeManipulator/ClassRenamer.php b/rules/renaming/src/NodeManipulator/ClassRenamer.php index 54888dc82fe8..4405ce17b668 100644 --- a/rules/renaming/src/NodeManipulator/ClassRenamer.php +++ b/rules/renaming/src/NodeManipulator/ClassRenamer.php @@ -14,6 +14,7 @@ use PhpParser\Node\Stmt\Namespace_; use PhpParser\Node\Stmt\Use_; use PhpParser\Node\Stmt\UseUse; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ObjectType; use Rector\BetterPhpDocParser\Contract\PhpDocNode\TypeAwareTagValueNodeInterface; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; @@ -70,6 +71,11 @@ final class ClassRenamer */ private $docBlockClassRenamer; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( BetterNodeFinder $betterNodeFinder, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, @@ -77,7 +83,8 @@ public function __construct( NodeNameResolver $nodeNameResolver, PhpDocClassRenamer $phpDocClassRenamer, PhpDocInfoFactory $phpDocInfoFactory, - DocBlockClassRenamer $docBlockClassRenamer + DocBlockClassRenamer $docBlockClassRenamer, + ReflectionProvider $reflectionProvider ) { $this->nodeNameResolver = $nodeNameResolver; $this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser; @@ -86,6 +93,7 @@ public function __construct( $this->betterNodeFinder = $betterNodeFinder; $this->phpDocInfoFactory = $phpDocInfoFactory; $this->docBlockClassRenamer = $docBlockClassRenamer; + $this->reflectionProvider = $reflectionProvider; } /** @@ -180,16 +188,16 @@ private function refactorNamespace(Namespace_ $namespace, array $oldToNewClasses } $currentName = $this->nodeNameResolver->getName($classLike); - $newClassFqn = $oldToNewClasses[$currentName]; + $newClassFullyQualified = $oldToNewClasses[$currentName]; - if (ClassExistenceStaticHelper::doesClassLikeExist($newClassFqn)) { + if ($this->reflectionProvider->hasClass($newClassFullyQualified)) { return null; } - $newNamespace = $this->classNaming->getNamespace($newClassFqn); + $newNamespace = $this->classNaming->getNamespace($newClassFullyQualified); // Renaming to class without namespace (example MyNamespace\DateTime -> DateTimeImmutable) if (! $newNamespace) { - $classLike->name = new Identifier($newClassFqn); + $classLike->name = new Identifier($newClassFullyQualified); return $classLike; } @@ -362,7 +370,7 @@ private function isValidClassNameChange(Name $name, string $newName, Class_ $cla return false; } - if ($class->extends === $name && class_exists($newName)) { + if ($class->extends === $name && $this->reflectionProvider->hasClass($newName)) { // is final class? $reflectionClass = new ReflectionClass($newName); if ($reflectionClass->isFinal()) { diff --git a/rules/restoration/src/NameMatcher/FullyQualifiedNameMatcher.php b/rules/restoration/src/NameMatcher/FullyQualifiedNameMatcher.php index 97bbd5d844c6..7aa27a92cfa2 100644 --- a/rules/restoration/src/NameMatcher/FullyQualifiedNameMatcher.php +++ b/rules/restoration/src/NameMatcher/FullyQualifiedNameMatcher.php @@ -9,6 +9,7 @@ use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\NullableType; use PhpParser\Node\UnionType; +use PHPStan\Reflection\ReflectionProvider; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\ClassExistenceStaticHelper; @@ -24,10 +25,16 @@ final class FullyQualifiedNameMatcher */ private $nameMatcher; - public function __construct(NodeNameResolver $nodeNameResolver, NameMatcher $nameMatcher) + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(NodeNameResolver $nodeNameResolver, NameMatcher $nameMatcher, ReflectionProvider $reflectionProvider) { $this->nodeNameResolver = $nodeNameResolver; $this->nameMatcher = $nameMatcher; + $this->reflectionProvider = $reflectionProvider; } /** @@ -51,7 +58,7 @@ public function matchFullyQualifiedName($name) } $resolvedName = $this->nodeNameResolver->getName($name); - if (ClassExistenceStaticHelper::doesClassLikeExist($resolvedName)) { + if ($this->reflectionProvider->hasClass($resolvedName)) { return null; } diff --git a/rules/type-declaration/src/PHPStan/Type/ObjectTypeSpecifier.php b/rules/type-declaration/src/PHPStan/Type/ObjectTypeSpecifier.php index cc7c22105b2c..ccd0a83e0ffb 100644 --- a/rules/type-declaration/src/PHPStan/Type/ObjectTypeSpecifier.php +++ b/rules/type-declaration/src/PHPStan/Type/ObjectTypeSpecifier.php @@ -10,6 +10,7 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Stmt\Use_; use PhpParser\Node\Stmt\UseUse; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\MixedType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; @@ -21,6 +22,16 @@ final class ObjectTypeSpecifier { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + /** * @return AliasedObjectType|FullyQualifiedObjectType|ObjectType|MixedType */ @@ -49,7 +60,8 @@ public function narrowToFullyQualifiedOrAliasedObjectType(Node $node, ObjectType } $className = ltrim($objectType->getClassName(), '\\'); - if (ClassExistenceStaticHelper::doesClassLikeExist($className)) { + + if ($this->reflectionProvider->hasClass($className)) { return new FullyQualifiedObjectType($className); } @@ -160,7 +172,7 @@ private function matchSameNamespacedObjectType(Node $node, ObjectType $objectTyp $namespacedObject = $namespaceName . '\\' . ltrim($objectType->getClassName(), '\\'); - if (ClassExistenceStaticHelper::doesClassLikeExist($namespacedObject)) { + if ($this->reflectionProvider->hasClass($namespacedObject)) { return new FullyQualifiedObjectType($namespacedObject); } @@ -177,7 +189,7 @@ private function matchPartialNamespaceObjectType(ObjectType $objectType, UseUse $classNameWithoutLastUsePart = Strings::after($objectType->getClassName(), '\\', 1); $connectedClassName = $useUse->name->toString() . '\\' . $classNameWithoutLastUsePart; - if (! ClassExistenceStaticHelper::doesClassLikeExist($connectedClassName)) { + if (!$this->reflectionProvider->hasClass($connectedClassName)) { return null; } @@ -197,7 +209,7 @@ private function matchClassWithLastUseImportPart(ObjectType $objectType, UseUse return null; } - if (! ClassExistenceStaticHelper::doesClassLikeExist($useUse->name->toString())) { + if (! $this->reflectionProvider->hasClass($useUse->name->toString())) { return null; } diff --git a/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php b/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php index 1ed86d36f770..ae00fa41a75a 100644 --- a/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php +++ b/rules/type-declaration/src/TypeInferer/ParamTypeInferer/PHPUnitDataProviderParamTypeInferer.php @@ -79,7 +79,7 @@ public function inferParam(Param $param): Type /** @var Return_[] $returns */ $returns = $this->betterNodeFinder->findInstanceOf((array) $dataProviderClassMethod->stmts, Return_::class); - if( $returns !== [] ) { + if ($returns !== []) { return $this->resolveReturnStaticArrayTypeByParameterPosition($returns, $parameterPosition); } @@ -190,9 +190,7 @@ private function resolveYieldStaticArrayTypeByParameterPosition(array $yields, i return new MixedType(); } - $p = $this->typeFactory->createMixedPassedOrUnionType($paramOnPositionTypes); - - return $p; + return $this->typeFactory->createMixedPassedOrUnionType($paramOnPositionTypes); } private function getTypeFromClassMethodYield(Array_ $classMethodYieldArrayNode): Type