From b9cddc01d89eeae17bf4fe78baa87be074c9eb76 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Wed, 24 Feb 2021 11:28:55 +0100 Subject: [PATCH] replace ClassReflection with ReflectionProvider, use unprefixed BetterReflection namespace --- composer.json | 2 +- .../AnnotationReader/NodeAnnotationReader.php | 21 ++-- .../src/NodeAnalyzer/ClassChildAnalyzer.php | 84 ++++++--------- .../NodeAnalyzer/PropertyUsageAnalyzer.php | 8 +- .../Reflection/FamilyRelationsAnalyzer.php | 31 +++--- .../src/NodeCollector/NodeRepository.php | 11 +- .../ParsedClassConstFetchNodeCollector.php | 22 ++-- .../Reflection/MethodReflectionProvider.php | 24 +++-- .../node-collector/src/StaticAnalyzer.php | 20 ++-- .../src/ValueObject/ArrayCallable.php | 5 - .../config/phpstan/static-reflection.neon | 2 +- .../ArrayDimFetchTypeResolver.php | 2 +- .../src/NodeTypeResolver/CastTypeResolver.php | 2 +- .../ClassAndInterfaceTypeResolver.php | 2 +- .../ClassConstFetchTypeResolver.php | 2 +- .../ClassMethodOrClassConstTypeResolver.php | 2 +- .../src/NodeTypeResolver/NameTypeResolver.php | 2 +- .../NodeTypeResolver/ParamTypeResolver.php | 2 +- .../PropertyFetchTypeResolver.php | 11 +- .../NodeTypeResolver/PropertyTypeResolver.php | 2 +- .../StaticCallTypeResolver.php | 20 +++- .../NodeTypeResolver/TraitTypeResolver.php | 25 ++++- .../NodeTypeResolver/VariableTypeResolver.php | 2 +- .../src/PHPStan/TypeHasher.php | 7 +- ...orBetterReflectionSourceLocatorFactory.php | 4 +- .../IntermediateSourceLocator.php | 10 +- .../DynamicSourceLocator.php | 4 +- .../UnionTypeCommonTypeNarrower.php | 66 +++++------- .../src/NodeAnalyzer/NetteInjectDetector.php | 7 +- .../src/Provider/NodeTypesProvider.php | 4 +- .../AbstractNodeVendorLockResolver.php | 61 +++-------- .../ClassMethodParamVendorLockResolver.php | 60 +++++++---- .../ClassMethodReturnVendorLockResolver.php | 37 +++---- .../ClassMethodVendorLockResolver.php | 35 +++--- ...lassMethodVisibilityVendorLockResolver.php | 83 ++++---------- .../PropertyTypeVendorLockResolver.php | 79 ++++++-------- .../PropertyVisibilityVendorLockResolver.php | 61 +++++------ phpstan.neon | 56 +++++++++- .../CallableClassMethodMatcher.php | 8 -- .../NodeFactory/AnonymousFunctionFactory.php | 8 -- .../ArrayThisCallToThisMethodCallRector.php | 27 +++-- .../CompleteDynamicPropertiesRector.php | 44 ++++++-- ...OnPropertyObjectToPropertyExistsRector.php | 30 ++++-- ...itedMethodVisibilitySameAsParentRector.php | 8 +- .../ClassUnusedPrivateClassMethodResolver.php | 48 ++++++--- .../ParentClassMethodTypeOverrideGuard.php | 14 +-- .../PhpDocParser/DoctrineDocBlockResolver.php | 13 ++- ...AddUuidMirrorForRelationPropertyRector.php | 17 ++- .../DowngradeParameterTypeWideningRector.php | 52 +++++---- ...wngradeContravariantArgumentTypeRector.php | 35 +++--- .../DowngradeCovariantReturnTypeRector.php | 6 +- .../MockistaMockToMockeryMockRector.php | 35 ++++-- .../naming/src/Guard/HasMagicGetSetGuard.php | 25 ++++- rules/naming/src/Naming/PropertyNaming.php | 12 ++- .../OnPropertyMagicCallProvider.php | 31 ++++-- .../nette-kdyby/src/Naming/VariableNaming.php | 13 +-- ...outerListToControllerAnnotationsRector.php | 38 +++++-- .../src/Route/RouteInfoFactory.php | 21 ++-- .../src/PHPUnitTypeDeclarationDecorator.php | 19 +++- ...isCallOnStaticMethodToStaticCallRector.php | 6 +- ...ticCallOnNonStaticToInstanceCallRector.php | 15 +-- .../src/NodeAnalyzer/CountableAnalyzer.php | 3 +- .../PrivatizeLocalClassConstantRector.php | 4 +- .../MakeOnlyUsedByChildrenProtectedRector.php | 27 +++-- .../PrivatizeFinalClassMethodRector.php | 31 ++++-- .../PrivatizeFinalClassPropertyRector.php | 29 ++--- .../ParentConstantReflectionResolver.php | 11 +- .../ClassMethodVisibilityGuard.php | 101 ++++++------------ ...llyCalledStaticMethodToNonStaticRector.php | 9 +- .../src/NodeManipulator/ClassRenamer.php | 38 ++++--- .../NodeManipulator/IdentifierManipulator.php | 20 ++-- .../CompleteMissingDependencyInNewRector.php | 4 +- .../FormTypeInstanceToClassConstRector.php | 7 +- .../src/PhpParserTypeAnalyzer.php | 19 +++- src/NodeAnalyzer/PropertyPresenceChecker.php | 13 +-- .../ChildAndParentClassManipulator.php | 31 ++++-- .../ClassDependencyManipulator.php | 23 +++- .../ClassMethodManipulator.php | 15 +-- src/PhpParser/Node/Value/ValueResolver.php | 6 +- src/Rector/AbstractTemporaryRector.php | 1 + .../ClassMethodReflectionFactory.php | 9 +- .../config/rector-rules.neon | 4 + 82 files changed, 986 insertions(+), 822 deletions(-) diff --git a/composer.json b/composer.json index e5105c01f54c..20a4f5a95d5d 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "nette/utils": "^3.2", "nikic/php-parser": "^4.10.4", "phpstan/phpdoc-parser": "^0.4.9", - "phpstan/phpstan": "^0.12.76", + "phpstan/phpstan": "dev-master", "phpstan/phpstan-phpunit": "^0.12.17", "psr/simple-cache": "^1.0", "sebastian/diff": "^4.0.4", diff --git a/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php b/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php index eca1e6137f06..924f2fe3674c 100644 --- a/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php +++ b/packages/better-php-doc-parser/src/AnnotationReader/NodeAnnotationReader.php @@ -11,6 +11,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\Php\PhpPropertyReflection; use PHPStan\Reflection\ReflectionProvider; use Rector\Core\Exception\ShouldNotHappenException; use Rector\DoctrineAnnotationGenerated\PhpDocNode\ConstantReferenceIdentifierRestorer; @@ -18,7 +19,6 @@ use Rector\NodeTypeResolver\Node\AttributeKey; use ReflectionMethod; use ReflectionProperty; -use Symplify\PackageBuilder\Reflection\PrivatesAccessor; use Throwable; final class NodeAnnotationReader @@ -48,23 +48,16 @@ final class NodeAnnotationReader */ private $reflectionProvider; - /** - * @var PrivatesAccessor - */ - private $privatesAccessor; - public function __construct( ConstantReferenceIdentifierRestorer $constantReferenceIdentifierRestorer, NodeNameResolver $nodeNameResolver, Reader $reader, - ReflectionProvider $reflectionProvider, - PrivatesAccessor $privatesAccessor + ReflectionProvider $reflectionProvider ) { $this->reader = $reader; $this->nodeNameResolver = $nodeNameResolver; $this->constantReferenceIdentifierRestorer = $constantReferenceIdentifierRestorer; $this->reflectionProvider = $reflectionProvider; - $this->privatesAccessor = $privatesAccessor; } public function readAnnotation(Node $node, string $annotationClass): ?object @@ -211,11 +204,12 @@ private function getNativePropertyReflection(Property $property): ?ReflectionPro try { $classReflection = $this->reflectionProvider->getClass($className); - $propertyScope = $property->getAttribute(AttributeKey::SCOPE); - $propertyReflection = $classReflection->getProperty($propertyName, $propertyScope); + $scope = $property->getAttribute(AttributeKey::SCOPE); - // @see https://github.com/phpstan/phpstan-src/commit/5fad625b7770b9c5beebb19ccc1a493839308fb4 - return $this->privatesAccessor->getPrivateProperty($propertyReflection, 'reflection'); + $propertyReflection = $classReflection->getProperty($propertyName, $scope); + if ($propertyReflection instanceof PhpPropertyReflection) { + return $propertyReflection->getNativeReflection(); + } } catch (Throwable $throwable) { // in case of PHPUnit property or just-added property return null; @@ -230,6 +224,7 @@ private function resolveNativeClassMethodReflection(string $className, string $m $classReflection = $this->reflectionProvider->getClass($className); $reflectionClass = $classReflection->getNativeReflection(); + return $reflectionClass->getMethod($methodName); } } diff --git a/packages/family-tree/src/NodeAnalyzer/ClassChildAnalyzer.php b/packages/family-tree/src/NodeAnalyzer/ClassChildAnalyzer.php index 70a188b4b2dd..f5772e9c9bf6 100644 --- a/packages/family-tree/src/NodeAnalyzer/ClassChildAnalyzer.php +++ b/packages/family-tree/src/NodeAnalyzer/ClassChildAnalyzer.php @@ -5,10 +5,10 @@ namespace Rector\FamilyTree\NodeAnalyzer; use PhpParser\Node\Stmt\Class_; +use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Reflection\ReflectionProvider; +use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; -use ReflectionClass; -use ReflectionMethod; final class ClassChildAnalyzer { @@ -17,31 +17,40 @@ final class ClassChildAnalyzer */ private $reflectionProvider; - public function __construct(ReflectionProvider $reflectionProvider) + /** + * @var NodeNameResolver + */ + private $nodeNameResolver; + + public function __construct(ReflectionProvider $reflectionProvider, NodeNameResolver $nodeNameResolver) { $this->reflectionProvider = $reflectionProvider; + $this->nodeNameResolver = $nodeNameResolver; } public function hasChildClassConstructor(Class_ $class): bool { - $childClasses = $this->getChildClasses($class); + $className = $this->nodeNameResolver->getName($class); + if ($className === null) { + return false; + } - foreach ($childClasses as $childClass) { - if (! $this->reflectionProvider->hasClass($childClass)) { - continue; - } + if (! $this->reflectionProvider->hasClass($className)) { + return false; + } - $reflectionClass = new ReflectionClass($childClass); - $constructorReflectionMethod = $reflectionClass->getConstructor(); - if (! $constructorReflectionMethod instanceof ReflectionMethod) { - continue; - } + $classReflection = $this->reflectionProvider->getClass($className); - if ($constructorReflectionMethod->class !== $childClass) { + foreach ($classReflection->getAncestors() as $childClassReflection) { + $constructorReflectionMethod = $childClassReflection->getConstructor(); + if (! $constructorReflectionMethod instanceof PhpMethodReflection) { continue; } - return true; + $methodDeclaringClassReflection = $constructorReflectionMethod->getDeclaringClass(); + if ($methodDeclaringClassReflection->getName() === $childClassReflection->getName()) { + return true; + } } return false; @@ -54,49 +63,24 @@ public function hasParentClassConstructor(Class_ $class): bool return false; } - /** @var string[] $classParents */ - $classParents = (array) class_parents($className); - - foreach ($classParents as $classParent) { - $parentReflectionClass = new ReflectionClass($classParent); - $constructMethodReflection = $parentReflectionClass->getConstructor(); - if (! $constructMethodReflection instanceof ReflectionMethod) { - continue; - } - - if ($constructMethodReflection->class !== $classParent) { - continue; - } - - return true; + if (! $this->reflectionProvider->hasClass($className)) { + return false; } - return false; - } - - /** - * @return class-string[] - */ - private function getChildClasses(Class_ $class): array - { - $className = $class->getAttribute(AttributeKey::CLASS_NAME); - if ($className === null) { - return []; - } + $classReflection = $this->reflectionProvider->getClass($className); - $childClasses = []; - foreach (get_declared_classes() as $declaredClass) { - if (! is_a($declaredClass, $className, true)) { + foreach ($classReflection->getParents() as $parentClassReflections) { + $constructMethodReflection = $parentClassReflections->getConstructor(); + if (! $constructMethodReflection instanceof PhpMethodReflection) { continue; } - if ($declaredClass === $className) { - continue; + $methodDeclaringMethodClass = $constructMethodReflection->getDeclaringClass(); + if ($methodDeclaringMethodClass->getName() === $parentClassReflections->getName()) { + return true; } - - $childClasses[] = $declaredClass; } - return $childClasses; + return false; } } diff --git a/packages/family-tree/src/NodeAnalyzer/PropertyUsageAnalyzer.php b/packages/family-tree/src/NodeAnalyzer/PropertyUsageAnalyzer.php index ce90d84f3fff..58e32f243610 100644 --- a/packages/family-tree/src/NodeAnalyzer/PropertyUsageAnalyzer.php +++ b/packages/family-tree/src/NodeAnalyzer/PropertyUsageAnalyzer.php @@ -61,10 +61,10 @@ public function isPropertyFetchedInChildClass(Property $property): bool $propertyName = $this->nodeNameResolver->getName($property); - $childrenClassNames = $this->familyRelationsAnalyzer->getChildrenOfClass($className); - foreach ($childrenClassNames as $childClassName) { - $childClass = $this->nodeRepository->findClass($childClassName); - if (! $childClass instanceof Class_) { + $childrenClassReflections = $this->familyRelationsAnalyzer->getChildrenOfClass($className); + foreach ($childrenClassReflections as $childClassReflection) { + $childClass = $this->nodeRepository->findClass($childClassReflection->getName()); + if ($childClass === null) { continue; } diff --git a/packages/family-tree/src/Reflection/FamilyRelationsAnalyzer.php b/packages/family-tree/src/Reflection/FamilyRelationsAnalyzer.php index 558fc557e229..592e42f6bb01 100644 --- a/packages/family-tree/src/Reflection/FamilyRelationsAnalyzer.php +++ b/packages/family-tree/src/Reflection/FamilyRelationsAnalyzer.php @@ -4,27 +4,28 @@ namespace Rector\FamilyTree\Reflection; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ReflectionProvider; + final class FamilyRelationsAnalyzer { /** - * @return class-string[] + * @var ReflectionProvider */ - public function getChildrenOfClass(string $parentClass): array - { - $childrenClasses = []; - foreach (get_declared_classes() as $declaredClass) { - if ($declaredClass === $parentClass) { - continue; - } - - if (! is_a($declaredClass, $parentClass, true)) { - continue; - } + private $reflectionProvider; - $childrenClasses[] = $declaredClass; - } + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } - return $childrenClasses; + /** + * @return ClassReflection[] + */ + public function getChildrenOfClass(string $className): array + { + $classReflection = $this->reflectionProvider->getClass($className); + return $classReflection->getAncestors(); } public function isParentClass(string $class): bool diff --git a/packages/node-collector/src/NodeCollector/NodeRepository.php b/packages/node-collector/src/NodeCollector/NodeRepository.php index 8c28832b630c..034eace81997 100644 --- a/packages/node-collector/src/NodeCollector/NodeRepository.php +++ b/packages/node-collector/src/NodeCollector/NodeRepository.php @@ -663,7 +663,16 @@ private function collectArray(Array_ $array): void return; } - if (! $arrayCallable->isExistingMethod()) { + if (! $this->reflectionProvider->hasClass($arrayCallable->getClass())) { + return; + } + + $classReflection = $this->reflectionProvider->getClass($arrayCallable->getClass()); + if ($classReflection->isClass()) { + return; + } + + if (! $classReflection->hasMethod($arrayCallable->getMethod())) { return; } diff --git a/packages/node-collector/src/NodeCollector/ParsedClassConstFetchNodeCollector.php b/packages/node-collector/src/NodeCollector/ParsedClassConstFetchNodeCollector.php index 6b59d859dc8c..685edcdb51a6 100644 --- a/packages/node-collector/src/NodeCollector/ParsedClassConstFetchNodeCollector.php +++ b/packages/node-collector/src/NodeCollector/ParsedClassConstFetchNodeCollector.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\ClassConstFetch; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use PHPStan\Type\TypeUtils; @@ -13,7 +14,6 @@ use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; -use ReflectionClass; final class ParsedClassConstFetchNodeCollector { @@ -32,9 +32,15 @@ final class ParsedClassConstFetchNodeCollector */ private $nodeTypeResolver; - public function __construct(NodeNameResolver $nodeNameResolver) + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider) { $this->nodeNameResolver = $nodeNameResolver; + $this->reflectionProvider = $reflectionProvider; } /** @@ -137,14 +143,16 @@ private function matchClassTypeThatContainsConstant(Type $type, string $constant */ private function getConstantsDefinedInClass(string $className): array { - $reflectionClass = new ReflectionClass($className); + if (! $this->reflectionProvider->hasClass($className)) { + return []; + } - $constants = $reflectionClass->getConstants(); + $classReflection = $this->reflectionProvider->getClass($className); + $nativeClassReflection = $classReflection->getNativeReflection(); + $constants = $nativeClassReflection->getConstants(); $currentClassConstants = array_keys($constants); - $parentClassReflection = $reflectionClass->getParentClass(); - - if (! $parentClassReflection) { + if ($classReflection->getParentClass() !== false) { return $currentClassConstants; } diff --git a/packages/node-collector/src/Reflection/MethodReflectionProvider.php b/packages/node-collector/src/Reflection/MethodReflectionProvider.php index 85658da4aa1c..6a193d80c8eb 100644 --- a/packages/node-collector/src/Reflection/MethodReflectionProvider.php +++ b/packages/node-collector/src/Reflection/MethodReflectionProvider.php @@ -21,7 +21,6 @@ use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; -use ReflectionMethod; final class MethodReflectionProvider { @@ -70,7 +69,7 @@ public function provideParameterTypesFromMethodReflection(MethodReflection $meth return $parameterTypes; } - public function provideByMethodCall(MethodCall $methodCall): ?ReflectionMethod + public function provideByMethodCall(MethodCall $methodCall): ?MethodReflection { $className = $methodCall->getAttribute(AttributeKey::CLASS_NAME); if (! is_string($className)) { @@ -82,11 +81,16 @@ public function provideByMethodCall(MethodCall $methodCall): ?ReflectionMethod return null; } - if (! method_exists($className, $methodName)) { + if (! $this->reflectionProvider->hasClass($className)) { return null; } - return new ReflectionMethod($className, $methodName); + $classReflection = $this->reflectionProvider->getClass($className); + if (! $classReflection->hasMethod($methodName)) { + return null; + } + + return $classReflection->getNativeMethod($methodName); } public function provideByClassAndMethodName(string $class, string $method, Scope $scope): ?MethodReflection @@ -174,16 +178,24 @@ public function getParameterReflectionsFromMethodReflection(MethodReflection $me public function provideParameterNamesByNew(New_ $new): array { $objectType = $this->nodeTypeResolver->resolve($new->class); + $classes = TypeUtils::getDirectClassNames($objectType); $parameterNames = []; foreach ($classes as $class) { - if (! method_exists($class, MethodName::CONSTRUCT)) { + if (! $this->reflectionProvider->hasClass($class)) { continue; } - $methodReflection = new ReflectionMethod($class, MethodName::CONSTRUCT); + $classReflection = $this->reflectionProvider->getClass($class); + if (! $classReflection->hasMethod(MethodName::CONSTRUCT)) { + continue; + } + + $nativeClassReflection = $classReflection->getNativeReflection(); + $methodReflection = $nativeClassReflection->getMethod(MethodName::CONSTRUCT); + foreach ($methodReflection->getParameters() as $reflectionParameter) { $parameterNames[] = $reflectionParameter->name; } diff --git a/packages/node-collector/src/StaticAnalyzer.php b/packages/node-collector/src/StaticAnalyzer.php index a9bd0c3d02f7..78013c78981f 100644 --- a/packages/node-collector/src/StaticAnalyzer.php +++ b/packages/node-collector/src/StaticAnalyzer.php @@ -5,9 +5,9 @@ namespace Rector\NodeCollector; use Nette\Utils\Strings; +use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use Rector\NodeCollector\NodeCollector\NodeRepository; -use ReflectionClass; final class StaticAnalyzer { @@ -40,25 +40,29 @@ public function isStaticMethod(string $methodName, string $className): bool return false; } - $reflectionClass = new ReflectionClass($className); - if ($this->hasStaticAnnotation($methodName, $reflectionClass)) { + $classReflection = $this->reflectionProvider->getClass($className); + if ($this->hasStaticAnnotation($methodName, $classReflection)) { return true; } // probably magic method → we don't know - if (! method_exists($className, $methodName)) { + if (! $classReflection->hasMethod($methodName)) { return false; } - $methodReflection = $reflectionClass->getMethod($methodName); - + $methodReflection = $classReflection->getNativeMethod($methodName); return $methodReflection->isStatic(); } - private function hasStaticAnnotation(string $methodName, ReflectionClass $reflectionClass): bool + private function hasStaticAnnotation(string $methodName, ClassReflection $classReflection): bool { + $resolvedPhpDoc = $classReflection->getResolvedPhpDoc(); + if ($resolvedPhpDoc === null) { + return false; + } + return (bool) Strings::match( - (string) $reflectionClass->getDocComment(), + $resolvedPhpDoc->getPhpDocString(), '#@method\s*static\s*(.*?)\b' . $methodName . '\b#' ); } diff --git a/packages/node-collector/src/ValueObject/ArrayCallable.php b/packages/node-collector/src/ValueObject/ArrayCallable.php index 1c7a0bc99f1e..f0198b4d3c00 100644 --- a/packages/node-collector/src/ValueObject/ArrayCallable.php +++ b/packages/node-collector/src/ValueObject/ArrayCallable.php @@ -34,11 +34,6 @@ public function getMethod(): string return $this->method; } - public function isExistingMethod(): bool - { - return method_exists($this->class, $this->method); - } - public function getReflectionMethod(): ReflectionMethod { return new ReflectionMethod($this->class, $this->method); diff --git a/packages/node-type-resolver/config/phpstan/static-reflection.neon b/packages/node-type-resolver/config/phpstan/static-reflection.neon index efd5a7e2de95..534aab723875 100644 --- a/packages/node-type-resolver/config/phpstan/static-reflection.neon +++ b/packages/node-type-resolver/config/phpstan/static-reflection.neon @@ -10,6 +10,6 @@ services: # basically decorates native PHPStan source locator with a dynamic source locator that is also available in Rector DI betterReflectionSourceLocator: - class: _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator + class: PHPStan\BetterReflection\SourceLocator\Type\SourceLocator factory: ['@Rector\NodeTypeResolver\Reflection\BetterReflection\RectorBetterReflectionSourceLocatorFactory', 'create'] autowired: false diff --git a/packages/node-type-resolver/src/NodeTypeResolver/ArrayDimFetchTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/ArrayDimFetchTypeResolver.php index 590c919ddc4f..725c52c8ecef 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/ArrayDimFetchTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/ArrayDimFetchTypeResolver.php @@ -27,7 +27,7 @@ public function autowireArrayDimFetchTypeResolver(NodeTypeResolver $nodeTypeReso } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/CastTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/CastTypeResolver.php index 5339b710374b..51298786b5c2 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/CastTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/CastTypeResolver.php @@ -26,7 +26,7 @@ public function autowireCastTypeResolver(NodeTypeResolver $nodeTypeResolver): vo } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/ClassAndInterfaceTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/ClassAndInterfaceTypeResolver.php index 332cfe52487b..302062d4af7a 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/ClassAndInterfaceTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/ClassAndInterfaceTypeResolver.php @@ -35,7 +35,7 @@ public function __construct(ClassReflectionTypesResolver $classReflectionTypesRe } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/ClassConstFetchTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/ClassConstFetchTypeResolver.php index cd6a6786c6e6..23c5b6135c9c 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/ClassConstFetchTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/ClassConstFetchTypeResolver.php @@ -26,7 +26,7 @@ public function autowireClassConstFetchTypeResolver(NodeTypeResolver $nodeTypeRe } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php index b63db658d675..c9bc8c9add3f 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php @@ -31,7 +31,7 @@ public function autowireClassMethodOrClassConstTypeResolver(NodeTypeResolver $no } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/NameTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/NameTypeResolver.php index 90fb50aca9b2..e786bc108da4 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/NameTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/NameTypeResolver.php @@ -20,7 +20,7 @@ final class NameTypeResolver implements NodeTypeResolverInterface { /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/ParamTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/ParamTypeResolver.php index e256035e9c4b..e53f14f1e1f1 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/ParamTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/ParamTypeResolver.php @@ -75,7 +75,7 @@ public function autowireParamTypeResolver( } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/PropertyFetchTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/PropertyFetchTypeResolver.php index 8d509c45eaf2..0f0a5d8d3a12 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/PropertyFetchTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/PropertyFetchTypeResolver.php @@ -20,7 +20,6 @@ use PHPStan\Type\MixedType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; -use PHPStan\Type\TypeWithClassName; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\NodeCollector\NodeCollector\NodeRepository; @@ -104,7 +103,7 @@ public function autowirePropertyFetchTypeResolver(NodeTypeResolver $nodeTypeReso } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { @@ -153,12 +152,12 @@ public function resolve(Node $node): Type private function getVendorPropertyFetchType(PropertyFetch $propertyFetch): Type { $varObjectType = $this->nodeTypeResolver->resolve($propertyFetch->var); - if (! $varObjectType instanceof TypeWithClassName) { + if (! $varObjectType instanceof ObjectType) { return new MixedType(); } - $class = $this->nodeRepository->findClass($varObjectType->getClassName()); - if ($class !== null) { + $classReflection = $varObjectType->getClassReflection(); + if ($classReflection === null) { return new MixedType(); } @@ -168,7 +167,7 @@ private function getVendorPropertyFetchType(PropertyFetch $propertyFetch): Type return new MixedType(); } - if (! property_exists($varObjectType->getClassName(), $propertyName)) { + if (! $classReflection->hasProperty($propertyName)) { return new MixedType(); } diff --git a/packages/node-type-resolver/src/NodeTypeResolver/PropertyTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/PropertyTypeResolver.php index 36a50cdf14d0..c5083363b54e 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/PropertyTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/PropertyTypeResolver.php @@ -32,7 +32,7 @@ public function autowirePropertyTypeResolver(NodeTypeResolver $nodeTypeResolver) } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/NodeTypeResolver/StaticCallTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/StaticCallTypeResolver.php index 1a02a01c05eb..2ab90a971aa6 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/StaticCallTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/StaticCallTypeResolver.php @@ -7,8 +7,9 @@ use PhpParser\Node; use PhpParser\Node\Expr\StaticCall; use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Type\ObjectType; use PHPStan\Type\Type; -use PHPStan\Type\TypeUtils; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -40,7 +41,7 @@ public function autowireStaticCallTypeResolver(NodeTypeResolver $nodeTypeResolve } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { @@ -60,15 +61,24 @@ public function resolve(Node $node): Type return $classType; } - $classNames = TypeUtils::getDirectClassNames($classType); + if (! $classType instanceof ObjectType) { + return $classType; + } + + $classReflection = $classType->getClassReflection(); + if ($classReflection === null) { + return $classType; + } $scope = $node->getAttribute(AttributeKey::SCOPE); if (! $scope instanceof Scope) { return $classType; } - foreach ($classNames as $className) { - if (! method_exists($className, $methodName)) { + /** @var ClassReflection[] $currentAndParentClassReflections */ + $currentAndParentClassReflections = array_merge([$classReflection], $classReflection->getParents()); + foreach ($currentAndParentClassReflections as $currentAndParentClassReflection) { + if (! $currentAndParentClassReflection->hasMethod($methodName)) { continue; } diff --git a/packages/node-type-resolver/src/NodeTypeResolver/TraitTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/TraitTypeResolver.php index f0e10ce044a4..89d5595d8788 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/TraitTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/TraitTypeResolver.php @@ -6,12 +6,12 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Trait_; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\MixedType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use PHPStan\Type\UnionType; use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface; -use ReflectionClass; /** * @see \Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\TraitTypeResolver\TraitTypeResolverTest @@ -19,7 +19,17 @@ final class TraitTypeResolver implements NodeTypeResolverInterface { /** - * @return string[] + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + + /** + * @return array> */ public function getNodeClasses(): array { @@ -31,12 +41,17 @@ public function getNodeClasses(): array */ public function resolve(Node $traitNode): Type { - $reflectionClass = new ReflectionClass((string) $traitNode->namespacedName); + $traitName = (string) $traitNode->namespacedName; + if (! $this->reflectionProvider->hasClass($traitName)) { + return new MixedType(); + } + + $traitReflection = $this->reflectionProvider->getClass($traitName); $types = []; - $types[] = new ObjectType($reflectionClass->getName()); + $types[] = new ObjectType($traitName); - foreach ($reflectionClass->getTraits() as $usedTraitReflection) { + foreach ($traitReflection->getTraits() as $usedTraitReflection) { $types[] = new ObjectType($usedTraitReflection->getName()); } diff --git a/packages/node-type-resolver/src/NodeTypeResolver/VariableTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver/VariableTypeResolver.php index 70a127d7e5a4..7b6cf21972bf 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver/VariableTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver/VariableTypeResolver.php @@ -59,7 +59,7 @@ public function __construct( } /** - * @return string[] + * @return array> */ public function getNodeClasses(): array { diff --git a/packages/node-type-resolver/src/PHPStan/TypeHasher.php b/packages/node-type-resolver/src/PHPStan/TypeHasher.php index 2458132848a6..7a50cd31b5f9 100644 --- a/packages/node-type-resolver/src/PHPStan/TypeHasher.php +++ b/packages/node-type-resolver/src/PHPStan/TypeHasher.php @@ -4,7 +4,6 @@ namespace Rector\NodeTypeResolver\PHPStan; -use PHPStan\ShouldNotHappenException; use PHPStan\Type\ArrayType; use PHPStan\Type\ConstantType; use PHPStan\Type\Generic\GenericObjectType; @@ -54,11 +53,7 @@ private function createTypeHash(Type $type): string } if ($type instanceof ConstantType) { - if (method_exists($type, 'getValue')) { - return get_class($type) . $type->getValue(); - } - - throw new ShouldNotHappenException(); + return get_class($type) . $type->getValue(); } if ($type instanceof UnionType) { diff --git a/packages/node-type-resolver/src/Reflection/BetterReflection/RectorBetterReflectionSourceLocatorFactory.php b/packages/node-type-resolver/src/Reflection/BetterReflection/RectorBetterReflectionSourceLocatorFactory.php index 726457893044..4ce347b80995 100644 --- a/packages/node-type-resolver/src/Reflection/BetterReflection/RectorBetterReflectionSourceLocatorFactory.php +++ b/packages/node-type-resolver/src/Reflection/BetterReflection/RectorBetterReflectionSourceLocatorFactory.php @@ -4,8 +4,8 @@ namespace Rector\NodeTypeResolver\Reflection\BetterReflection; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\AggregateSourceLocator; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator; +use PHPStan\BetterReflection\SourceLocator\Type\AggregateSourceLocator; +use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator; use PHPStan\Reflection\BetterReflection\BetterReflectionSourceLocatorFactory; use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator\IntermediateSourceLocator; diff --git a/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php b/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php index 278c2b0a6802..1fd093daefe4 100644 --- a/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php +++ b/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php @@ -4,11 +4,11 @@ namespace Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\Identifier\Identifier; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\Identifier\IdentifierType; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\Reflection\Reflection; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\Reflector\Reflector; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator; +use PHPStan\BetterReflection\Identifier\Identifier; +use PHPStan\BetterReflection\Identifier\IdentifierType; +use PHPStan\BetterReflection\Reflection\Reflection; +use PHPStan\BetterReflection\Reflector\Reflector; +use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator; use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocator; final class IntermediateSourceLocator implements SourceLocator diff --git a/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocator.php b/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocator.php index 4dd0b33cc19a..9d2dd0434fc1 100644 --- a/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocator.php +++ b/packages/node-type-resolver/src/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocator.php @@ -4,8 +4,8 @@ namespace Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\AggregateSourceLocator; -use _HumbugBoxfac515c46e83\Roave\BetterReflection\SourceLocator\Type\SourceLocator; +use PHPStan\BetterReflection\SourceLocator\Type\AggregateSourceLocator; +use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator; use PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher; use PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedSingleFileSourceLocator; use Symplify\SmartFileSystem\SmartFileInfo; diff --git a/packages/phpstan-static-type-mapper/src/TypeAnalyzer/UnionTypeCommonTypeNarrower.php b/packages/phpstan-static-type-mapper/src/TypeAnalyzer/UnionTypeCommonTypeNarrower.php index 07cc734a609f..6974dbe75556 100644 --- a/packages/phpstan-static-type-mapper/src/TypeAnalyzer/UnionTypeCommonTypeNarrower.php +++ b/packages/phpstan-static-type-mapper/src/TypeAnalyzer/UnionTypeCommonTypeNarrower.php @@ -4,16 +4,15 @@ namespace Rector\PHPStanStaticTypeMapper\TypeAnalyzer; -use Nette\Utils\Strings; use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Expr\BinaryOp; use PhpParser\Node\Stmt; +use PHPStan\Reflection\ClassReflection; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\Generic\GenericClassStringType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; -use PHPStan\Type\TypeWithClassName; use PHPStan\Type\UnionType; use Rector\NodeTypeResolver\NodeTypeCorrector\GenericClassStringTypeCorrector; @@ -79,8 +78,11 @@ public function narrowToGenericClassStringType(UnionType $unionType): Type return $unionType; } - if ($unionedType->getGenericType() instanceof TypeWithClassName) { - $availableTypes[] = $this->resolveClassParentClassesAndInterfaces($unionedType->getGenericType()); + if ($unionedType->getGenericType() instanceof ObjectType) { + $parentClassReflections = $this->resolveClassParentClassesAndInterfaces($unionedType->getGenericType()); + foreach ($parentClassReflections as $classReflection) { + $availableTypes[] = $classReflection->getName(); + } } } @@ -93,64 +95,48 @@ public function narrowToGenericClassStringType(UnionType $unionType): Type } /** - * @return string[] + * @return class-string[] */ private function narrowToSharedTypes(UnionType $unionType): array { $availableTypes = []; foreach ($unionType->getTypes() as $unionedType) { - if (! $unionedType instanceof TypeWithClassName) { + if (! $unionedType instanceof ObjectType) { return []; } - $availableTypes[] = $this->resolveClassParentClassesAndInterfaces($unionedType); + $typeClassReflections = $this->resolveClassParentClassesAndInterfaces($unionedType); + foreach ($typeClassReflections as $classReflection) { + $availableTypes[] = $classReflection->getName(); + } } return $this->narrowAvailableTypes($availableTypes); } /** - * @return string[] + * @return ClassReflection[] */ - private function resolveClassParentClassesAndInterfaces(TypeWithClassName $typeWithClassName): array + private function resolveClassParentClassesAndInterfaces(ObjectType $objectType): array { - $parentClasses = class_parents($typeWithClassName->getClassName()); - if ($parentClasses === false) { - $parentClasses = []; + $classReflection = $objectType->getClassReflection(); + if ($classReflection === null) { + return []; } - $implementedInterfaces = class_implements($typeWithClassName->getClassName()); - if ($implementedInterfaces === false) { - $implementedInterfaces = []; - } - - $implementedInterfaces = $this->filterOutNativeInterfaces($implementedInterfaces); - // put earliest interfaces first - $implementedInterfaces = array_reverse($implementedInterfaces); - - $classParentClassesAndInterfaces = array_merge($implementedInterfaces, $parentClasses); + $implementedInterfaceClassReflections = array_reverse($classReflection->getInterfaces()); - return array_unique($classParentClassesAndInterfaces); - } - - /** - * @param class-string[] $interfaces - * @return class-string[] - */ - private function filterOutNativeInterfaces(array $interfaces): array - { - foreach ($interfaces as $key => $implementedInterface) { - // remove native interfaces - if (Strings::contains($implementedInterface, '\\')) { - continue; - } - - unset($interfaces[$key]); - } + /** @var ClassReflection[] $parentClassAndInterfaceReflections */ + $parentClassAndInterfaceReflections = array_merge( + $implementedInterfaceClassReflections, + $classReflection->getParents() + ); - return $interfaces; + return array_filter($parentClassAndInterfaceReflections, function (ClassReflection $classReflection): bool { + return ! $classReflection->isInternal(); + }); } /** diff --git a/packages/post-rector/src/NodeAnalyzer/NetteInjectDetector.php b/packages/post-rector/src/NodeAnalyzer/NetteInjectDetector.php index 3fd9b70e1acb..86ebc90301f1 100644 --- a/packages/post-rector/src/NodeAnalyzer/NetteInjectDetector.php +++ b/packages/post-rector/src/NodeAnalyzer/NetteInjectDetector.php @@ -87,14 +87,13 @@ private function hasParentClassConstructor(Class_ $class): bool // prefer local constructor $classReflection = $this->reflectionProvider->getClass($className); + if ($classReflection->hasMethod(MethodName::CONSTRUCT)) { $constructorReflectionMethod = $classReflection->getConstructor(); - - $declaringClassName = $constructorReflectionMethod->getDeclaringClass() - ->getName(); + $declaringClass = $constructorReflectionMethod->getDeclaringClass(); // be sure its local constructor - if ($declaringClassName === $className) { + if ($declaringClass->getName() === $className) { return false; } } diff --git a/packages/rector-generator/src/Provider/NodeTypesProvider.php b/packages/rector-generator/src/Provider/NodeTypesProvider.php index 83060c1eb9f1..82d8590816cd 100644 --- a/packages/rector-generator/src/Provider/NodeTypesProvider.php +++ b/packages/rector-generator/src/Provider/NodeTypesProvider.php @@ -29,8 +29,7 @@ final class NodeTypesProvider public function provide(): array { $finder = new Finder(); - $finder = $finder - ->files() + $finder = $finder->files() ->in(self::PHP_PARSER_NODES_PATH); $fileInfos = iterator_to_array($finder->getIterator()); @@ -44,6 +43,7 @@ public function provide(): array if ($reflectionClass->isAbstract()) { continue; } + if ($reflectionClass->isInterface()) { continue; } diff --git a/packages/vendor-locker/src/NodeVendorLocker/AbstractNodeVendorLockResolver.php b/packages/vendor-locker/src/NodeVendorLocker/AbstractNodeVendorLockResolver.php index 4f5507cb11b2..1a36df289147 100644 --- a/packages/vendor-locker/src/NodeVendorLocker/AbstractNodeVendorLockResolver.php +++ b/packages/vendor-locker/src/NodeVendorLocker/AbstractNodeVendorLockResolver.php @@ -4,14 +4,11 @@ namespace Rector\VendorLocker\NodeVendorLocker; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\Interface_; +use PHPStan\Reflection\ClassReflection; use Rector\Core\NodeManipulator\ClassManipulator; use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer; use Rector\NodeCollector\NodeCollector\NodeRepository; use Rector\NodeNameResolver\NodeNameResolver; -use Rector\NodeTypeResolver\Node\AttributeKey; abstract class AbstractNodeVendorLockResolver { @@ -50,63 +47,35 @@ public function autowireAbstractNodeVendorLockResolver( $this->familyRelationsAnalyzer = $familyRelationsAnalyzer; } - protected function hasParentClassChildrenClassesOrImplementsInterface(ClassLike $classLike): bool + protected function hasParentClassChildrenClassesOrImplementsInterface(ClassReflection $classReflection): bool { - if (($classLike instanceof Class_ || $classLike instanceof Interface_) && $classLike->extends) { - return true; - } + if ($classReflection->isClass()) { + if ($classReflection->getParents()) { + return true; + } - if ($classLike instanceof Class_) { - if ((bool) $classLike->implements) { + if ($classReflection->getInterfaces() !== []) { return true; } - /** @var Class_ $classLike */ - return $this->getChildrenClassesByClass($classLike) !== []; + return $classReflection->getAncestors() !== []; } - return false; - } - - /** - * @param Class_|Interface_ $classLike - */ - protected function isMethodVendorLockedByInterface(ClassLike $classLike, string $methodName): bool - { - $interfaceNames = $this->classManipulator->getClassLikeNodeParentInterfaceNames($classLike); - - foreach ($interfaceNames as $interfaceName) { - if (! $this->hasInterfaceMethod($methodName, $interfaceName)) { - continue; - } - + if ($classReflection->isInterface() && $classReflection->getInterfaces()) { return true; } return false; } - /** - * @return class-string[] - */ - protected function getChildrenClassesByClass(Class_ $class): array - { - $desiredClassName = $class->getAttribute(AttributeKey::CLASS_NAME); - if ($desiredClassName === null) { - return []; - } - - return $this->familyRelationsAnalyzer->getChildrenOfClass($desiredClassName); - } - - private function hasInterfaceMethod(string $methodName, string $interfaceName): bool + protected function isMethodVendorLockedByInterface(ClassReflection $classReflection, string $methodName): bool { - if (! interface_exists($interfaceName)) { - return false; + foreach ($classReflection->getInterfaces() as $interfaceReflection) { + if ($interfaceReflection->hasMethod($methodName)) { + return true; + } } - $interfaceMethods = get_class_methods($interfaceName); - - return in_array($methodName, $interfaceMethods, true); + return false; } } diff --git a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodParamVendorLockResolver.php b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodParamVendorLockResolver.php index b4d2262f8166..100b31fe7dbd 100644 --- a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodParamVendorLockResolver.php +++ b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodParamVendorLockResolver.php @@ -4,49 +4,72 @@ namespace Rector\VendorLocker\NodeVendorLocker; -use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Interface_; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ReflectionProvider; use Rector\NodeTypeResolver\Node\AttributeKey; final class ClassMethodParamVendorLockResolver extends AbstractNodeVendorLockResolver { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + public function isVendorLocked(ClassMethod $classMethod, int $paramPosition): bool { - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if (! $classNode instanceof Class_) { + /** @var Scope $scope */ + $scope = $classMethod->getAttribute(AttributeKey::SCOPE); + + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { return false; } - if (! $this->hasParentClassChildrenClassesOrImplementsInterface($classNode)) { + if (! $this->hasParentClassChildrenClassesOrImplementsInterface($classReflection)) { return false; } /** @var string $methodName */ $methodName = $this->nodeNameResolver->getName($classMethod); - /** @var string|null $parentClassName */ - $parentClassName = $classMethod->getAttribute(AttributeKey::PARENT_CLASS_NAME); - if ($parentClassName !== null) { - $vendorLock = $this->isParentClassVendorLocking($paramPosition, $parentClassName, $methodName); +// /** @var string|null $parentClassName */ +// $parentClassName = $classMethod->getAttribute(AttributeKey::PARENT_CLASS_NAME); + + if ($classReflection->getParentClass() !== false) { + $vendorLock = $this->isParentClassVendorLocking( + $classReflection->getParentClass(), + $paramPosition, + $methodName + ); if ($vendorLock !== null) { return $vendorLock; } } - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if ($classNode instanceof Class_) { - return $this->isMethodVendorLockedByInterface($classNode, $methodName); + if ($classReflection->isClass()) { + return $this->isMethodVendorLockedByInterface($classReflection, $methodName); } - if ($classNode instanceof Interface_) { - return $this->isMethodVendorLockedByInterface($classNode, $methodName); + + if ($classReflection->isInterface()) { + return $this->isMethodVendorLockedByInterface($classReflection, $methodName); } + return false; } - private function isParentClassVendorLocking(int $paramPosition, string $parentClassName, string $methodName): ?bool - { - $parentClass = $this->nodeRepository->findClass($parentClassName); + private function isParentClassVendorLocking( + ClassReflection $parentClassReflection, + int $paramPosition, + string $methodName + ): ?bool { + $parentClass = $this->nodeRepository->findClass($parentClassReflection->getName()); if ($parentClass !== null) { $parentClassMethod = $parentClass->getMethod($methodName); // parent class method in local scope → it's ok @@ -58,7 +81,8 @@ private function isParentClassVendorLocking(int $paramPosition, string $parentCl return $parentClassMethod->params[$paramPosition]->type === null; } } - if (method_exists($parentClassName, $methodName)) { + + if ($parentClassReflection->hasMethod($methodName)) { // parent class method in external scope → it's not ok // if not, look for it's parent parent return true; diff --git a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodReturnVendorLockResolver.php b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodReturnVendorLockResolver.php index 6864cc3245c1..3882da75e2ed 100644 --- a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodReturnVendorLockResolver.php +++ b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodReturnVendorLockResolver.php @@ -4,47 +4,44 @@ namespace Rector\VendorLocker\NodeVendorLocker; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Interface_; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; use Rector\NodeTypeResolver\Node\AttributeKey; final class ClassMethodReturnVendorLockResolver extends AbstractNodeVendorLockResolver { public function isVendorLocked(ClassMethod $classMethod): bool { - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if (! $classNode instanceof ClassLike) { + /** @var Scope $scope */ + $scope = $classMethod->getAttribute(AttributeKey::SCOPE); + + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { return false; } - if (! $this->hasParentClassChildrenClassesOrImplementsInterface($classNode)) { + if (! $this->hasParentClassChildrenClassesOrImplementsInterface($classReflection)) { return false; } /** @var string $methodName */ $methodName = $this->nodeNameResolver->getName($classMethod); - /** @var string|null $parentClassName */ - $parentClassName = $classMethod->getAttribute(AttributeKey::PARENT_CLASS_NAME); - if ($parentClassName !== null) { - return $this->isVendorLockedByParentClass($parentClassName, $methodName); + if ($classReflection->getParentClass() instanceof ClassReflection) { + return $this->isVendorLockedByParentClass($classReflection, $methodName); } - $classNode = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if ($classNode instanceof Class_) { - return $this->isMethodVendorLockedByInterface($classNode, $methodName); - } - if ($classNode instanceof Interface_) { - return $this->isMethodVendorLockedByInterface($classNode, $methodName); + if ($classReflection->isTrait()) { + return false; } - return false; + + return $this->isMethodVendorLockedByInterface($classReflection, $methodName); } - private function isVendorLockedByParentClass(string $parentClassName, string $methodName): bool + private function isVendorLockedByParentClass(ClassReflection $classReflection, string $methodName): bool { - $parentClass = $this->nodeRepository->findClass($parentClassName); + $parentClass = $this->nodeRepository->findClass($classReflection->getName()); if ($parentClass !== null) { $parentClassMethod = $parentClass->getMethod($methodName); // validate type is conflicting @@ -58,6 +55,6 @@ private function isVendorLockedByParentClass(string $parentClassName, string $me // validate type is conflicting // parent class method in external scope → it's not ok - return method_exists($parentClassName, $methodName); + return $classReflection->hasMethod($methodName); } } diff --git a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVendorLockResolver.php b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVendorLockResolver.php index 93375dce0ddf..c1e68b1c269c 100644 --- a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVendorLockResolver.php +++ b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVendorLockResolver.php @@ -4,12 +4,11 @@ namespace Rector\VendorLocker\NodeVendorLocker; -use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Interface_; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Reflection\ReflectionProvider; use Rector\NodeTypeResolver\Node\AttributeKey; -use ReflectionClass; final class ClassMethodVendorLockResolver extends AbstractNodeVendorLockResolver { @@ -33,45 +32,41 @@ public function __construct(ReflectionProvider $reflectionProvider) */ public function isRemovalVendorLocked(ClassMethod $classMethod): bool { - /** @var string $classMethodName */ $classMethodName = $this->nodeNameResolver->getName($classMethod); - /** @var Class_|Interface_|null $classLike */ - $classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if ($classLike === null) { + /** @var Scope $scope */ + $scope = $classMethod->getAttribute(AttributeKey::SCOPE); + $classReflection = $scope->getClassReflection(); + if ($classReflection === null) { return false; } - if ($this->isMethodVendorLockedByInterface($classLike, $classMethodName)) { + if ($this->isMethodVendorLockedByInterface($classReflection, $classMethodName)) { return true; } - if ($classLike->extends === null) { + if ($classReflection->getParents() === []) { return false; } /** @var string $className */ $className = $classMethod->getAttribute(AttributeKey::CLASS_NAME); - /** @var string[] $classParents */ - $classParents = (array) class_parents($className); + $classReflection = $this->reflectionProvider->getClass($className); - foreach ($classParents as $classParent) { - if (! $this->reflectionProvider->hasClass($classParent)) { - continue; - } - - $parentClassReflection = new ReflectionClass($classParent); + foreach ($classReflection->getParents() as $parentClassReflection) { if (! $parentClassReflection->hasMethod($classMethodName)) { continue; } - $methodReflection = $parentClassReflection->getMethod($classMethodName); - if (! $methodReflection->isAbstract()) { + $methodReflection = $classReflection->getNativeMethod($classMethodName); + if (! $methodReflection instanceof PhpMethodReflection) { continue; } - return true; + if ($methodReflection->isAbstract()) { + return true; + } } return false; diff --git a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVisibilityVendorLockResolver.php b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVisibilityVendorLockResolver.php index 2fb0696c2fcf..1445b10dcb8a 100644 --- a/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVisibilityVendorLockResolver.php +++ b/packages/vendor-locker/src/NodeVendorLocker/ClassMethodVisibilityVendorLockResolver.php @@ -5,6 +5,8 @@ namespace Rector\VendorLocker\NodeVendorLocker; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Privatization\VisibilityGuard\ClassMethodVisibilityGuard; @@ -25,85 +27,46 @@ final class ClassMethodVisibilityVendorLockResolver extends AbstractNodeVendorLo */ public function isParentLockedMethod(ClassMethod $classMethod): bool { - /** @var string $className */ - $className = $classMethod->getAttribute(AttributeKey::CLASS_NAME); + /** @var Scope $scope */ + $scope = $classMethod->getAttribute(AttributeKey::SCOPE); - if ($this->isInterfaceMethod($classMethod, $className)) { - return true; + $classReflection = $scope->getClassReflection(); + if ($classReflection === null) { + return false; } - /** @var string $methodName */ $methodName = $this->nodeNameResolver->getName($classMethod); - return $this->hasParentMethod($className, $methodName); - } - - public function isChildLockedMethod(ClassMethod $classMethod): bool - { - /** @var string $className */ - $className = $classMethod->getAttribute(AttributeKey::CLASS_NAME); - - /** @var string $methodName */ - $methodName = $this->nodeNameResolver->getName($classMethod); - - return $this->hasChildMethod($className, $methodName); - } + /** @var ClassReflection[] $parentClassReflections */ + $parentClassReflections = array_merge($classReflection->getParents(), $classReflection->getInterfaces()); - private function isInterfaceMethod(ClassMethod $classMethod, string $className): bool - { - $interfaceMethodNames = $this->getInterfaceMethodNames($className); - return $this->nodeNameResolver->isNames($classMethod, $interfaceMethodNames); - } - - private function hasParentMethod(string $className, string $methodName): bool - { - /** @var string[] $parentClasses */ - $parentClasses = (array) class_parents($className); - - foreach ($parentClasses as $parentClass) { - if (! method_exists($parentClass, $methodName)) { - continue; + foreach ($parentClassReflections as $parentClassReflection) { + if ($parentClassReflection->hasMethod($methodName)) { + return true; } - - return true; } return false; } - private function hasChildMethod(string $desiredClassName, string $methodName): bool + public function isChildLockedMethod(ClassMethod $classMethod): bool { - foreach (get_declared_classes() as $className) { - if ($className === $desiredClassName) { - continue; - } + /** @var Scope $scope */ + $scope = $classMethod->getAttribute(AttributeKey::SCOPE); - if (! is_a($className, $desiredClassName, true)) { - continue; - } + $classReflection = $scope->getClassReflection(); + if ($classReflection === null) { + return false; + } - if (method_exists($className, $methodName)) { + $methodName = $this->nodeNameResolver->getName($classMethod); + + foreach ($classReflection->getAncestors() as $childClassReflection) { + if ($childClassReflection->hasMethod($methodName)) { return true; } } return false; } - - /** - * @return string[] - */ - private function getInterfaceMethodNames(string $className): array - { - /** @var string[] $interfaces */ - $interfaces = (array) class_implements($className); - - $interfaceMethods = []; - foreach ($interfaces as $interface) { - $currentInterfaceMethods = get_class_methods($interface); - $interfaceMethods = array_merge($interfaceMethods, $currentInterfaceMethods); - } - - return $interfaceMethods; - } } diff --git a/packages/vendor-locker/src/NodeVendorLocker/PropertyTypeVendorLockResolver.php b/packages/vendor-locker/src/NodeVendorLocker/PropertyTypeVendorLockResolver.php index 183bae687cb0..f8e1a44a5c77 100644 --- a/packages/vendor-locker/src/NodeVendorLocker/PropertyTypeVendorLockResolver.php +++ b/packages/vendor-locker/src/NodeVendorLocker/PropertyTypeVendorLockResolver.php @@ -4,94 +4,77 @@ namespace Rector\VendorLocker\NodeVendorLocker; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Property; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; use Rector\NodeTypeResolver\Node\AttributeKey; -use ReflectionProperty; final class PropertyTypeVendorLockResolver extends AbstractNodeVendorLockResolver { public function isVendorLocked(Property $property): bool { - $classLike = $property->getAttribute(AttributeKey::CLASS_NODE); - if (! $classLike instanceof Class_) { + /** @var Scope $scope */ + $scope = $property->getAttribute(AttributeKey::SCOPE); + + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { return false; } - /** @var Class_|Interface_ $classLike */ - if (! $this->hasParentClassChildrenClassesOrImplementsInterface($classLike)) { + if (! $this->hasParentClassChildrenClassesOrImplementsInterface($classReflection)) { return false; } /** @var string $propertyName */ $propertyName = $this->nodeNameResolver->getName($property); - if ($this->isParentClassLocked($classLike, $propertyName)) { + if ($this->isParentClassLocked($classReflection, $propertyName)) { return true; } - return $this->isChildClassLocked($property, $classLike, $propertyName); + return $this->isChildClassLocked($property, $classReflection, $propertyName); } - /** - * @param Class_|Interface_ $classLike - */ - private function isParentClassLocked(ClassLike $classLike, string $propertyName): bool + private function isParentClassLocked(ClassReflection $classReflection, string $propertyName): bool { - if (! $classLike instanceof Class_) { - return false; - } - // extract to some "inherited parent method" service - /** @var string|null $parentClassName */ - $parentClassName = $classLike->getAttribute(AttributeKey::PARENT_CLASS_NAME); - if ($parentClassName === null) { - return false; - } - - // if not, look for it's parent parent - recursion - - if (property_exists($parentClassName, $propertyName)) { - // validate type is conflicting - // parent class property in external scope → it's not ok - return true; - - // if not, look for it's parent parent + foreach ($classReflection->getParents() as $parentClassReflection) { + if ($parentClassReflection->hasProperty($propertyName)) { + // validate type is conflicting + // parent class property in external scope → it's not ok + return true; + } } return false; } - /** - * @param Class_|Interface_ $classLike - */ - private function isChildClassLocked(Property $property, ClassLike $classLike, string $propertyName): bool - { - if (! $classLike instanceof Class_) { + private function isChildClassLocked( + Property $property, + ClassReflection $classReflection, + string $propertyName + ): bool { + if (! $classReflection->isClass()) { return false; } - // is child class locker + // is child class locked? if ($property->isPrivate()) { return false; } - $childrenClassNames = $this->getChildrenClassesByClass($classLike); - - foreach ($childrenClassNames as $childClassName) { - if (! property_exists($childClassName, $propertyName)) { + foreach ($classReflection->getAncestors() as $childClassReflection) { + if (! $childClassReflection->hasProperty($propertyName)) { continue; } + $propertyReflection = $childClassReflection->getNativeProperty($propertyName); + // ensure the property is not in the parent class - $reflectionProperty = new ReflectionProperty($childClassName, $propertyName); - if ($reflectionProperty->class !== $childClassName) { - continue; + $propertyReflectionDeclaringClass = $propertyReflection->getDeclaringClass(); + if ($propertyReflectionDeclaringClass->getName() === $childClassReflection->getName()) { + return true; } - - return true; } return false; diff --git a/packages/vendor-locker/src/NodeVendorLocker/PropertyVisibilityVendorLockResolver.php b/packages/vendor-locker/src/NodeVendorLocker/PropertyVisibilityVendorLockResolver.php index 47fda3af7c76..3b6497d17c8b 100644 --- a/packages/vendor-locker/src/NodeVendorLocker/PropertyVisibilityVendorLockResolver.php +++ b/packages/vendor-locker/src/NodeVendorLocker/PropertyVisibilityVendorLockResolver.php @@ -4,7 +4,10 @@ namespace Rector\VendorLocker\NodeVendorLocker; +use PhpParser\Node; use PhpParser\Node\Stmt\Property; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; use Rector\NodeTypeResolver\Node\AttributeKey; final class PropertyVisibilityVendorLockResolver extends AbstractNodeVendorLockResolver @@ -18,58 +21,46 @@ final class PropertyVisibilityVendorLockResolver extends AbstractNodeVendorLockR */ public function isParentLockedProperty(Property $property): bool { - /** @var string $className */ - $className = $property->getAttribute(AttributeKey::CLASS_NAME); + $classReflection = $this->resolveClassReflection($property); + if ($classReflection === null) { + return false; + } - /** @var string $propertyName */ $propertyName = $this->nodeNameResolver->getName($property); - return $this->hasParentProperty($className, $propertyName); + foreach ($classReflection->getParents() as $parentClassReflection) { + if ($parentClassReflection->hasProperty($propertyName)) { + return true; + } + } + + return false; } public function isChildLockedProperty(Property $property): bool { - /** @var string $className */ - $className = $property->getAttribute(AttributeKey::CLASS_NAME); + $classReflection = $this->resolveClassReflection($property); + if ($classReflection === null) { + return false; + } - /** @var string $propertyName */ $propertyName = $this->nodeNameResolver->getName($property); - - return $this->hasChildProperty($className, $propertyName); - } - - private function hasParentProperty(string $className, string $propertyName): bool - { - /** @var string[] $parentClasses */ - $parentClasses = (array) class_parents($className); - - foreach ($parentClasses as $parentClass) { - if (! property_exists($parentClass, $propertyName)) { - continue; + foreach ($classReflection->getAncestors() as $childClassReflection) { + if ($childClassReflection->hasProperty($propertyName)) { + return true; } - - return true; } return false; } - private function hasChildProperty(string $desiredClassName, string $propertyName): bool + private function resolveClassReflection(Node $node): ?ClassReflection { - foreach (get_declared_classes() as $className) { - if ($className === $desiredClassName) { - continue; - } - - if (! is_a($className, $desiredClassName, true)) { - continue; - } - - if (property_exists($className, $propertyName)) { - return true; - } + $scope = $node->getAttribute(AttributeKey::SCOPE); + if (! $scope instanceof Scope) { + return null; } - return false; + return $scope->getClassReflection(); } } diff --git a/phpstan.neon b/phpstan.neon index a609df05a230..94c88efd5de6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -121,10 +121,11 @@ parameters: - '#Cognitive complexity for "Rector\\Php80\\NodeResolver\\SwitchExprsResolver\:\:resolve\(\)" is \d+, keep it under 9#' + - message: "#^Cognitive complexity for \"Rector\\\\PhpSpecToPHPUnit\\\\Rector\\\\MethodCall\\\\PhpSpecPromisesToPHPUnitAssertRector\\:\\:refactor\\(\\)\" is 13, keep it under 9$#" - count: 1 path: rules/php-spec-to-phpunit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php + - message: '#Class cognitive complexity is \d+, keep it under \d+#' paths: @@ -133,6 +134,7 @@ parameters: - packages/node-type-resolver/src/NodeTypeResolver.php - rules/code-quality-strict/src/Rector/Variable/MoveVariableDeclarationNearReferenceRector.php - rules/php80/src/Rector/If_/NullsafeOperatorRector.php + - "#^Cognitive complexity for \"Rector\\\\Php70\\\\EregToPcreTransformer\\:\\:(.*?)\" is (.*?), keep it under 9$#" - '#Cognitive complexity for "Rector\\CodeQuality\\Rector\\If_\\SimplifyIfIssetToNullCoalescingRector\:\:shouldSkip\(\)" is 10, keep it under 9#' - '#Cognitive complexity for "Rector\\TypeDeclaration\\PHPStan\\Type\\ObjectTypeSpecifier\:\:matchShortenedObjectType\(\)" is 10, keep it under 9#' @@ -526,3 +528,55 @@ parameters: path: rules/symfony/src/Rector/BinaryOp/ResponseStatusCodeRector.php - '#Property Rector\\Core\\PhpParser\\Node\\AssignAndBinaryMap\:\:\$binaryOpToAssignClasses \(array, class\-string\>\) does not accept array#' + + - + message: '#Function "class_exists\(\)" cannot be used/left in the code#' + paths: + - utils/phpstan-type-mapper-checker/src/Finder/PHPStanTypeClassFinder.php + - packages/testing/src/Finder/RectorsFinder.php + - packages/better-php-doc-parser/src/AnnotationReader/AnnotationReaderFactory.php + + - + message: '#Function "property_exists\(\)" cannot be used/left in the code#' + paths: + # on PhpParser Nodes + - src/NodeManipulator/ClassMethodAssignManipulator.php + - rules/nette-kdyby/src/Naming/VariableNaming.php + - rules/php80/src/Rector/If_/NullsafeOperatorRector.php + - rules/early-return/src/Rector/If_/ChangeAndIfToEarlyReturnRector.php + - rules/early-return/src/Rector/Return_/PreparedValueToEarlyReturnRector.php + - packages/node-type-resolver/src/NodeVisitor/FunctionMethodAndClassNodeVisitor.php + - packages/node-name-resolver/src/NodeNameResolver.php + - packages/node-type-resolver/src/PHPStan/Scope/PHPStanNodeScopeResolver.php + - packages/node-name-resolver/src/NodeNameResolver/ClassNameResolver.php + - packages/node-type-resolver/src/NodeVisitor/StatementNodeVisitor.php + - packages/better-php-doc-parser/src/Printer/PhpDocInfoPrinter.php + - packages/better-php-doc-parser/src/Printer/MultilineSpaceFormatPreserver.php + - packages/better-php-doc-parser/src/AnnotationReader/AnnotationReaderFactory.php + + - + message: '#Function "class_implements\(\)" cannot be used/left in the code#' + paths: + - rules/symfony/src/ValueObject/ServiceMap/ServiceMap.php + + - + message: '#Instead of "ReflectionClass" class/interface use "PHPStan\\Reflection\\ClassReflection"#' + paths: + # own classes + - packages/rector-generator/src/Provider/SetsListProvider.php + - packages/testing/src/Finder/RectorsFinder.php + - packages/static-type-mapper/src/TypeFactory/UnionTypeFactory.php + - packages/set/src/RectorSetProvider.php + - packages/rector-generator/src/Provider/NodeTypesProvider.php + + - '#Method Rector\\TypeDeclaration\\PhpParserTypeAnalyzer\:\:unwrapNullableAndToString\(\) should return string but returns string\|null#' + + # @todo resolve in next PR!!! (Feb 2021) + - '#Function "array_filter\(\)" cannot be used/left in the code#' + - '#Cognitive complexity for "Rector\\CodeQuality\\Rector\\Isset_\\IssetOnPropertyObjectToPropertyExistsRector\:\:refactor\(\)" is 11, keep it under 9#' + - '#Cognitive complexity for "Rector\\DeadCode\\UnusedNodeResolver\\ClassUnusedPrivateClassMethodResolver\:\:filterOutParentAbstractMethods\(\)" is 10, keep it under 9#' + + # known types + - '#Call to an undefined method PHPStan\\Type\\ConstantType\:\:getValue\(\)#' + - '#Method Rector\\BetterPhpDocParser\\AnnotationReader\\NodeAnnotationReader\:\:getNativePropertyReflection\(\) should return ReflectionProperty\|null but return statement is missing#' + diff --git a/rules/code-quality/src/NodeAnalyzer/CallableClassMethodMatcher.php b/rules/code-quality/src/NodeAnalyzer/CallableClassMethodMatcher.php index 2225163911ba..9cd955479dcb 100644 --- a/rules/code-quality/src/NodeAnalyzer/CallableClassMethodMatcher.php +++ b/rules/code-quality/src/NodeAnalyzer/CallableClassMethodMatcher.php @@ -15,7 +15,6 @@ use PHPStan\Type\UnionType; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\PhpParser\Node\Value\ValueResolver; -use Rector\NodeCollector\NodeCollector\NodeRepository; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; @@ -32,11 +31,6 @@ final class CallableClassMethodMatcher */ private $nodeTypeResolver; - /** - * @var NodeRepository - */ - private $nodeRepository; - /** * @var NodeNameResolver */ @@ -50,13 +44,11 @@ final class CallableClassMethodMatcher public function __construct( ValueResolver $valueResolver, NodeTypeResolver $nodeTypeResolver, - NodeRepository $nodeRepository, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider ) { $this->valueResolver = $valueResolver; $this->nodeTypeResolver = $nodeTypeResolver; - $this->nodeRepository = $nodeRepository; $this->nodeNameResolver = $nodeNameResolver; $this->reflectionProvider = $reflectionProvider; } diff --git a/rules/code-quality/src/NodeFactory/AnonymousFunctionFactory.php b/rules/code-quality/src/NodeFactory/AnonymousFunctionFactory.php index 03e223938110..fe264e970132 100644 --- a/rules/code-quality/src/NodeFactory/AnonymousFunctionFactory.php +++ b/rules/code-quality/src/NodeFactory/AnonymousFunctionFactory.php @@ -18,18 +18,12 @@ use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Type\MixedType; use PHPStan\Type\VoidType; -use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\Core\PhpParser\Node\NodeFactory; use Rector\NodeNameResolver\NodeNameResolver; use Rector\StaticTypeMapper\StaticTypeMapper; final class AnonymousFunctionFactory { - /** - * @var BetterNodeFinder - */ - private $betterNodeFinder; - /** * @var NodeFactory */ @@ -46,12 +40,10 @@ final class AnonymousFunctionFactory private $staticTypeMapper; public function __construct( - BetterNodeFinder $betterNodeFinder, NodeFactory $nodeFactory, NodeNameResolver $nodeNameResolver, StaticTypeMapper $staticTypeMapper ) { - $this->betterNodeFinder = $betterNodeFinder; $this->nodeFactory = $nodeFactory; $this->nodeNameResolver = $nodeNameResolver; $this->staticTypeMapper = $staticTypeMapper; diff --git a/rules/code-quality/src/Rector/Array_/ArrayThisCallToThisMethodCallRector.php b/rules/code-quality/src/Rector/Array_/ArrayThisCallToThisMethodCallRector.php index 705002072698..33d8cdbb2fa7 100644 --- a/rules/code-quality/src/Rector/Array_/ArrayThisCallToThisMethodCallRector.php +++ b/rules/code-quality/src/Rector/Array_/ArrayThisCallToThisMethodCallRector.php @@ -14,6 +14,7 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; +use PHPStan\Reflection\ReflectionProvider; use Rector\Core\Rector\AbstractRector; use Rector\NodeCollector\NodeAnalyzer\ArrayCallableMethodReferenceAnalyzer; use Rector\NodeCollector\ValueObject\ArrayCallable; @@ -32,9 +33,17 @@ final class ArrayThisCallToThisMethodCallRector extends AbstractRector */ private $arrayCallableMethodReferenceAnalyzer; - public function __construct(ArrayCallableMethodReferenceAnalyzer $arrayCallableMethodReferenceAnalyzer) - { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct( + ArrayCallableMethodReferenceAnalyzer $arrayCallableMethodReferenceAnalyzer, + ReflectionProvider $reflectionProvider + ) { $this->arrayCallableMethodReferenceAnalyzer = $arrayCallableMethodReferenceAnalyzer; + $this->reflectionProvider = $reflectionProvider; } public function getRuleDefinition(): RuleDefinition @@ -107,15 +116,21 @@ public function refactor(Node $node): ?Node return null; } - if (! $arrayCallable->isExistingMethod()) { + if (! $this->reflectionProvider->hasClass($arrayCallable->getClass())) { + return null; + } + + $classReflection = $this->reflectionProvider->getClass($arrayCallable->getClass()); + if (! $classReflection->hasMethod($arrayCallable->getMethod())) { return null; } - $reflectionMethod = $arrayCallable->getReflectionMethod(); + $nativeReflectionClass = $classReflection->getNativeReflection(); - $this->privatizeClassMethod($reflectionMethod); + $methodReflection = $nativeReflectionClass->getMethod($arrayCallable->getMethod()); + $this->privatizeClassMethod($methodReflection); - if ($reflectionMethod->getNumberOfParameters() > 0) { + if ($methodReflection->getNumberOfParameters() > 0) { $classMethod = $this->nodeRepository->findClassMethod( $arrayCallable->getClass(), $arrayCallable->getMethod() diff --git a/rules/code-quality/src/Rector/Class_/CompleteDynamicPropertiesRector.php b/rules/code-quality/src/Rector/Class_/CompleteDynamicPropertiesRector.php index 32475f139032..df007322f53e 100644 --- a/rules/code-quality/src/Rector/Class_/CompleteDynamicPropertiesRector.php +++ b/rules/code-quality/src/Rector/Class_/CompleteDynamicPropertiesRector.php @@ -6,6 +6,8 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\Type; use Rector\CodeQuality\NodeAnalyzer\ClassLikeAnalyzer; use Rector\CodeQuality\NodeAnalyzer\LocalPropertyAnalyzer; @@ -38,14 +40,21 @@ final class CompleteDynamicPropertiesRector extends AbstractRector */ private $classLikeAnalyzer; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( MissingPropertiesFactory $missingPropertiesFactory, LocalPropertyAnalyzer $localPropertyAnalyzer, - ClassLikeAnalyzer $classLikeAnalyzer + ClassLikeAnalyzer $classLikeAnalyzer, + ReflectionProvider $reflectionProvider ) { $this->missingPropertiesFactory = $missingPropertiesFactory; $this->localPropertyAnalyzer = $localPropertyAnalyzer; $this->classLikeAnalyzer = $classLikeAnalyzer; + $this->reflectionProvider = $reflectionProvider; } public function getRuleDefinition(): RuleDefinition @@ -96,6 +105,17 @@ public function refactor(Node $node): ?Node return null; } + $className = $this->getName($node); + if ($className === null) { + return null; + } + + if (! $this->reflectionProvider->hasClass($className)) { + return null; + } + + $classReflection = $this->reflectionProvider->getClass($className); + // special case for Laravel Collection macro magic $fetchedLocalPropertyNameToTypes = $this->localPropertyAnalyzer->resolveFetchedPropertiesToTypesFromClass( $node @@ -106,10 +126,7 @@ public function refactor(Node $node): ?Node return null; } - /** @var string $className */ - $className = $this->getName($node); - - $propertiesToComplete = $this->filterOutExistingProperties($className, $propertiesToComplete); + $propertiesToComplete = $this->filterOutExistingProperties($classReflection, $propertiesToComplete); $newProperties = $this->missingPropertiesFactory->create( $fetchedLocalPropertyNameToTypes, @@ -127,17 +144,23 @@ private function shouldSkipClass(Class_ $class): bool return true; } - $className = $this->getName($class); + $className = $this->nodeNameResolver->getName($class); if ($className === null) { return true; } + if (! $this->reflectionProvider->hasClass($className)) { + return true; + } + + $classReflection = $this->reflectionProvider->getClass($className); + // properties are accessed via magic, nothing we can do - if (method_exists($className, '__set')) { + if ($classReflection->hasMethod('__set')) { return true; } - return method_exists($className, '__get'); + return $classReflection->hasMethod('__get'); } /** @@ -158,14 +181,13 @@ private function resolvePropertiesToComplete(Class_ $class, array $fetchedLocalP * @param string[] $propertiesToComplete * @return string[] */ - private function filterOutExistingProperties(string $className, array $propertiesToComplete): array + private function filterOutExistingProperties(ClassReflection $classReflection, array $propertiesToComplete): array { $missingPropertyNames = []; // remove other properties that are accessible from this scope foreach ($propertiesToComplete as $propertyToComplete) { - /** @var string $propertyToComplete */ - if (property_exists($className, $propertyToComplete)) { + if ($classReflection->hasProperty($propertyToComplete)) { continue; } diff --git a/rules/code-quality/src/Rector/Isset_/IssetOnPropertyObjectToPropertyExistsRector.php b/rules/code-quality/src/Rector/Isset_/IssetOnPropertyObjectToPropertyExistsRector.php index 81ea76fce3af..ac031ee01e04 100644 --- a/rules/code-quality/src/Rector/Isset_/IssetOnPropertyObjectToPropertyExistsRector.php +++ b/rules/code-quality/src/Rector/Isset_/IssetOnPropertyObjectToPropertyExistsRector.php @@ -13,6 +13,7 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\Property; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\TypeWithClassName; use Rector\Core\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -24,6 +25,16 @@ */ final class IssetOnPropertyObjectToPropertyExistsRector extends AbstractRector { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition('Change isset on property object to property_exists() and not null check', [ @@ -86,12 +97,19 @@ public function refactor(Node $node): ?Node } $propertyFetchVarType = $this->getObjectType($issetVar->var); - if ($propertyFetchVarType instanceof TypeWithClassName && property_exists( - $propertyFetchVarType->getClassName(), - $propertyFetchName - )) { - $newNodes[] = $this->createNotIdenticalToNull($issetVar); - continue; + if ($propertyFetchVarType instanceof TypeWithClassName) { + if (! $this->reflectionProvider->hasClass($propertyFetchVarType->getClassName())) { + continue; + } + + $propertyTypeClassReflection = $this->reflectionProvider->getClass( + $propertyFetchVarType->getClassName() + ); + + if ($propertyTypeClassReflection->hasProperty($propertyFetchName)) { + $newNodes[] = $this->createNotIdenticalToNull($issetVar); + continue; + } } $newNodes[] = $this->replaceToPropertyExistsWithNullCheck($issetVar->var, $propertyFetchName, $issetVar); diff --git a/rules/coding-style/src/Rector/ClassMethod/MakeInheritedMethodVisibilitySameAsParentRector.php b/rules/coding-style/src/Rector/ClassMethod/MakeInheritedMethodVisibilitySameAsParentRector.php index 19fb467ea89e..2198cffa9c2f 100644 --- a/rules/coding-style/src/Rector/ClassMethod/MakeInheritedMethodVisibilitySameAsParentRector.php +++ b/rules/coding-style/src/Rector/ClassMethod/MakeInheritedMethodVisibilitySameAsParentRector.php @@ -92,12 +92,14 @@ public function refactor(Node $node): ?Node /** @var string $methodName */ $methodName = $this->getName($node->name); - foreach ($classReflection->getParentClassesNames() as $parentClassName) { - if (! method_exists($parentClassName, $methodName)) { + foreach ($classReflection->getParents() as $parentClassReflection) { + if (! $parentClassReflection->hasMethod($methodName)) { continue; } - $parentReflectionMethod = new ReflectionMethod($parentClassName, $methodName); + $nativeClassReflection = $parentClassReflection->getNativeReflection(); + + $parentReflectionMethod = $nativeClassReflection->getMethod($methodName); if ($this->isClassMethodCompatibleWithParentReflectionMethod($node, $parentReflectionMethod)) { return null; } diff --git a/rules/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php b/rules/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php index e34ba4ad160e..8c995abfcba2 100644 --- a/rules/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php +++ b/rules/dead-code/src/UnusedNodeResolver/ClassUnusedPrivateClassMethodResolver.php @@ -6,10 +6,11 @@ use Nette\Utils\Strings; use PhpParser\Node\Stmt\Class_; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ReflectionProvider; use Rector\Core\NodeManipulator\ClassManipulator; use Rector\NodeCollector\NodeCollector\NodeRepository; use Rector\NodeNameResolver\NodeNameResolver; -use ReflectionMethod; final class ClassUnusedPrivateClassMethodResolver { @@ -28,14 +29,21 @@ final class ClassUnusedPrivateClassMethodResolver */ private $nodeRepository; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( ClassManipulator $classManipulator, NodeNameResolver $nodeNameResolver, - NodeRepository $nodeRepository + NodeRepository $nodeRepository, + ReflectionProvider $reflectionProvider ) { $this->nodeNameResolver = $nodeNameResolver; $this->classManipulator = $classManipulator; $this->nodeRepository = $nodeRepository; + $this->reflectionProvider = $reflectionProvider; } /** @@ -98,14 +106,14 @@ private function filterOutInterfaceRequiredMethods(Class_ $class, array $unusedM { /** @var string $className */ $className = $this->nodeNameResolver->getName($class); - - /** @var string[] $interfaces */ - $interfaces = (array) class_implements($className); + $classReflection = $this->reflectionProvider->getClass($className); $interfaceMethods = []; - foreach ($interfaces as $interface) { - $currentInterfaceMethods = get_class_methods($interface); - $interfaceMethods = array_merge($interfaceMethods, $currentInterfaceMethods); + foreach ($classReflection->getInterfaces() as $interfaceClassReflection) { + $nativeInterfaceClassReflection = $interfaceClassReflection->getNativeReflection(); + foreach ($nativeInterfaceClassReflection->getMethods() as $methodReflection) { + $interfaceMethods[] = $methodReflection->getName(); + } } return array_diff($unusedMethods, $interfaceMethods); @@ -121,18 +129,26 @@ private function filterOutParentAbstractMethods(Class_ $class, array $unusedMeth return $unusedMethods; } - /** @var string[] $parentClasses */ - $parentClasses = (array) class_parents($class); + $className = $this->nodeNameResolver->getName($class); + if ($className === null) { + return []; + } + + if (! $this->reflectionProvider->hasClass($className)) { + return []; + } + + $classReflection = $this->reflectionProvider->getClass($className); $parentAbstractMethods = []; - foreach ($parentClasses as $parentClass) { + foreach ($classReflection->getParents() as $parentClassReflection) { foreach ($unusedMethods as $unusedMethod) { if (in_array($unusedMethod, $parentAbstractMethods, true)) { continue; } - if ($this->isMethodAbstract($parentClass, $unusedMethod)) { + if ($this->isMethodAbstract($parentClassReflection, $unusedMethod)) { $parentAbstractMethods[] = $unusedMethod; } } @@ -141,12 +157,14 @@ private function filterOutParentAbstractMethods(Class_ $class, array $unusedMeth return array_diff($unusedMethods, $parentAbstractMethods); } - private function isMethodAbstract(string $class, string $method): bool + private function isMethodAbstract(ClassReflection $classReflection, string $method): bool { - if (! method_exists($class, $method)) { + if (! $classReflection->hasMethod($method)) { return false; } - $reflectionMethod = new ReflectionMethod($class, $method); + + $nativeClassReflection = $classReflection->getNativeReflection(); + $reflectionMethod = $nativeClassReflection->getMethod($method); return $reflectionMethod->isAbstract(); } diff --git a/rules/defluent/src/ConflictGuard/ParentClassMethodTypeOverrideGuard.php b/rules/defluent/src/ConflictGuard/ParentClassMethodTypeOverrideGuard.php index 0d1da0d2628d..c95e658886dc 100644 --- a/rules/defluent/src/ConflictGuard/ParentClassMethodTypeOverrideGuard.php +++ b/rules/defluent/src/ConflictGuard/ParentClassMethodTypeOverrideGuard.php @@ -8,18 +8,12 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\MethodReflection; -use PHPStan\Reflection\ReflectionProvider; use Rector\NodeCollector\NodeCollector\NodeRepository; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; final class ParentClassMethodTypeOverrideGuard { - /** - * @var ReflectionProvider - */ - private $reflectionProvider; - /** * @var NodeRepository */ @@ -30,12 +24,8 @@ final class ParentClassMethodTypeOverrideGuard */ private $nodeNameResolver; - public function __construct( - ReflectionProvider $reflectionProvider, - NodeRepository $nodeRepository, - NodeNameResolver $nodeNameResolver - ) { - $this->reflectionProvider = $reflectionProvider; + public function __construct(NodeRepository $nodeRepository, NodeNameResolver $nodeNameResolver) + { $this->nodeRepository = $nodeRepository; $this->nodeNameResolver = $nodeNameResolver; } diff --git a/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php b/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php index d3eb08b716bf..967b52b66053 100644 --- a/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php +++ b/rules/doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php @@ -123,12 +123,15 @@ private function isStringClassEntity(string $class): bool } $classReflection = $this->reflectionProvider->getClass($class); - dump($classReflection->getResolvedPhpDoc()); - die; + $resolvedPhpDoc = $classReflection->getResolvedPhpDoc(); + if ($resolvedPhpDoc === null) { + return false; + } // dummy check of 3rd party code without running it - $docCommentContent = (string) $reflectionClass->getDocComment(); - - return (bool) Strings::match($docCommentContent, self::ORM_ENTITY_EMBEDDABLE_SHORT_ANNOTATION_REGEX); + return (bool) Strings::match( + $resolvedPhpDoc->getPhpDocString(), + self::ORM_ENTITY_EMBEDDABLE_SHORT_ANNOTATION_REGEX + ); } } diff --git a/rules/doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php b/rules/doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php index a743e6f13fa2..d3804d4f209b 100644 --- a/rules/doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php +++ b/rules/doctrine/src/Rector/Class_/AddUuidMirrorForRelationPropertyRector.php @@ -9,6 +9,7 @@ use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\PropertyProperty; use PhpParser\Node\VarLikeIdentifier; +use PHPStan\Reflection\ReflectionProvider; use Rector\BetterPhpDocParser\Contract\Doctrine\DoctrineRelationTagValueNodeInterface; use Rector\BetterPhpDocParser\Contract\Doctrine\ToManyTagNodeInterface; use Rector\BetterPhpDocParser\Contract\Doctrine\ToOneTagNodeInterface; @@ -51,16 +52,23 @@ final class AddUuidMirrorForRelationPropertyRector extends AbstractRector */ private $joinColumnTagValueNodeFactory; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( PhpDocTagNodeFactory $phpDocTagNodeFactory, UuidMigrationDataCollector $uuidMigrationDataCollector, DoctrineDocBlockResolver $doctrineDocBlockResolver, - JoinColumnTagValueNodeFactory $joinColumnTagValueNodeFactory + JoinColumnTagValueNodeFactory $joinColumnTagValueNodeFactory, + ReflectionProvider $reflectionProvider ) { $this->phpDocTagNodeFactory = $phpDocTagNodeFactory; $this->uuidMigrationDataCollector = $uuidMigrationDataCollector; $this->doctrineDocBlockResolver = $doctrineDocBlockResolver; $this->joinColumnTagValueNodeFactory = $joinColumnTagValueNodeFactory; + $this->reflectionProvider = $reflectionProvider; } public function getRuleDefinition(): RuleDefinition @@ -189,7 +197,12 @@ private function shouldSkipProperty(Class_ $class, Property $property): bool return true; } - if (! property_exists($targetEntity, 'uuid')) { + if (! $this->reflectionProvider->hasClass($targetEntity)) { + return true; + } + + $classReflection = $this->reflectionProvider->getClass($targetEntity); + if (! $classReflection->hasProperty('uuid')) { return true; } diff --git a/rules/downgrade-php72/src/Rector/ClassMethod/DowngradeParameterTypeWideningRector.php b/rules/downgrade-php72/src/Rector/ClassMethod/DowngradeParameterTypeWideningRector.php index 9f40a972d968..4ebfabf2fa99 100644 --- a/rules/downgrade-php72/src/Rector/ClassMethod/DowngradeParameterTypeWideningRector.php +++ b/rules/downgrade-php72/src/Rector/ClassMethod/DowngradeParameterTypeWideningRector.php @@ -17,7 +17,6 @@ use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger; use Rector\Core\Rector\AbstractRector; use Rector\NodeTypeResolver\Node\AttributeKey; -use ReflectionMethod; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -181,16 +180,16 @@ private function getClassesWithDifferentSignature( string $paramName ): array { // 1. All ancestor classes with different signature - $ancestorClassNames = array_filter( - $classReflection->getParentClassesNames(), - function (string $ancestorClassName) use ($methodName, $paramName): bool { - return $this->hasMethodWithTypedParam($ancestorClassName, $methodName, $paramName); + $ancestorClassReflections = array_filter( + $classReflection->getParents(), + function (ClassReflection $classReflection) use ($methodName, $paramName): bool { + return $this->hasMethodWithTypedParam($classReflection, $methodName, $paramName); } ); $classes = []; - foreach ($ancestorClassNames as $ancestorClassName) { - $class = $this->nodeRepository->findClass($ancestorClassName); + foreach ($ancestorClassReflections as $ancestorClassReflection) { + $class = $this->nodeRepository->findClass($ancestorClassReflection->getName()); if (! $class instanceof Class_) { continue; } @@ -210,22 +209,16 @@ private function getInterfacesWithDifferentSignature( string $methodName, string $paramName ): array { - $interfaceClassNames = array_map( - function (ClassReflection $interfaceReflection): string { - return $interfaceReflection->getName(); - }, - $classReflection->getInterfaces() - ); - $refactorableInterfaceClassNames = array_filter( - $interfaceClassNames, - function (string $interfaceClassName) use ($methodName, $paramName): bool { - return $this->hasMethodWithTypedParam($interfaceClassName, $methodName, $paramName); + $interfaceClassReflections = array_filter( + $classReflection->getInterfaces(), + function (ClassReflection $interfaceReflection) use ($methodName, $paramName): bool { + return $this->hasMethodWithTypedParam($interfaceReflection, $methodName, $paramName); } ); $interfaces = []; - foreach ($refactorableInterfaceClassNames as $refactorableInterfaceClassName) { - $interface = $this->nodeRepository->findInterface($refactorableInterfaceClassName); + foreach ($interfaceClassReflections as $interfaceClassReflection) { + $interface = $this->nodeRepository->findInterface($interfaceClassReflection->getName()); if (! $interface instanceof Interface_) { continue; } @@ -284,23 +277,26 @@ private function removeParamTypeFromMethodForChildren( } } - private function hasMethodWithTypedParam(string $parentClassName, string $methodName, string $paramName): bool - { - if (! method_exists($parentClassName, $methodName)) { + private function hasMethodWithTypedParam( + ClassReflection $classReflection, + string $methodName, + string $paramName + ): bool { + if (! $classReflection->hasMethod($methodName)) { return false; } - $parentReflectionMethod = new ReflectionMethod($parentClassName, $methodName); + $nativeClassReflection = $classReflection->getNativeReflection(); + $reflectionMethodReflection = $nativeClassReflection->getMethod($methodName); - $parentReflectionMethodParams = $parentReflectionMethod->getParameters(); - foreach ($parentReflectionMethodParams as $reflectionParameter) { + foreach ($reflectionMethodReflection->getParameters() as $reflectionParameter) { if ($reflectionParameter->name !== $paramName) { continue; } - if ($reflectionParameter->getType() === null) { - continue; + + if ($reflectionParameter->getType() !== null) { + return true; } - return true; } return false; diff --git a/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php b/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php index 80b06c8db903..769de625152e 100644 --- a/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php +++ b/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeContravariantArgumentTypeRector.php @@ -113,14 +113,15 @@ private function getDifferentParamTypeFromAncestorClass(Param $param, FunctionLi // If it is the NullableType, extract the name from its inner type /** @var Node $paramType */ $paramType = $param->type; - $isNullableType = $param->type instanceof NullableType; - if ($isNullableType) { + + if ($param->type instanceof NullableType) { /** @var NullableType $nullableType */ $nullableType = $paramType; $paramTypeName = $this->getName($nullableType->type); } else { $paramTypeName = $this->getName($paramType); } + if ($paramTypeName === null) { return null; } @@ -128,29 +129,26 @@ private function getDifferentParamTypeFromAncestorClass(Param $param, FunctionLi /** @var string $methodName */ $methodName = $this->getName($functionLike); - // Either Ancestor classes or implemented interfaces - $interfaceNames = array_map( - function (ClassReflection $interfaceReflection): string { - return $interfaceReflection->getName(); - }, - $classReflection->getInterfaces() - ); - - $parentClassesNames = $classReflection->getParentClassesNames(); - $parentClassLikes = array_merge($parentClassesNames, $interfaceNames); + // parent classes or implemented interfaces + /** @var ClassReflection[] $parentClassReflections */ + $parentClassReflections = array_merge($classReflection->getParents(), $classReflection->getInterfaces()); - foreach ($parentClassLikes as $parentClassLike) { - if (! method_exists($parentClassLike, $methodName)) { + foreach ($parentClassReflections as $parentClassReflection) { + if (! $parentClassReflection->hasMethod($methodName)) { continue; } + $nativeClassReflection = $parentClassReflection->getNativeReflection(); + // Find the param we're looking for - $parentReflectionMethod = new ReflectionMethod($parentClassLike, $methodName); + $parentReflectionMethod = $nativeClassReflection->getMethod($methodName); + $differentAncestorParamTypeName = $this->getDifferentParamTypeFromReflectionMethod( $parentReflectionMethod, $paramName, $paramTypeName ); + if ($differentAncestorParamTypeName !== null) { return $differentAncestorParamTypeName; } @@ -160,12 +158,13 @@ function (ClassReflection $interfaceReflection): string { } private function getDifferentParamTypeFromReflectionMethod( - ReflectionMethod $parentReflectionMethod, + ReflectionMethod $reflectionMethod, string $paramName, string $paramTypeName ): ?string { /** @var ReflectionParameter[] $parentReflectionMethodParams */ - $parentReflectionMethodParams = $parentReflectionMethod->getParameters(); + $parentReflectionMethodParams = $reflectionMethod->getParameters(); + foreach ($parentReflectionMethodParams as $reflectionParameter) { if ($reflectionParameter->name === $paramName) { /** @@ -173,6 +172,7 @@ private function getDifferentParamTypeFromReflectionMethod( * @see https://www.php.net/manual/en/reflectionparameter.gettype.php#125334 */ $reflectionParamType = $reflectionParameter->getType(); + /** * If the type is null, we don't have enough information * to check if they are different. Then do nothing @@ -180,6 +180,7 @@ private function getDifferentParamTypeFromReflectionMethod( if (! $reflectionParamType instanceof ReflectionNamedType) { continue; } + if ($reflectionParamType->getName() !== $paramTypeName) { // We found it: a different param type in some ancestor return $reflectionParamType->getName(); diff --git a/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeCovariantReturnTypeRector.php b/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeCovariantReturnTypeRector.php index f1b3eaa3f287..6b86f35cb9ca 100644 --- a/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeCovariantReturnTypeRector.php +++ b/rules/downgrade-php74/src/Rector/ClassMethod/DowngradeCovariantReturnTypeRector.php @@ -163,11 +163,7 @@ private function resolveDifferentAncestorReturnType(ClassMethod $classMethod, No return new MixedType(); } - if ($returnTypeNode instanceof NullableType) { - $bareReturnType = $returnTypeNode->type; - } else { - $bareReturnType = $returnTypeNode; - } + $bareReturnType = $returnTypeNode instanceof NullableType ? $returnTypeNode->type : $returnTypeNode; $returnType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($bareReturnType); $methodName = $this->getName($classMethod); diff --git a/rules/mockista-to-mockery/src/Rector/ClassMethod/MockistaMockToMockeryMockRector.php b/rules/mockista-to-mockery/src/Rector/ClassMethod/MockistaMockToMockeryMockRector.php index 31743f17035f..daf7a0a85c23 100644 --- a/rules/mockista-to-mockery/src/Rector/ClassMethod/MockistaMockToMockeryMockRector.php +++ b/rules/mockista-to-mockery/src/Rector/ClassMethod/MockistaMockToMockeryMockRector.php @@ -12,12 +12,11 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Reflection\ReflectionProvider; use Rector\Core\Rector\AbstractRector; use Rector\MockeryToProphecy\Collector\MockVariableCollector; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer; -use ReflectionMethod; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -32,7 +31,7 @@ final class MockistaMockToMockeryMockRector extends AbstractRector private const METHODS_TO_REMOVE = ['freeze', 'assertExpectations']; /** - * @var string[] + * @var array */ private $mockVariableTypesByNames = []; @@ -46,10 +45,19 @@ final class MockistaMockToMockeryMockRector extends AbstractRector */ private $testsNodeAnalyzer; - public function __construct(MockVariableCollector $mockVariableCollector, TestsNodeAnalyzer $testsNodeAnalyzer) - { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct( + MockVariableCollector $mockVariableCollector, + TestsNodeAnalyzer $testsNodeAnalyzer, + ReflectionProvider $reflectionProvider + ) { $this->mockVariableCollector = $mockVariableCollector; $this->testsNodeAnalyzer = $testsNodeAnalyzer; + $this->reflectionProvider = $reflectionProvider; } public function getRuleDefinition(): RuleDefinition @@ -270,11 +278,17 @@ private function decorateWithAnyArgs(MethodCall $originalMethodCall, MethodCall return $expectsMethodCall; } - if (! method_exists($mockVariableType, $methodName)) { + if (! $this->reflectionProvider->hasClass($mockVariableType)) { return $expectsMethodCall; } - $reflectionMethod = new ReflectionMethod($mockVariableType, $methodName); + $classReflection = $this->reflectionProvider->getClass($mockVariableType); + if (! $classReflection->hasMethod($methodName)) { + return $expectsMethodCall; + } + + $nativeReflectionClass = $classReflection->getNativeReflection(); + $reflectionMethod = $nativeReflectionClass->getMethod($methodName); if ($reflectionMethod->getNumberOfRequiredParameters() === 0) { return $expectsMethodCall; } @@ -298,11 +312,16 @@ private function isPropertyFetchDisguisedAsMethodCall(Node $node): bool } $mockVariableType = $this->mockVariableTypesByNames[$variableName]; + if (! $this->reflectionProvider->hasClass($mockVariableType)) { + return false; + } + + $classReflection = $this->reflectionProvider->getClass($mockVariableType); $propertyName = $this->getName($node->name); if ($propertyName === null) { return false; } - return method_exists($mockVariableType, $propertyName); + return $classReflection->hasMethod($propertyName); } } diff --git a/rules/naming/src/Guard/HasMagicGetSetGuard.php b/rules/naming/src/Guard/HasMagicGetSetGuard.php index 060d219752e5..2d02169e3e84 100644 --- a/rules/naming/src/Guard/HasMagicGetSetGuard.php +++ b/rules/naming/src/Guard/HasMagicGetSetGuard.php @@ -4,20 +4,37 @@ namespace Rector\Naming\Guard; +use PHPStan\Reflection\ReflectionProvider; use Rector\Naming\Contract\Guard\ConflictingGuardInterface; use Rector\Naming\Contract\RenameValueObjectInterface; use Rector\Naming\ValueObject\PropertyRename; final class HasMagicGetSetGuard implements ConflictingGuardInterface { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + /** * @param PropertyRename $renameValueObject */ public function check(RenameValueObjectInterface $renameValueObject): bool { - return method_exists($renameValueObject->getClassLikeName(), '__set') || method_exists( - $renameValueObject->getClassLikeName(), - '__get' - ); + if (! $this->reflectionProvider->hasClass($renameValueObject->getClassLikeName())) { + return false; + } + + $classReflection = $this->reflectionProvider->getClass($renameValueObject->getClassLikeName()); + if ($classReflection->hasMethod('__set')) { + return true; + } + + return $classReflection->hasMethod('__get'); } } diff --git a/rules/naming/src/Naming/PropertyNaming.php b/rules/naming/src/Naming/PropertyNaming.php index 08d9a040e43d..436b32ef7409 100644 --- a/rules/naming/src/Naming/PropertyNaming.php +++ b/rules/naming/src/Naming/PropertyNaming.php @@ -11,6 +11,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Return_; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ObjectType; use PHPStan\Type\StaticType; use PHPStan\Type\Type; @@ -86,18 +87,25 @@ final class PropertyNaming */ private $nodeTypeResolver; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( TypeUnwrapper $typeUnwrapper, RectorNamingInflector $rectorNamingInflector, BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver, - NodeTypeResolver $nodeTypeResolver + NodeTypeResolver $nodeTypeResolver, + ReflectionProvider $reflectionProvider ) { $this->typeUnwrapper = $typeUnwrapper; $this->rectorNamingInflector = $rectorNamingInflector; $this->betterNodeFinder = $betterNodeFinder; $this->nodeNameResolver = $nodeNameResolver; $this->nodeTypeResolver = $nodeTypeResolver; + $this->reflectionProvider = $reflectionProvider; } public function getExpectedNameFromMethodName(string $methodName): ?ExpectedName @@ -278,7 +286,7 @@ private function fqnToShortName(string $fqn): string private function removeInterfaceSuffixPrefix(string $className, string $shortName): string { // remove interface prefix/suffix - if (! interface_exists($className)) { + if (! $this->reflectionProvider->hasClass($className)) { return $shortName; } diff --git a/rules/nette-kdyby/src/DataProvider/OnPropertyMagicCallProvider.php b/rules/nette-kdyby/src/DataProvider/OnPropertyMagicCallProvider.php index cff15aad9d26..bbc79cd76573 100644 --- a/rules/nette-kdyby/src/DataProvider/OnPropertyMagicCallProvider.php +++ b/rules/nette-kdyby/src/DataProvider/OnPropertyMagicCallProvider.php @@ -6,6 +6,8 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\StaticCall; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ReflectionProvider; use Rector\NodeCollector\NodeCollector\NodeRepository; use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -36,10 +38,19 @@ final class OnPropertyMagicCallProvider */ private $nodeNameResolver; - public function __construct(NodeNameResolver $nodeNameResolver, NodeRepository $nodeRepository) - { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct( + NodeNameResolver $nodeNameResolver, + NodeRepository $nodeRepository, + ReflectionProvider $reflectionProvider + ) { $this->nodeRepository = $nodeRepository; $this->nodeNameResolver = $nodeNameResolver; + $this->reflectionProvider = $reflectionProvider; } /** @@ -52,7 +63,8 @@ public function provide(): array } foreach ($this->nodeRepository->getMethodsCalls() as $methodCall) { - if (! $this->isLocalOnPropertyCall($methodCall)) { + $scope = $methodCall->getAttribute(AttributeKey::SCOPE); + if (! $this->isLocalOnPropertyCall($methodCall, $scope)) { continue; } @@ -66,7 +78,7 @@ public function provide(): array * Detects method call on, e.g: * public $onSomeProperty; */ - private function isLocalOnPropertyCall(MethodCall $methodCall): bool + private function isLocalOnPropertyCall(MethodCall $methodCall, Scope $scope): bool { if ($methodCall->var instanceof StaticCall) { return false; @@ -89,19 +101,20 @@ private function isLocalOnPropertyCall(MethodCall $methodCall): bool return false; } - $className = $methodCall->getAttribute(AttributeKey::CLASS_NAME); - if ($className === null) { + $classReflection = $scope->getClassReflection(); + if ($classReflection === null) { return false; } + // control event, inner only - if (is_a($className, self::CONTROL_CLASS, true)) { + if ($classReflection->isSubclassOf(self::CONTROL_CLASS)) { return false; } - if (method_exists($className, $methodName)) { + if ($classReflection->hasMethod($methodName)) { return false; } - return property_exists($className, $methodName); + return $classReflection->hasProperty($methodName); } } diff --git a/rules/nette-kdyby/src/Naming/VariableNaming.php b/rules/nette-kdyby/src/Naming/VariableNaming.php index 5c5787987e0a..1ecfdb86ba0d 100644 --- a/rules/nette-kdyby/src/Naming/VariableNaming.php +++ b/rules/nette-kdyby/src/Naming/VariableNaming.php @@ -144,7 +144,9 @@ private function resolveBareFromNode(Node $node): ?string return $this->resolveFromPropertyFetch($node); } - if ($this->isCall($node)) { + if ($node !== null && StaticInstanceOf::isOneOf( + $node, + [MethodCall::class, NullsafeMethodCall::class, StaticCall::class])) { return $this->resolveFromMethodCall($node); } @@ -242,15 +244,6 @@ private function resolveFromPropertyFetch(PropertyFetch $propertyFetch): string return $varName . ucfirst($propertyName); } - private function isCall(?Node $node): bool - { - if (! $node instanceof Node) { - return false; - } - - return StaticInstanceOf::isOneOf($node, [MethodCall::class, NullsafeMethodCall::class, StaticCall::class]); - } - private function resolveFromMethodCall(?Node $node): ?string { if (! $node instanceof Node) { diff --git a/rules/nette-to-symfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php b/rules/nette-to-symfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php index d4bb62548a19..bbe01363c9fb 100644 --- a/rules/nette-to-symfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php +++ b/rules/nette-to-symfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php @@ -11,7 +11,9 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ObjectType; +use PHPStan\Type\TypeWithClassName; use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\Symfony\SymfonyRouteTagValueNode; use Rector\BetterPhpDocParser\ValueObjectFactory\PhpDocNode\Symfony\SymfonyRouteTagValueNodeFactory; use Rector\Core\Rector\AbstractRector; @@ -20,7 +22,7 @@ use Rector\NetteToSymfony\Routing\ExplicitRouteAnnotationDecorator; use Rector\NetteToSymfony\ValueObject\RouteInfo; use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; -use ReflectionMethod; +use Symplify\PackageBuilder\Reflection\PrivatesCaller; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -66,16 +68,30 @@ final class RouterListToControllerAnnotationsRector extends AbstractRector */ private $symfonyRouteTagValueNodeFactory; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + /** + * @var PrivatesCaller + */ + private $privatesCaller; + public function __construct( ExplicitRouteAnnotationDecorator $explicitRouteAnnotationDecorator, ReturnTypeInferer $returnTypeInferer, RouteInfoFactory $routeInfoFactory, - SymfonyRouteTagValueNodeFactory $symfonyRouteTagValueNodeFactory + SymfonyRouteTagValueNodeFactory $symfonyRouteTagValueNodeFactory, + ReflectionProvider $reflectionProvider, + PrivatesCaller $privatesCaller ) { $this->routeInfoFactory = $routeInfoFactory; $this->returnTypeInferer = $returnTypeInferer; $this->explicitRouteAnnotationDecorator = $explicitRouteAnnotationDecorator; $this->symfonyRouteTagValueNodeFactory = $symfonyRouteTagValueNodeFactory; + $this->reflectionProvider = $reflectionProvider; + $this->privatesCaller = $privatesCaller; } public function getRuleDefinition(): RuleDefinition @@ -297,17 +313,25 @@ private function isRouteStaticCallMatch(StaticCall $staticCall): bool return false; } - if (! method_exists($className, $methodName)) { + if (! $this->reflectionProvider->hasClass($className)) { return false; } - $reflectionMethod = new ReflectionMethod($className, $methodName); - if ($reflectionMethod->getReturnType() === null) { + $classReflection = $this->reflectionProvider->getClass($className); + if (! $classReflection->hasMethod($methodName)) { return false; } - $staticCallReturnType = (string) $reflectionMethod->getReturnType(); - return is_a($staticCallReturnType, 'Nette\Application\IRouter', true); + $reflectionMethod = $classReflection->getNativeMethod($methodName); + + /** @var \PHPStan\Type\Type $returnType */ + $returnType = $this->privatesCaller->callPrivateMethod($reflectionMethod, 'getReturnType', []); + + if ($returnType instanceof TypeWithClassName) { + return is_a($returnType->getClassName(), 'Nette\Application\IRouter', true); + } + + return false; } private function shouldSkipClassMethod(ClassMethod $classMethod): bool diff --git a/rules/nette-to-symfony/src/Route/RouteInfoFactory.php b/rules/nette-to-symfony/src/Route/RouteInfoFactory.php index f1cb908025b9..c0181dc4544b 100644 --- a/rules/nette-to-symfony/src/Route/RouteInfoFactory.php +++ b/rules/nette-to-symfony/src/Route/RouteInfoFactory.php @@ -187,17 +187,22 @@ private function createForString(String_ $string, string $routePath): ?RouteInfo return null; } - $methodName = null; - if (method_exists($controllerClass, 'render' . ucfirst($method))) { - $methodName = 'render' . ucfirst($method); - } elseif (method_exists($controllerClass, 'action' . ucfirst($method))) { - $methodName = 'action' . ucfirst($method); + if (! $this->reflectionProvider->hasClass($controllerClass)) { + return null; } - if ($methodName === null) { - return null; + $controllerClassReflection = $this->reflectionProvider->getClass($controllerClass); + + $renderMethodName = 'render' . ucfirst($method); + if ($controllerClassReflection->hasMethod($renderMethodName)) { + return new RouteInfo($controllerClass, $renderMethodName, $routePath, []); } - return new RouteInfo($controllerClass, $methodName, $routePath, []); + $actionMethodName = 'action' . ucfirst($method); + if ($controllerClassReflection->hasMethod($actionMethodName)) { + return new RouteInfo($controllerClass, $actionMethodName, $routePath, []); + } + + return null; } } diff --git a/rules/php-spec-to-phpunit/src/PHPUnitTypeDeclarationDecorator.php b/rules/php-spec-to-phpunit/src/PHPUnitTypeDeclarationDecorator.php index cdb8bdfc723c..cd1089b85eac 100644 --- a/rules/php-spec-to-phpunit/src/PHPUnitTypeDeclarationDecorator.php +++ b/rules/php-spec-to-phpunit/src/PHPUnitTypeDeclarationDecorator.php @@ -6,18 +6,28 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Reflection\ReflectionProvider; use Rector\Core\ValueObject\MethodName; use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment; -use ReflectionMethod; /** * Decorate setUp() and tearDown() with "void" when local TestClass class uses them */ final class PHPUnitTypeDeclarationDecorator { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + public function decorate(ClassMethod $classMethod): void { - if (! class_exists('PHPUnit\Framework\TestCase')) { + if (! $this->reflectionProvider->hasClass('PHPUnit\Framework\TestCase')) { return; } @@ -26,7 +36,10 @@ public function decorate(ClassMethod $classMethod): void return; } - $reflectionMethod = new ReflectionMethod('PHPUnit\Framework\TestCase', MethodName::SET_UP); + $classReflection = $this->reflectionProvider->getClass('PHPUnit\Framework\TestCase'); + $nativeClassReflection = $classReflection->getNativeReflection(); + + $reflectionMethod = $nativeClassReflection->getMethod(MethodName::SET_UP); if (! $reflectionMethod->hasReturnType()) { return; } diff --git a/rules/php70/src/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php b/rules/php70/src/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php index 725c241a1254..6dba86f455fc 100644 --- a/rules/php70/src/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php +++ b/rules/php70/src/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php @@ -7,11 +7,11 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Stmt\Class_; +use PHPStan\Reflection\Php\PhpMethodReflection; use Rector\Core\Rector\AbstractRector; use Rector\NodeCollector\Reflection\MethodReflectionProvider; use Rector\NodeCollector\StaticAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; -use ReflectionMethod; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -129,12 +129,14 @@ private function resolveClassSelf(MethodCall $methodCall): string } $methodReflection = $this->methodReflectionProvider->provideByMethodCall($methodCall); - if (! $methodReflection instanceof ReflectionMethod) { + if (! $methodReflection instanceof PhpMethodReflection) { return 'static'; } + if (! $methodReflection->isPrivate()) { return 'static'; } + return 'self'; } } diff --git a/rules/php70/src/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php b/rules/php70/src/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php index a41b4524826a..b3001588c2e1 100644 --- a/rules/php70/src/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php +++ b/rules/php70/src/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php @@ -11,13 +11,13 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Stmt\ClassMethod; -use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ObjectType; use Rector\Core\NodeManipulator\ClassMethodManipulator; use Rector\Core\Rector\AbstractRector; use Rector\NodeCollector\StaticAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; +use ReflectionMethod; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -185,18 +185,19 @@ private function isInstantiable(string $className): bool return false; } - $reflectionClass = $this->reflectionProvider->getClass($className); - $classConstructorReflection = $reflectionClass->getConstructor(); - if (! $classConstructorReflection instanceof PhpMethodReflection) { + $classReflection = $this->reflectionProvider->getClass($className); + $nativeClassReflection = $classReflection->getNativeReflection(); + + $constructorMethodReflection = $nativeClassReflection->getConstructor(); + if (! $constructorMethodReflection instanceof ReflectionMethod) { return true; } - if (! $classConstructorReflection->isPublic()) { + if (! $constructorMethodReflection->isPublic()) { return false; } // required parameters in constructor, nothing we can do - // @todo - return ! (bool) $classConstructorReflection->getNumberOfRequiredParameters(); + return ! (bool) $constructorMethodReflection->getNumberOfRequiredParameters(); } } diff --git a/rules/php71/src/NodeAnalyzer/CountableAnalyzer.php b/rules/php71/src/NodeAnalyzer/CountableAnalyzer.php index 77a3363dd0fb..c0ca79622c0a 100644 --- a/rules/php71/src/NodeAnalyzer/CountableAnalyzer.php +++ b/rules/php71/src/NodeAnalyzer/CountableAnalyzer.php @@ -7,6 +7,7 @@ use PhpParser\Node\Expr; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Stmt; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\UnionType; @@ -61,7 +62,7 @@ public function isCastableArrayType(Expr $expr): bool return false; } - if (is_a($callerObjectType->getClassName(), \PhpParser\Node\Stmt::class, true)) { + if (is_a($callerObjectType->getClassName(), Stmt::class, true)) { return false; } diff --git a/rules/privatization/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php b/rules/privatization/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php index e2eb2974f0de..728010b81a87 100644 --- a/rules/privatization/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php +++ b/rules/privatization/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php @@ -6,7 +6,6 @@ use PhpParser\Node; use PhpParser\Node\Stmt\ClassConst; -use PHPStan\Reflection\ClassConstantReflection; use Rector\BetterPhpDocParser\ValueObject\PhpDocNode\ApiPhpDocTagNode; use Rector\Caching\Contract\Rector\ZeroCacheRectorInterface; use Rector\Core\Rector\AbstractRector; @@ -177,13 +176,12 @@ private function findParentClassConstantAndRefactorIfPossible(string $class, str } $parentClassConstantReflection = $this->parentConstantReflectionResolver->resolve($class, $constant); - if (! $parentClassConstantReflection instanceof ClassConstantReflection) { + if ($parentClassConstantReflection === null) { return null; } return new ConstantVisibility( $parentClassConstantReflection->isPublic(), - // @todo $parentClassConstantReflection->isProtected(), $parentClassConstantReflection->isPrivate() ); diff --git a/rules/privatization/src/Rector/ClassMethod/MakeOnlyUsedByChildrenProtectedRector.php b/rules/privatization/src/Rector/ClassMethod/MakeOnlyUsedByChildrenProtectedRector.php index 15ed9c982d16..1c64d060e988 100644 --- a/rules/privatization/src/Rector/ClassMethod/MakeOnlyUsedByChildrenProtectedRector.php +++ b/rules/privatization/src/Rector/ClassMethod/MakeOnlyUsedByChildrenProtectedRector.php @@ -8,11 +8,11 @@ use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Reflection\ReflectionProvider; use Rector\Core\Rector\AbstractRector; use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Privatization\NodeAnalyzer\ClassMethodExternalCallNodeAnalyzer; -use ReflectionClass; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -31,12 +31,19 @@ final class MakeOnlyUsedByChildrenProtectedRector extends AbstractRector */ private $familyRelationsAnalyzer; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( ClassMethodExternalCallNodeAnalyzer $classMethodExternalCallNodeAnalyzer, - FamilyRelationsAnalyzer $familyRelationsAnalyzer + FamilyRelationsAnalyzer $familyRelationsAnalyzer, + ReflectionProvider $reflectionProvider ) { $this->classMethodExternalCallNodeAnalyzer = $classMethodExternalCallNodeAnalyzer; $this->familyRelationsAnalyzer = $familyRelationsAnalyzer; + $this->reflectionProvider = $reflectionProvider; } public function getRuleDefinition(): RuleDefinition @@ -157,17 +164,17 @@ private function shouldSkip(ClassMethod $classMethod): bool private function isOverriddenInChildClass(string $className, string $methodName): bool { - $childrenClassNames = $this->familyRelationsAnalyzer->getChildrenOfClass($className); - foreach ($childrenClassNames as $childrenClassName) { - $reflectionClass = new ReflectionClass($childrenClassName); - $isMethodExists = method_exists($childrenClassName, $methodName); - if (! $isMethodExists) { + $childrenClassReflection = $this->familyRelationsAnalyzer->getChildrenOfClass($className); + + foreach ($childrenClassReflection as $childClassReflection) { + if (! $childClassReflection->hasMethod($methodName)) { continue; } - $isMethodInChildrenClass = $reflectionClass->getMethod($methodName) - ->class === $childrenClassName; - if ($isMethodInChildrenClass) { + $methodReflection = $childClassReflection->getNativeMethod($methodName); + $methodDeclaringClass = $methodReflection->getDeclaringClass(); + + if ($methodDeclaringClass->getName() === $childClassReflection->getName()) { return true; } } diff --git a/rules/privatization/src/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php b/rules/privatization/src/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php index 2172ce52271f..a2b91e11f8cc 100644 --- a/rules/privatization/src/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php +++ b/rules/privatization/src/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php @@ -5,8 +5,10 @@ namespace Rector\Privatization\Rector\ClassMethod; use PhpParser\Node; -use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ReflectionProvider; use Rector\Core\Rector\AbstractRector; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Privatization\VisibilityGuard\ClassMethodVisibilityGuard; @@ -23,9 +25,17 @@ final class PrivatizeFinalClassMethodRector extends AbstractRector */ private $classMethodVisibilityGuard; - public function __construct(ClassMethodVisibilityGuard $classMethodVisibilityGuard) - { + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + + public function __construct( + ClassMethodVisibilityGuard $classMethodVisibilityGuard, + ReflectionProvider $reflectionProvider + ) { $this->classMethodVisibilityGuard = $classMethodVisibilityGuard; + $this->reflectionProvider = $reflectionProvider; } public function getRuleDefinition(): RuleDefinition @@ -69,12 +79,17 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - $classLike = $node->getAttribute(AttributeKey::CLASS_NODE); - if (! $classLike instanceof Class_) { + $scope = $node->getAttribute(AttributeKey::SCOPE); + if (! $scope instanceof Scope) { + return null; + } + + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { return null; } - if (! $classLike->isFinal()) { + if (! $classReflection->isFinal()) { return null; } @@ -82,11 +97,11 @@ public function refactor(Node $node): ?Node return null; } - if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByParent($node)) { + if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByParent($node, $classReflection)) { return null; } - if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByTrait($node)) { + if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByTrait($node, $classReflection)) { return null; } diff --git a/rules/privatization/src/Rector/Property/PrivatizeFinalClassPropertyRector.php b/rules/privatization/src/Rector/Property/PrivatizeFinalClassPropertyRector.php index ada5cd020073..af471098825b 100644 --- a/rules/privatization/src/Rector/Property/PrivatizeFinalClassPropertyRector.php +++ b/rules/privatization/src/Rector/Property/PrivatizeFinalClassPropertyRector.php @@ -7,6 +7,8 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Property; +use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; use Rector\Core\Rector\AbstractRector; use Rector\NodeTypeResolver\Node\AttributeKey; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -93,31 +95,20 @@ private function isPropertyVisibilityGuardedByParent(Property $property, Class_ return false; } - $parentClasses = $this->getParentClasses($class); + /** @var Scope $scope */ + $scope = $property->getAttribute(AttributeKey::SCOPE); + + /** @var ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + $propertyName = $this->getName($property); - foreach ($parentClasses as $parentClass) { - if (property_exists($parentClass, $propertyName)) { + foreach ($classReflection->getParents() as $parentClassReflection) { + if ($parentClassReflection->hasProperty($propertyName)) { return true; } } return false; } - - /** - * @return string[] - */ - private function getParentClasses(Class_ $class): array - { - /** @var string $className */ - $className = $this->getName($class); - - $classParents = class_parents($className); - if ($classParents === false) { - return []; - } - - return $classParents; - } } diff --git a/rules/privatization/src/Reflection/ParentConstantReflectionResolver.php b/rules/privatization/src/Reflection/ParentConstantReflectionResolver.php index f9509b6f0e84..9315c4d3c2d2 100644 --- a/rules/privatization/src/Reflection/ParentConstantReflectionResolver.php +++ b/rules/privatization/src/Reflection/ParentConstantReflectionResolver.php @@ -4,8 +4,8 @@ namespace Rector\Privatization\Reflection; -use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ReflectionProvider; +use ReflectionClassConstant; final class ParentConstantReflectionResolver { @@ -19,7 +19,7 @@ public function __construct(ReflectionProvider $reflectionProvider) $this->reflectionProvider = $reflectionProvider; } - public function resolve(string $class, string $constant): ?ClassConstantReflection + public function resolve(string $class, string $constant): ?ReflectionClassConstant { if (! $this->reflectionProvider->hasClass($class)) { return null; @@ -31,7 +31,12 @@ public function resolve(string $class, string $constant): ?ClassConstantReflecti continue; } - return $parentClassReflection->getConstant($constant); + $nativeClassReflection = $parentClassReflection->getNativeReflection(); + + $constantReflection = $nativeClassReflection->getConstant($constant); + if ($constantReflection instanceof ReflectionClassConstant) { + return $constantReflection; + } } return null; diff --git a/rules/privatization/src/VisibilityGuard/ClassMethodVisibilityGuard.php b/rules/privatization/src/VisibilityGuard/ClassMethodVisibilityGuard.php index d7da2de41ea1..d1465cde2184 100644 --- a/rules/privatization/src/VisibilityGuard/ClassMethodVisibilityGuard.php +++ b/rules/privatization/src/VisibilityGuard/ClassMethodVisibilityGuard.php @@ -4,10 +4,9 @@ namespace Rector\Privatization\VisibilityGuard; -use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Reflection\ClassReflection; use Rector\NodeNameResolver\NodeNameResolver; -use Rector\NodeTypeResolver\Node\AttributeKey; final class ClassMethodVisibilityGuard { @@ -21,94 +20,54 @@ public function __construct(NodeNameResolver $nodeNameResolver) $this->nodeNameResolver = $nodeNameResolver; } - public function isClassMethodVisibilityGuardedByParent(ClassMethod $classMethod): bool - { - $classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if (! $classLike instanceof Class_) { - return false; - } - + public function isClassMethodVisibilityGuardedByParent( + ClassMethod $classMethod, + ClassReflection $classReflection + ): bool { $methodName = $this->nodeNameResolver->getName($classMethod); - $parentClasses = $this->getParentClasses($classLike); - $classInterfaces = $this->getClassInterfaces($classLike); - $classClassLikes = array_merge($parentClasses, $classInterfaces); - - return $this->methodExistsInClasses($classClassLikes, $methodName); - } + /** @var ClassReflection[] $parentClassReflections */ + $parentClassReflections = array_merge($classReflection->getParents(), $classReflection->getInterfaces()); - public function isClassMethodVisibilityGuardedByTrait(ClassMethod $classMethod): bool - { - $classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE); - if (! $classLike instanceof Class_) { - return false; + foreach ($parentClassReflections as $parentClassReflection) { + if ($parentClassReflection->hasMethod($methodName)) { + return true; + } } - $traits = $this->getParentTraits($classLike); - $methodName = $this->nodeNameResolver->getName($classMethod); - - return $this->methodExistsInClasses($traits, $methodName); + return false; } - /** - * @return string[] - */ - public function getParentTraits(Class_ $class): array - { - /** @var string $className */ - $className = $this->nodeNameResolver->getName($class); - - $traits = class_uses($className); - if ($traits === false) { - return []; - } - - return $traits; - } + public function isClassMethodVisibilityGuardedByTrait( + ClassMethod $classMethod, + ClassReflection $classReflection + ): bool { + $parentTraitReflections = $this->getParentTraits($classReflection); - /** - * @return string[] - */ - private function getParentClasses(Class_ $class): array - { - /** @var string $className */ - $className = $this->nodeNameResolver->getName($class); + $methodName = $this->nodeNameResolver->getName($classMethod); - $classParents = class_parents($className); - if ($classParents === false) { - return []; + foreach ($parentTraitReflections as $parentTraitReflection) { + if ($parentTraitReflection->hasMethod($methodName)) { + return true; + } } - return $classParents; + return false; } /** - * @return string[] + * @return ClassReflection[] */ - private function getClassInterfaces(Class_ $class): array + public function getParentTraits(ClassReflection $classReflection): array { - /** @var string $className */ - $className = $this->nodeNameResolver->getName($class); + $traitReflections = []; - $classInterfaces = class_implements($className); - if ($classInterfaces === false) { - return []; - } - - return $classInterfaces; - } - - /** - * @param string[] $classes - */ - private function methodExistsInClasses(array $classes, string $method): bool - { - foreach ($classes as $class) { - if (method_exists($class, $method)) { - return true; + foreach ($classReflection->getParents() as $parentClassReflection) { + foreach ($parentClassReflection->getTraits() as $traitReflection) { + $traitReflections[] = $traitReflection; } } - return false; + return $traitReflections; } } diff --git a/rules/removing-static/src/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php b/rules/removing-static/src/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php index 430afd64da5e..585283a55ce3 100644 --- a/rules/removing-static/src/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php +++ b/rules/removing-static/src/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php @@ -9,6 +9,7 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Reflection\ClassReflection; use Rector\Core\Rector\AbstractRector; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Privatization\VisibilityGuard\ClassMethodVisibilityGuard; @@ -100,7 +101,13 @@ private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod return null; } - if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByParent($classMethod)) { + $scope = $classMethod->getAttribute(AttributeKey::SCOPE); + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { + return null; + } + + if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByParent($classMethod, $classReflection)) { return null; } diff --git a/rules/renaming/src/NodeManipulator/ClassRenamer.php b/rules/renaming/src/NodeManipulator/ClassRenamer.php index be9f2dfc815d..6437e99541cc 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\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ObjectType; use Rector\BetterPhpDocParser\Contract\PhpDocNode\TypeAwareTagValueNodeInterface; @@ -266,21 +267,27 @@ private function refactorClassLike(ClassLike $classLike, array $oldToNewClasses) * - implements SomeInterface * - implements SomeClass */ - private function isClassToInterfaceValidChange(Name $name, string $newName): bool + private function isClassToInterfaceValidChange(Name $name, string $newClassName): bool { + if (! $this->reflectionProvider->hasClass($newClassName)) { + return true; + } + + $classReflection = $this->reflectionProvider->getClass($newClassName); + // ensure new is not with interface $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE); - if ($parentNode instanceof New_ && interface_exists($newName)) { + if ($parentNode instanceof New_ && $classReflection->isInterface()) { return false; } if ($parentNode instanceof Class_) { - return $this->isValidClassNameChange($name, $newName, $parentNode); + return $this->isValidClassNameChange($name, $parentNode, $classReflection); } // prevent to change to import, that already exists if ($parentNode instanceof UseUse) { - return $this->isValidUseImportChange($newName, $parentNode); + return $this->isValidUseImportChange($newClassName, $parentNode); } return true; @@ -354,25 +361,24 @@ private function changeNameToFullyQualifiedName(ClassLike $classLike): void }); } - private function isValidClassNameChange(Name $name, string $newName, Class_ $class): bool + private function isValidClassNameChange(Name $name, Class_ $class, ClassReflection $classReflection): bool { - // is class to interface? - if ($class->extends === $name && interface_exists($newName)) { - return false; - } - - // is interface to class? - if (in_array($name, $class->implements, true) && $this->reflectionProvider->hasClass($newName)) { - return false; - } + if ($class->extends === $name) { + // is class to interface? + if ($classReflection->isInterface()) { + return false; + } - if ($class->extends === $name && $this->reflectionProvider->hasClass($newName)) { - $classReflection = $this->reflectionProvider->getClass($newName); if ($classReflection->isFinalByKeyword()) { return false; } } + // is interface to class? + if (in_array($name, $class->implements, true) && $classReflection->isClass()) { + return false; + } + return true; } diff --git a/rules/renaming/src/NodeManipulator/IdentifierManipulator.php b/rules/renaming/src/NodeManipulator/IdentifierManipulator.php index 34453a675755..2024dec30bcf 100644 --- a/rules/renaming/src/NodeManipulator/IdentifierManipulator.php +++ b/rules/renaming/src/NodeManipulator/IdentifierManipulator.php @@ -40,14 +40,9 @@ public function __construct(NodeNameResolver $nodeNameResolver) */ public function renameNodeWithMap(Node $node, array $renameMethodMap): void { - Assert::isAnyOf( - $node, - [ClassConstFetch::class, - MethodCall::class, - PropertyFetch::class, - StaticCall::class, - ClassMethod::class, - ]); + Assert::isAnyOf($node, [ + ClassConstFetch::class, MethodCall::class, PropertyFetch::class, StaticCall::class, ClassMethod::class, + ]); $oldNodeMethodName = $this->resolveOldMethodName($node); if ($oldNodeMethodName === null) { @@ -81,16 +76,15 @@ public function removeSuffix(Node $node, string $suffixToRemove): void $node->name = new Identifier($newName); } + /** + * @param ClassConstFetch|MethodCall|PropertyFetch|StaticCall|ClassMethod $node + */ private function resolveOldMethodName(Node $node): ?string { - if (! property_exists($node, 'name')) { - return $this->nodeNameResolver->getName($node); - } - if (StaticInstanceOf::isOneOf($node, [StaticCall::class, MethodCall::class])) { return $this->nodeNameResolver->getName($node->name); } - return null; + return $this->nodeNameResolver->getName($node); } } diff --git a/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php b/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php index 72de690344f4..f09e7c5838c6 100644 --- a/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php +++ b/rules/restoration/src/Rector/New_/CompleteMissingDependencyInNewRector.php @@ -156,8 +156,8 @@ private function getNewNodeClassConstructorMethodReflection(New_ $new): ?MethodR return null; } - $reflectionClass = $this->reflectionProvider->getClass($className); - return $reflectionClass->getConstructor(); + $classReflection = $this->reflectionProvider->getClass($className); + return $classReflection->getConstructor(); } private function resolveClassToInstantiateByParameterReflection(ReflectionParameter $reflectionParameter): ?string diff --git a/rules/symfony3/src/Rector/MethodCall/FormTypeInstanceToClassConstRector.php b/rules/symfony3/src/Rector/MethodCall/FormTypeInstanceToClassConstRector.php index 5c84fe7c9c31..0b24bdb1ca52 100644 --- a/rules/symfony3/src/Rector/MethodCall/FormTypeInstanceToClassConstRector.php +++ b/rules/symfony3/src/Rector/MethodCall/FormTypeInstanceToClassConstRector.php @@ -15,11 +15,11 @@ use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; -use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Reflection\ReflectionProvider; use Rector\Core\ValueObject\MethodName; use Rector\Symfony3\NodeFactory\BuilderFormNodeFactory; use Rector\Symfony3\NodeFactory\ConfigureOptionsNodeFactory; +use ReflectionMethod; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -259,9 +259,10 @@ private function resolveNamesToArgs(string $className, array $argNodes): array } $classReflection = $this->reflectionProvider->getClass($className); + $nativeClassReflection = $classReflection->getNativeReflection(); - $constructorReflectionMethod = $classReflection->getConstructor(); - if (! $constructorReflectionMethod instanceof PhpMethodReflection) { + $constructorReflectionMethod = $nativeClassReflection->getConstructor(); + if (! $constructorReflectionMethod instanceof ReflectionMethod) { return []; } diff --git a/rules/type-declaration/src/PhpParserTypeAnalyzer.php b/rules/type-declaration/src/PhpParserTypeAnalyzer.php index 9ef57ee0d5f4..f34fbe60effd 100644 --- a/rules/type-declaration/src/PhpParserTypeAnalyzer.php +++ b/rules/type-declaration/src/PhpParserTypeAnalyzer.php @@ -9,9 +9,20 @@ use PhpParser\Node\Name; use PhpParser\Node\NullableType; use PhpParser\Node\UnionType; +use Rector\NodeNameResolver\NodeNameResolver; final class PhpParserTypeAnalyzer { + /** + * @var NodeNameResolver + */ + private $nodeNameResolver; + + public function __construct(NodeNameResolver $nodeNameResolver) + { + $this->nodeNameResolver = $nodeNameResolver; + } + /** * @param Name|NullableType|UnionType|Identifier $possibleSubtype * @param Name|NullableType|UnionType|Identifier $possibleParentType @@ -65,13 +76,11 @@ private function isUnionType(Node $possibleSubtype, Node $possibleParentType): b private function unwrapNullableAndToString(Node $node): string { - if (! $node instanceof NullableType && method_exists($node, 'toString')) { - return $node->toString(); + if (! $node instanceof NullableType) { + return $this->nodeNameResolver->getName($node); } - /** @var NullableType $type */ - $type = $node; - return $type->type->toString(); + return $this->nodeNameResolver->getName($node->type); } private function isTraversableOrIterableSubtype(string $possibleSubtype, string $possibleParentType): bool diff --git a/src/NodeAnalyzer/PropertyPresenceChecker.php b/src/NodeAnalyzer/PropertyPresenceChecker.php index 0eb5ff651868..4c63cd34b8d9 100644 --- a/src/NodeAnalyzer/PropertyPresenceChecker.php +++ b/src/NodeAnalyzer/PropertyPresenceChecker.php @@ -82,14 +82,15 @@ public function hasClassContextPropertyByName(Class_ $class, string $propertyNam */ private function getParentClassPublicAndProtectedPropertyReflections(string $className): array { - /** @var string[] $parentClassNames */ - $parentClassNames = (array) class_parents($className); + if (! $this->reflectionProvider->hasClass($className)) { + return []; + } - $propertyReflections = []; + $classReflection = $this->reflectionProvider->getClass($className); - foreach ($parentClassNames as $parentClassName) { - $reflectionClass = $this->reflectionProvider->getClass($parentClassName); - $nativeReflectionClass = $reflectionClass->getNativeReflection(); + $propertyReflections = []; + foreach ($classReflection->getParents() as $parentClassReflection) { + $nativeReflectionClass = $parentClassReflection->getNativeReflection(); $currentPropertyReflections = $nativeReflectionClass->getProperties( ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED diff --git a/src/NodeManipulator/ChildAndParentClassManipulator.php b/src/NodeManipulator/ChildAndParentClassManipulator.php index 0c13ff794694..025e5a3caa6f 100644 --- a/src/NodeManipulator/ChildAndParentClassManipulator.php +++ b/src/NodeManipulator/ChildAndParentClassManipulator.php @@ -7,6 +7,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; +use PHPStan\Reflection\ReflectionProvider; use Rector\Core\NodeAnalyzer\PromotedPropertyParamCleaner; use Rector\Core\PhpParser\Node\NodeFactory; use Rector\Core\ValueObject\MethodName; @@ -36,16 +37,23 @@ final class ChildAndParentClassManipulator */ private $promotedPropertyParamCleaner; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( NodeFactory $nodeFactory, NodeNameResolver $nodeNameResolver, NodeRepository $nodeRepository, - PromotedPropertyParamCleaner $promotedPropertyParamCleaner + PromotedPropertyParamCleaner $promotedPropertyParamCleaner, + ReflectionProvider $reflectionProvider ) { $this->nodeFactory = $nodeFactory; $this->nodeNameResolver = $nodeNameResolver; $this->nodeRepository = $nodeRepository; $this->promotedPropertyParamCleaner = $promotedPropertyParamCleaner; + $this->reflectionProvider = $reflectionProvider; } /** @@ -53,21 +61,30 @@ public function __construct( */ public function completeParentConstructor(Class_ $class, ClassMethod $classMethod): void { - /** @var string|null $parentClassName */ - $parentClassName = $class->getAttribute(AttributeKey::PARENT_CLASS_NAME); - if ($parentClassName === null) { + $className = $this->nodeNameResolver->getName($class); + if ($className === null) { + return; + } + + if (! $this->reflectionProvider->hasClass($className)) { + return; + } + + $classReflection = $this->reflectionProvider->getClass($className); + $parentClassReflection = $classReflection->getParentClass(); + if ($parentClassReflection === false) { return; } // not in analyzed scope, nothing we can do - $parentClassNode = $this->nodeRepository->findClass($parentClassName); - if ($parentClassNode !== null) { + $parentClassNode = $this->nodeRepository->findClass($parentClassReflection->getName()); + if ($parentClassNode instanceof Class_) { $this->completeParentConstructorBasedOnParentNode($parentClassNode, $classMethod); return; } // complete parent call for __construct() - if ($parentClassName !== '' && method_exists($parentClassName, MethodName::CONSTRUCT)) { + if ($parentClassReflection->hasMethod(MethodName::CONSTRUCT)) { $staticCall = $this->nodeFactory->createParentConstructWithParams([]); $classMethod->stmts[] = new Expression($staticCall); } diff --git a/src/NodeManipulator/ClassDependencyManipulator.php b/src/NodeManipulator/ClassDependencyManipulator.php index 3f4c4ef006fc..981b8297c75e 100644 --- a/src/NodeManipulator/ClassDependencyManipulator.php +++ b/src/NodeManipulator/ClassDependencyManipulator.php @@ -7,11 +7,11 @@ use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Name; -use PhpParser\Node\Param; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\Type; use Rector\Core\NodeAnalyzer\PropertyPresenceChecker; use Rector\Core\Php\PhpVersionProvider; @@ -64,6 +64,11 @@ final class ClassDependencyManipulator */ private $nodeNameResolver; + /** + * @var ReflectionProvider + */ + private $reflectionProvider; + public function __construct( ChildAndParentClassManipulator $childAndParentClassManipulator, ClassInsertManipulator $classInsertManipulator, @@ -72,7 +77,8 @@ public function __construct( StmtsManipulator $stmtsManipulator, PhpVersionProvider $phpVersionProvider, PropertyPresenceChecker $propertyPresenceChecker, - NodeNameResolver $nodeNameResolver + NodeNameResolver $nodeNameResolver, + ReflectionProvider $reflectionProvider ) { $this->classMethodAssignManipulator = $classMethodAssignManipulator; $this->nodeFactory = $nodeFactory; @@ -82,6 +88,7 @@ public function __construct( $this->phpVersionProvider = $phpVersionProvider; $this->propertyPresenceChecker = $propertyPresenceChecker; $this->nodeNameResolver = $nodeNameResolver; + $this->reflectionProvider = $reflectionProvider; } public function addConstructorDependency(Class_ $class, PropertyMetadata $propertyMetadata): void @@ -203,7 +210,17 @@ private function hasClassParentClassMethod(Class_ $class, string $methodName): b return false; } - return method_exists($parentClassName, $methodName); + if (! $this->reflectionProvider->hasClass($parentClassName)) { + return false; + } + + $classReflection = $this->reflectionProvider->getClass($parentClassName); + $parentClassReflection = $classReflection->getParentClass(); + if ($parentClassReflection === false) { + return false; + } + + return $parentClassReflection->hasMethod($methodName); } private function createParentClassMethodCall(string $methodName): Expression diff --git a/src/NodeManipulator/ClassMethodManipulator.php b/src/NodeManipulator/ClassMethodManipulator.php index e5dccd004e21..c8d2e9d6f5bb 100644 --- a/src/NodeManipulator/ClassMethodManipulator.php +++ b/src/NodeManipulator/ClassMethodManipulator.php @@ -105,6 +105,9 @@ public function isNamedConstructor(ClassMethod $classMethod): bool public function hasParentMethodOrInterfaceMethod(ClassMethod $classMethod, ?string $methodName = null): bool { $methodName = $methodName ?? $this->nodeNameResolver->getName($classMethod->name); + if ($methodName === null) { + return false; + } $scope = $classMethod->getAttribute(AttributeKey::SCOPE); if (! $scope instanceof Scope) { @@ -187,18 +190,6 @@ public function isPropertyPromotion(ClassMethod $classMethod): bool return false; } - private function isMethodInParent(string $class, string $method): bool - { - foreach ((array) class_parents($class) as $parentClass) { - /** @var string $parentClass */ - if (method_exists($parentClass, $method)) { - return true; - } - } - - return false; - } - /** * @param string[] $possibleNames */ diff --git a/src/PhpParser/Node/Value/ValueResolver.php b/src/PhpParser/Node/Value/ValueResolver.php index e3cd0960727d..73511a751141 100644 --- a/src/PhpParser/Node/Value/ValueResolver.php +++ b/src/PhpParser/Node/Value/ValueResolver.php @@ -292,10 +292,10 @@ private function resolveClassConstFetch(ClassConstFetch $classConstFetch) } if ($this->reflectionProvider->hasClass($class)) { - $reflectionClass = $this->reflectionProvider->getClass($class); + $classReflection = $this->reflectionProvider->getClass($class); - if ($reflectionClass->hasConstant($constant)) { - $constantReflection = $reflectionClass->getConstant($constant); + if ($classReflection->hasConstant($constant)) { + $constantReflection = $classReflection->getConstant($constant); return $constantReflection->getValue(); } } diff --git a/src/Rector/AbstractTemporaryRector.php b/src/Rector/AbstractTemporaryRector.php index f4403ac7a54d..88f254ae6136 100644 --- a/src/Rector/AbstractTemporaryRector.php +++ b/src/Rector/AbstractTemporaryRector.php @@ -297,6 +297,7 @@ final public function enterNode(Node $node) $originalNode = $node->getAttribute(AttributeKey::ORIGINAL_NODE) ?? clone $node; $originalNodeWithAttributes = clone $node; + $node = $this->refactor($node); // nothing to change → continue diff --git a/src/Reflection/ClassMethodReflectionFactory.php b/src/Reflection/ClassMethodReflectionFactory.php index 9cc70bbd8eb8..1cf66503b39b 100644 --- a/src/Reflection/ClassMethodReflectionFactory.php +++ b/src/Reflection/ClassMethodReflectionFactory.php @@ -4,6 +4,7 @@ namespace Rector\Core\Reflection; +use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\IntersectionType; @@ -24,10 +25,8 @@ public function __construct(ReflectionProvider $reflectionProvider) $this->reflectionProvider = $reflectionProvider; } - public function createFromPHPStanTypeAndMethodName( - Type $type, - string $methodName - ): ?\PHPStan\Reflection\MethodReflection { + public function createFromPHPStanTypeAndMethodName(Type $type, string $methodName): ?MethodReflection + { if ($type instanceof ShortenedObjectType) { return $this->createReflectionMethodIfExists($type->getFullyQualifiedName(), $methodName); } @@ -54,7 +53,7 @@ public function createFromPHPStanTypeAndMethodName( return null; } - public function createReflectionMethodIfExists(string $class, string $method): ?\PHPStan\Reflection\MethodReflection + public function createReflectionMethodIfExists(string $class, string $method): ?MethodReflection { if (! $this->reflectionProvider->hasClass($class)) { return null; diff --git a/utils/phpstan-extensions/config/rector-rules.neon b/utils/phpstan-extensions/config/rector-rules.neon index 804d33a150d9..74833dfe842d 100644 --- a/utils/phpstan-extensions/config/rector-rules.neon +++ b/utils/phpstan-extensions/config/rector-rules.neon @@ -197,8 +197,12 @@ services: - 'spl_autoload_register' - 'spl_autoload_unregister' - array_walk + # creates messy nested logic + - array_filter # there are handled in ReflectionProvider->has*() - 'class_exists' - 'interface_exists' - 'method_exists' - 'property_exists' + - class_parents + - class_implements