From 2eb71cd3d1949cbc862ee64aef5e8326119797fc Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Mon, 30 Dec 2024 15:24:43 +0100 Subject: [PATCH] Reflection: support members only on descendants --- src/Collector/ProvidedUsagesCollector.php | 16 ++-------------- src/Provider/ReflectionUsageProvider.php | 12 ++---------- tests/Rule/data/providers/reflection.php | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/Collector/ProvidedUsagesCollector.php b/src/Collector/ProvidedUsagesCollector.php index 95e7870..5c54a2f 100644 --- a/src/Collector/ProvidedUsagesCollector.php +++ b/src/Collector/ProvidedUsagesCollector.php @@ -7,9 +7,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Collectors\Collector; use PHPStan\Reflection\ReflectionProvider; -use ShipMonk\PHPStan\DeadCode\Graph\ClassConstantRef; use ShipMonk\PHPStan\DeadCode\Graph\ClassMemberUsage; -use ShipMonk\PHPStan\DeadCode\Graph\ClassMethodRef; use ShipMonk\PHPStan\DeadCode\Provider\MemberUsageProvider; use function get_class; use function sprintf; @@ -88,18 +86,8 @@ private function validateUsage( $node->getStartLine(), ); - if ($memberRefClass !== null) { - if (!$this->reflectionProvider->hasClass($memberRefClass)) { - throw new LogicException("Class '$memberRefClass' does not exist. $context"); - } - - if ($memberRef instanceof ClassMethodRef && !$this->reflectionProvider->getClass($memberRefClass)->hasMethod($memberRef->getMemberName())) { - throw new LogicException("Method '{$memberRef->getMemberName()}' does not exist in class '$memberRefClass'. $context"); - } - - if ($memberRef instanceof ClassConstantRef && !$this->reflectionProvider->getClass($memberRefClass)->hasConstant($memberRef->getMemberName())) { - throw new LogicException("Constant '{$memberRef->getMemberName()}' does not exist in class '$memberRefClass'. $context"); - } + if (($memberRefClass !== null) && !$this->reflectionProvider->hasClass($memberRefClass)) { + throw new LogicException("Class '$memberRefClass' does not exist. $context"); } if ( diff --git a/src/Provider/ReflectionUsageProvider.php b/src/Provider/ReflectionUsageProvider.php index 9173767..94dbb23 100644 --- a/src/Provider/ReflectionUsageProvider.php +++ b/src/Provider/ReflectionUsageProvider.php @@ -106,10 +106,6 @@ private function extractConstantsUsedByReflection( $firstArg = $args[array_key_first($args)]; // @phpstan-ignore offsetAccess.notFound foreach ($scope->getType($firstArg->value)->getConstantStrings() as $constantString) { - if (!$genericReflection->hasConstant($constantString->getValue())) { - continue; - } - $usedConstants[] = $this->createConstantUsage($genericReflection->getName(), $constantString->getValue()); } } @@ -140,10 +136,6 @@ private function extractMethodsUsedByReflection( $firstArg = $args[array_key_first($args)]; // @phpstan-ignore offsetAccess.notFound foreach ($scope->getType($firstArg->value)->getConstantStrings() as $constantString) { - if (!$genericReflection->hasMethod($constantString->getValue())) { - continue; - } - $usedMethods[] = $this->createMethodUsage($genericReflection->getName(), $constantString->getValue()); } } @@ -189,7 +181,7 @@ private function createConstantUsage(string $className, string $constantName): C new ClassConstantRef( $className, $constantName, - false, + true, ), ); } @@ -201,7 +193,7 @@ private function createMethodUsage(string $className, string $methodName): Class new ClassMethodRef( $className, $methodName, - false, + true, ), ); } diff --git a/tests/Rule/data/providers/reflection.php b/tests/Rule/data/providers/reflection.php index 2cea91d..76fe99b 100644 --- a/tests/Rule/data/providers/reflection.php +++ b/tests/Rule/data/providers/reflection.php @@ -46,6 +46,12 @@ class Holder5 public function __construct() {} } +abstract class HolderParent {} +class Holder6 extends HolderParent +{ + const NOT_IN_PARENT = 1; +} + enum EnumHolder1 { const CONST1 = 1; public function used() {} @@ -73,3 +79,14 @@ public function used() {} $enumReflection1 = new \ReflectionClass(EnumHolder1::class); $enumReflection1->getConstants(); $enumReflection1->getMethod('used'); + +/** + * @param class-string $fqn + */ +function testMemberOnlyInDescendant(string $fqn) { + $classReflection = new \ReflectionClass($fqn); + + if ($classReflection->hasConstant('NOT_IN_PARENT')) { + echo $classReflection->getConstant('NOT_IN_PARENT'); + } +}