From dad08d5ba05c180ba0de80d03032466635e1b52d Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Mon, 30 Dec 2024 17:57:38 +0100 Subject: [PATCH] ClassHierarchy: fix missing parts of vendor hierarchy --- src/Collector/ClassDefinitionCollector.php | 51 ++++++++-------------- tests/Rule/DeadCodeRuleTest.php | 2 +- tests/Rule/data/providers/reflection.php | 18 ++++++++ 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/Collector/ClassDefinitionCollector.php b/src/Collector/ClassDefinitionCollector.php index 065f5fd..f6da3d7 100644 --- a/src/Collector/ClassDefinitionCollector.php +++ b/src/Collector/ClassDefinitionCollector.php @@ -4,7 +4,6 @@ use LogicException; use PhpParser\Node; -use PhpParser\Node\Name; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\Enum_; @@ -14,6 +13,8 @@ use PhpParser\Node\Stmt\TraitUseAdaptation\Precedence; use PHPStan\Analyser\Scope; use PHPStan\Collectors\Collector; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ReflectionProvider; use ShipMonk\PHPStan\DeadCode\Enum\ClassLikeKind; use ShipMonk\PHPStan\DeadCode\Enum\Visibility; use function array_fill_keys; @@ -33,6 +34,13 @@ class ClassDefinitionCollector implements Collector { + private ReflectionProvider $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + public function getNodeType(): string { return ClassLike::class; @@ -61,6 +69,7 @@ public function processNode( $kind = $this->getKind($node); $typeName = $node->namespacedName->toString(); + $reflection = $this->reflectionProvider->getClass($typeName); $methods = []; @@ -87,54 +96,32 @@ public function processNode( 'name' => $typeName, 'methods' => $methods, 'constants' => $constants, - 'parents' => $this->getParents($node), + 'parents' => $this->getParents($reflection), 'traits' => $this->getTraits($node), - 'interfaces' => $this->getInterfaces($node), + 'interfaces' => $this->getInterfaces($reflection), ]; } /** * @return array */ - private function getParents(ClassLike $node): array + private function getParents(ClassReflection $reflection): array { - if ($node instanceof Class_) { - if ($node->extends === null) { - return []; - } + $parents = []; - return [$node->extends->toString() => null]; + foreach ($reflection->getParentClassesNames() as $parent) { + $parents[$parent] = null; } - if ($node instanceof Interface_) { - return array_fill_keys( - array_map( - static fn(Name $name) => $name->toString(), - $node->extends, - ), - null, - ); - } - - return []; + return $parents; } /** * @return array */ - private function getInterfaces(ClassLike $node): array + private function getInterfaces(ClassReflection $reflection): array { - if ($node instanceof Class_ || $node instanceof Enum_) { - return array_fill_keys( - array_map( - static fn(Name $name) => $name->toString(), - $node->implements, - ), - null, - ); - } - - return []; + return array_fill_keys(array_map(static fn (ClassReflection $reflection) => $reflection->getName(), $reflection->getInterfaces()), null); } /** diff --git a/tests/Rule/DeadCodeRuleTest.php b/tests/Rule/DeadCodeRuleTest.php index 358086c..3dd4878 100644 --- a/tests/Rule/DeadCodeRuleTest.php +++ b/tests/Rule/DeadCodeRuleTest.php @@ -76,7 +76,7 @@ protected function getCollectors(): array $reflectionProvider, $this->getMemberUsageProviders(), ), - new ClassDefinitionCollector(), + new ClassDefinitionCollector(self::createReflectionProvider()), new MethodCallCollector($this->createUsageOriginDetector(), $this->trackMixedAccess), new ConstantFetchCollector($this->createUsageOriginDetector(), $reflectionProvider, $this->trackMixedAccess), ]; diff --git a/tests/Rule/data/providers/reflection.php b/tests/Rule/data/providers/reflection.php index a9209e1..2559516 100644 --- a/tests/Rule/data/providers/reflection.php +++ b/tests/Rule/data/providers/reflection.php @@ -2,6 +2,8 @@ namespace Reflection; +use PHPUnit\Framework\TestCase; +use ShipMonk\PHPStan\DeadCode\Rule\RuleTestCase; interface MyParent { @@ -99,3 +101,19 @@ function testMemberOnlyInDescendant(string $fqn) { echo $classReflection->getConstant('NOT_IN_PARENT'); } } + +class UserOfVendorClass extends RuleTestCase +{ + const DUMMY = 1; +} + +/** + * @param class-string $testCase + */ +function testVendorClassDescendant(string $testCase) { + $classReflection = new \ReflectionClass($testCase); + + if ($classReflection->hasConstant('DUMMY')) { + echo $classReflection->getConstant('DUMMY'); + } +}