From 5a3ede3de45f0fdb4145d7c92c066bb756820ff3 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 9 Feb 2020 10:32:51 +0100 Subject: [PATCH] decouple ParentConstantReflectionResolver --- .../ParentClassConstantNodeFinder.php | 38 ++++++++ .../PrivatizeLocalClassConstantRector.php | 86 +++++++------------ .../ParentConstantReflectionResolver.php | 27 ++++++ phpstan.neon | 3 +- 4 files changed, 99 insertions(+), 55 deletions(-) create mode 100644 packages/solid/src/NodeFinder/ParentClassConstantNodeFinder.php create mode 100644 packages/solid/src/Reflection/ParentConstantReflectionResolver.php diff --git a/packages/solid/src/NodeFinder/ParentClassConstantNodeFinder.php b/packages/solid/src/NodeFinder/ParentClassConstantNodeFinder.php new file mode 100644 index 000000000000..d7a15c8d5589 --- /dev/null +++ b/packages/solid/src/NodeFinder/ParentClassConstantNodeFinder.php @@ -0,0 +1,38 @@ +parsedNodesByType = $parsedNodesByType; + } + + public function find(string $class, string $constant): ?ClassConst + { + $classNode = $this->parsedNodesByType->findClass($class); + if ($classNode === null) { + return null; + } + + /** @var string|null $parentClassName */ + $parentClassName = $classNode->getAttribute(AttributeKey::PARENT_CLASS_NAME); + if ($parentClassName === null) { + return null; + } + + return $this->parsedNodesByType->findClassConstant($parentClassName, $constant); + } +} diff --git a/packages/solid/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php b/packages/solid/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php index 24546bcdc42d..2e212e2b4d2f 100644 --- a/packages/solid/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php +++ b/packages/solid/src/Rector/ClassConst/PrivatizeLocalClassConstantRector.php @@ -10,11 +10,12 @@ use Rector\Core\Rector\AbstractRector; use Rector\Core\RectorDefinition\CodeSample; use Rector\Core\RectorDefinition\RectorDefinition; +use Rector\Core\ValueObject\PhpVersionFeature; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\SOLID\Analyzer\ClassConstantFetchAnalyzer; +use Rector\SOLID\NodeFinder\ParentClassConstantNodeFinder; +use Rector\SOLID\Reflection\ParentConstantReflectionResolver; use Rector\SOLID\ValueObject\ConstantVisibility; -use ReflectionClass; -use ReflectionClassConstant; /** * @see \Rector\SOLID\Tests\Rector\ClassConst\PrivatizeLocalClassConstantRector\PrivatizeLocalClassConstantRectorTest @@ -36,12 +37,26 @@ final class PrivatizeLocalClassConstantRector extends AbstractRector */ private $classConstantFetchAnalyzer; + /** + * @var ParentConstantReflectionResolver + */ + private $parentConstantReflectionResolver; + + /** + * @var ParentClassConstantNodeFinder + */ + private $parentClassConstantNodeFinder; + public function __construct( ParsedNodesByType $parsedNodesByType, - ClassConstantFetchAnalyzer $classConstantFetchAnalyzer + ClassConstantFetchAnalyzer $classConstantFetchAnalyzer, + ParentConstantReflectionResolver $parentConstantReflectionResolver, + ParentClassConstantNodeFinder $parentClassConstantNodeFinder ) { $this->parsedNodesByType = $parsedNodesByType; $this->classConstantFetchAnalyzer = $classConstantFetchAnalyzer; + $this->parentConstantReflectionResolver = $parentConstantReflectionResolver; + $this->parentClassConstantNodeFinder = $parentClassConstantNodeFinder; } public function getDefinition(): RectorDefinition @@ -126,7 +141,7 @@ private function shouldSkip(ClassConst $classConst): bool return true; } - if (! $this->isAtLeastPhpVersion('7.1')) { + if (! $this->isAtLeastPhpVersion(PhpVersionFeature::CONSTANT_VISIBILITY)) { return true; } @@ -135,43 +150,21 @@ private function shouldSkip(ClassConst $classConst): bool private function findParentClassConstantAndRefactorIfPossible(string $class, string $constant): ?ConstantVisibility { - $classNode = $this->parsedNodesByType->findClass($class); - if ($classNode !== null && $classNode->hasAttribute(AttributeKey::PARENT_CLASS_NAME)) { - /** @var string $parentClass */ - $parentClass = $classNode->getAttribute(AttributeKey::PARENT_CLASS_NAME); - - if ($parentClass !== '') { - $parentClassConstant = $this->parsedNodesByType->findClassConstant($parentClass, $constant); - if ($parentClassConstant !== null) { - // Make sure the parent's constant has been refactored - $this->refactor($parentClassConstant); - - return new ConstantVisibility( - $parentClassConstant->isPublic(), - $parentClassConstant->isProtected(), - $parentClassConstant->isPrivate() - ); - } - - // If the constant isn't declared in the parent, it might be declared in the parent's parent - } - } - - $reflectionClass = new ReflectionClass($class); - if (! $reflectionClass->getParentClass()) { - return null; - } - - $parentClass = $reflectionClass->getParentClass(); - if (! $parentClass) { - return null; + $parentClassConstant = $this->parentClassConstantNodeFinder->find($class, $constant); + + if ($parentClassConstant !== null) { + // Make sure the parent's constant has been refactored + $this->refactor($parentClassConstant); + + return new ConstantVisibility( + $parentClassConstant->isPublic(), + $parentClassConstant->isProtected(), + $parentClassConstant->isPrivate() + ); + // If the constant isn't declared in the parent, it might be declared in the parent's parent } - /** @var ReflectionClass $parentClass */ - $parentClassConstantReflection = $this->resolveParentClassConstantReflection( - $parentClass->getName(), - $constant - ); + $parentClassConstantReflection = $this->parentConstantReflectionResolver->resolve($class, $constant); if ($parentClassConstantReflection === null) { return null; } @@ -250,19 +243,4 @@ private function isUsedByChildrenOnly(array $useClasses, string $class): bool return $isChild; } - - private function resolveParentClassConstantReflection(string $class, string $constant): ?ReflectionClassConstant - { - $parentReflectionClass = new ReflectionClass($class); - - while ($parentReflectionClass !== false) { - if ($parentReflectionClass->hasConstant($constant)) { - return $parentReflectionClass->getReflectionConstant($constant); - } - - $parentReflectionClass = $parentReflectionClass->getParentClass(); - } - - return null; - } } diff --git a/packages/solid/src/Reflection/ParentConstantReflectionResolver.php b/packages/solid/src/Reflection/ParentConstantReflectionResolver.php new file mode 100644 index 000000000000..9f1217fa2fde --- /dev/null +++ b/packages/solid/src/Reflection/ParentConstantReflectionResolver.php @@ -0,0 +1,27 @@ +getParentClass(); + + while ($parentReflectionClass !== false) { + if ($parentReflectionClass->hasConstant($constant)) { + return $parentReflectionClass->getReflectionConstant($constant); + } + + $parentReflectionClass = $parentReflectionClass->getParentClass(); + } + + return null; + } +} diff --git a/phpstan.neon b/phpstan.neon index 55a0ab1fc3f9..ed9563a2a477 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -9,7 +9,7 @@ parameters: level: max # to allow installing with various phsptan versions without reporting old errors here -# reportUnmatchedIgnoredErrors: false + reportUnmatchedIgnoredErrors: false autoload_directories: - stubs @@ -237,3 +237,4 @@ parameters: - '#Method Rector\\FileSystemRector\\Rector\\AbstractFileSystemRector\:\:wrapToArg\(\) should return array but returns array#' - '#Method Rector\\SOLID\\Rector\\ClassConst\\PrivatizeLocalClassConstantRector\:\:resolveParentClassConstantReflection\(\) should return ReflectionClassConstant\|null but returns ReflectionClassConstant\|false#' - '#PHPDoc tag @var for variable \$parentClass contains generic class ReflectionClass but does not specify its types\: T#' + - '#Method Rector\\SOLID\\Reflection\\ParentConstantReflectionResolver\:\:(.*?)\(\) should return ReflectionClassConstant\|null but returns ReflectionClassConstant\|false#'