diff --git a/src/Analyser/StmtHandler/ClassLikeHandler.php b/src/Analyser/StmtHandler/ClassLikeHandler.php index 88ae6f66543..cab627b2438 100644 --- a/src/Analyser/StmtHandler/ClassLikeHandler.php +++ b/src/Analyser/StmtHandler/ClassLikeHandler.php @@ -32,6 +32,7 @@ use PHPStan\Node\ClassPropertiesNode; use PHPStan\Node\ClassStatementsGatherer; use PHPStan\Node\InClassNode; +use PHPStan\PhpDoc\PhpDocPrivateClassConstFetchFinder; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ClassReflectionFactory; use PHPStan\Reflection\ReflectionProvider; @@ -64,6 +65,7 @@ public function __construct( private AttributesHandler $attributesHandler, #[AutowiredExtensions(of: ReadWritePropertiesExtension::class)] private ExtensionsCollection $readWritePropertiesExtensions, + private PhpDocPrivateClassConstFetchFinder $phpDocPrivateClassConstFetchFinder, ) { } @@ -116,7 +118,7 @@ public function processStmt( throw new ShouldNotHappenException(); } - $classStatementsGatherer = new ClassStatementsGatherer($classReflection, $nodeCallback); + $classStatementsGatherer = new ClassStatementsGatherer($this->phpDocPrivateClassConstFetchFinder, $classReflection, $nodeCallback); // the class attributes are processed before the InClassNode emission, so // rules firing on it (ClassAttributesRule) read the attribute arguments // from the storage diff --git a/src/Node/ClassStatementsGatherer.php b/src/Node/ClassStatementsGatherer.php index 71a56858423..718d40b329a 100644 --- a/src/Node/ClassStatementsGatherer.php +++ b/src/Node/ClassStatementsGatherer.php @@ -19,6 +19,7 @@ use PHPStan\Node\Property\PropertyAssign; use PHPStan\Node\Property\PropertyRead; use PHPStan\Node\Property\PropertyWrite; +use PHPStan\PhpDoc\PhpDocPrivateClassConstFetchFinder; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\MethodReflection; use PHPStan\ShouldNotHappenException; @@ -70,6 +71,7 @@ final class ClassStatementsGatherer * @param callable(Node $node, Scope $scope): void $nodeCallback */ public function __construct( + private PhpDocPrivateClassConstFetchFinder $phpDocPrivateClassConstFetchFinder, private ClassReflection $classReflection, callable $nodeCallback, ) @@ -156,6 +158,14 @@ private function gatherNodes(Node $node, Scope $scope): void if ($scope->getClassReflection()->getName() !== $this->classReflection->getName()) { return; } + + $docComment = $node->getDocComment(); + if ($docComment !== null) { + foreach ($this->phpDocPrivateClassConstFetchFinder->findClassConstFetches($docComment->getText(), $scope) as $constFetch) { + $this->constantFetches[] = $constFetch; + } + } + if ($node instanceof ClassPropertyNode) { $this->properties[] = $node; if ($node->isPromoted()) { diff --git a/src/PhpDoc/PhpDocPrivateClassConstFetchFinder.php b/src/PhpDoc/PhpDocPrivateClassConstFetchFinder.php new file mode 100644 index 00000000000..9dccf1f5335 --- /dev/null +++ b/src/PhpDoc/PhpDocPrivateClassConstFetchFinder.php @@ -0,0 +1,46 @@ + + */ + public function findClassConstFetches(string $phpDoc, Scope $scope): array + { + if (!$scope->isInClass()) { + throw new ShouldNotHappenException(); + } + + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + $scope->getFile(), + $scope->getClassReflection()->getName(), + $scope->isInTrait() ? $scope->getTraitReflection()->getName() : null, + null, + $phpDoc, + ); + + $visitor = new PhpDocPrivateClassConstFetchFinderVisitor($scope->getClassReflection(), $scope); + + (new NodeTraverser([$visitor]))->traverse($resolvedPhpDoc->getPhpDocNodes()); + + return $visitor->classConstantFetches; + } + +} diff --git a/src/PhpDoc/PhpDocPrivateClassConstFetchFinderVisitor.php b/src/PhpDoc/PhpDocPrivateClassConstFetchFinderVisitor.php new file mode 100644 index 00000000000..118ae1877ea --- /dev/null +++ b/src/PhpDoc/PhpDocPrivateClassConstFetchFinderVisitor.php @@ -0,0 +1,68 @@ + */ + public array $classConstantFetches = []; + + public function __construct(private ClassReflection $classReflection, private Scope $scope) + { + } + + #[Override] + public function enterNode(\PHPStan\PhpDocParser\Ast\Node $node) + { + if (!$node instanceof ConstFetchNode) { + return null; + } + + if ($node->className !== 'self') { + return null; + } + + $constantName = $node->name; + if (Strings::contains($constantName, '*')) { + // convert * into .*? and escape everything else so the constants can be matched against the pattern + $pattern = '{^' . str_replace('\\*', '.*?', preg_quote($constantName)) . '$}D'; + foreach ($this->classReflection->getNativeReflection()->getReflectionConstants() as $reflectionConstant) { + $classConstantName = $reflectionConstant->getName(); + if (Strings::match($classConstantName, $pattern) === null) { + continue; + } + + $this->addClassConstantFetch($classConstantName); + } + } else { + $this->addClassConstantFetch($constantName); + } + + return null; + } + + private function addClassConstantFetch(string $constantName): void + { + $this->classConstantFetches[] = new ClassConstantFetch( + new Expr\ClassConstFetch( + new Node\Name\FullyQualified($this->classReflection->getName()), + $constantName, + ), + $this->scope, + ); + } + +} diff --git a/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php b/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php index 944c758a947..67c83630e70 100644 --- a/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php @@ -132,4 +132,24 @@ public function testBug12201(): void ]); } + public function testBug6415(): void + { + $this->analyse([__DIR__ . '/data/bug-6415.php'], []); + } + + public function testBug7184(): void + { + $this->analyse([__DIR__ . '/data/bug-7184.php'], []); + } + + public function testBug9385(): void + { + $this->analyse([__DIR__ . '/data/bug-9385.php'], []); + } + + public function testPhpdocConstWildcard(): void + { + $this->analyse([__DIR__ . '/data/phpdoc-const-wildcard.php'], []); + } + } diff --git a/tests/PHPStan/Rules/DeadCode/data/bug-6415.php b/tests/PHPStan/Rules/DeadCode/data/bug-6415.php new file mode 100644 index 00000000000..51fd4850a70 --- /dev/null +++ b/tests/PHPStan/Rules/DeadCode/data/bug-6415.php @@ -0,0 +1,16 @@ + $value */ + public function bar(int $value): void { + } + + /** @param key-of $value */ + public function baz(int $value): void { + } +} diff --git a/tests/PHPStan/Rules/DeadCode/data/bug-7184.php b/tests/PHPStan/Rules/DeadCode/data/bug-7184.php new file mode 100644 index 00000000000..b1e343f0db7 --- /dev/null +++ b/tests/PHPStan/Rules/DeadCode/data/bug-7184.php @@ -0,0 +1,14 @@ += 8.0 + +namespace Bug7184; + +class Character +{ + + private const MAX_CHARACTER = 4; // ISSUE, this is being used on line 10. + + /** @param int<1,self::MAX_CHARACTER> $int */ + public function __construct( + public int $int, + ) {} +} diff --git a/tests/PHPStan/Rules/DeadCode/data/bug-9385.php b/tests/PHPStan/Rules/DeadCode/data/bug-9385.php new file mode 100644 index 00000000000..ad7657b7616 --- /dev/null +++ b/tests/PHPStan/Rules/DeadCode/data/bug-9385.php @@ -0,0 +1,36 @@ += 7.4 + +namespace Bug9385; + +final class WorkDayCalculator +{ + private const DATE_FORMAT = 'Y-m-d'; + private const WORKDAY = 1; + private const HOLIDAY = 0; + + /** @var non-empty-array> */ + private array $days = ['2023-06-01' => 1, '2023-06-02' => 1]; + + public function calculate(DateTimeInterface $start, DateTimeInterface $end): int + { + if (self::HOLIDAY === $this->getDay($start)) { + throw new RuntimeException( + sprintf('Start day should be a work one: %s', $start->format(self::DATE_FORMAT)) + ); + } + + $days = 0; + foreach (new DatePeriod($start, new DateInterval('P1D'), $end) as $day) { + $days += $this->getDay($day); + } + return $days; + } + + /** + * @return self::WORKDAY|self::HOLIDAY + */ + private function getDay(DateTimeInterface $day): int + { + return $this->days[$day->format(self::DATE_FORMAT)]; + } +} diff --git a/tests/PHPStan/Rules/DeadCode/data/phpdoc-const-wildcard.php b/tests/PHPStan/Rules/DeadCode/data/phpdoc-const-wildcard.php new file mode 100644 index 00000000000..b7ea30ea20e --- /dev/null +++ b/tests/PHPStan/Rules/DeadCode/data/phpdoc-const-wildcard.php @@ -0,0 +1,36 @@ += 7.4 + +namespace PhpdocConstWildcard; + +final class WorkDayCalculator +{ + private const DATE_FORMAT = 'Y-m-d'; + private const WORKDAY = 1; + private const HOLIDAY = 0; + + /** @var non-empty-array> */ + private array $days = ['2023-06-01' => 1, '2023-06-02' => 1]; + + public function calculate(DateTimeInterface $start, DateTimeInterface $end): int + { + if (self::HOLIDAY === $this->getDay($start)) { + throw new RuntimeException( + sprintf('Start day should be a work one: %s', $start->format(self::DATE_FORMAT)) + ); + } + + $days = 0; + foreach (new DatePeriod($start, new DateInterval('P1D'), $end) as $day) { + $days += $this->getDay($day); + } + return $days; + } + + /** + * @return self::*DAY + */ + private function getDay(DateTimeInterface $day): int + { + return $this->days[$day->format(self::DATE_FORMAT)]; + } +} diff --git a/turbo-ext/src/ClassLikeHandler.cpp b/turbo-ext/src/ClassLikeHandler.cpp index 555ac1abee6..33441e61004 100644 --- a/turbo-ext/src/ClassLikeHandler.cpp +++ b/turbo-ext/src/ClassLikeHandler.cpp @@ -214,7 +214,7 @@ class ClassLikeHandler explicit ClassLikeHandler(zend_object *self) : self(self) {} /* the constructor body: the promoted properties */ - void construct(zval *reflector, zval *classReflectionFactory, zval *calledMethodProcessor, zval *reflectionProvider, zval *attributesHandler, zval *readWritePropertiesExtensions) + void construct(zval *reflector, zval *classReflectionFactory, zval *calledMethodProcessor, zval *reflectionProvider, zval *attributesHandler, zval *readWritePropertiesExtensions, zval *phpDocPrivateClassConstFetchFinder) { zv::ObjRef object(self); object.propAtWrite(slots::reflector, zv::Val::copyOf(zv::Ref(reflector))); @@ -223,6 +223,7 @@ class ClassLikeHandler object.propAtWrite(slots::reflectionProvider, zv::Val::copyOf(zv::Ref(reflectionProvider))); object.propAtWrite(slots::attributesHandler, zv::Val::copyOf(zv::Ref(attributesHandler))); object.propAtWrite(slots::readWritePropertiesExtensions, zv::Val::copyOf(zv::Ref(readWritePropertiesExtensions))); + object.propAtWrite(slots::phpDocPrivateClassConstFetchFinder, zv::Val::copyOf(zv::Ref(phpDocPrivateClassConstFetchFinder))); } /* Mirrors supports(); false = pending exception */ @@ -321,7 +322,7 @@ class ClassLikeHandler zv::Val classScope = pt_mutating_scope_enter_class(Z_OBJ_P(resultScope), classReflection.raw()); if (UNEXPECTED(classScope.isUndef())) return zv::Val(); - zv::Val classStatementsGatherer = pt_class_statements_gatherer_new(classReflection.raw(), nodeCallback); + zv::Val classStatementsGatherer = pt_class_statements_gatherer_new(OBJ_PROP_NUM(self, slots::phpDocPrivateClassConstFetchFinder), classReflection.raw(), nodeCallback); if (UNEXPECTED(classStatementsGatherer.isUndef())) return zv::Val(); // the class attributes are processed before the InClassNode emission, so // rules firing on it (ClassAttributesRule) read the attribute arguments @@ -629,16 +630,17 @@ PT_MINIT_REGISTRATION(pt_register_class_like_handler) /* the real parameter class names: the DI container autowires the * service by reflecting the constructor */ cls.method(sigs::__construct, [](INTERNAL_FUNCTION_PARAMETERS) { - zval *reflector, *classReflectionFactory, *calledMethodProcessor, *reflectionProvider, *attributesHandler, *readWritePropertiesExtensions; - ZEND_PARSE_PARAMETERS_START(6, 6) + zval *reflector, *classReflectionFactory, *calledMethodProcessor, *reflectionProvider, *attributesHandler, *readWritePropertiesExtensions, *phpDocPrivateClassConstFetchFinder; + ZEND_PARSE_PARAMETERS_START(7, 7) Z_PARAM_OBJECT(reflector) Z_PARAM_OBJECT(classReflectionFactory) Z_PARAM_OBJECT(calledMethodProcessor) Z_PARAM_OBJECT(reflectionProvider) Z_PARAM_OBJECT(attributesHandler) Z_PARAM_OBJECT(readWritePropertiesExtensions) + Z_PARAM_OBJECT(phpDocPrivateClassConstFetchFinder) ZEND_PARSE_PARAMETERS_END(); - ClassLikeHandler(Z_OBJ_P(ZEND_THIS)).construct(reflector, classReflectionFactory, calledMethodProcessor, reflectionProvider, attributesHandler, readWritePropertiesExtensions); + ClassLikeHandler(Z_OBJ_P(ZEND_THIS)).construct(reflector, classReflectionFactory, calledMethodProcessor, reflectionProvider, attributesHandler, readWritePropertiesExtensions, phpDocPrivateClassConstFetchFinder); }); cls.method<&ClassLikeHandler::supports, zp::Obj>(sigs::supports); diff --git a/turbo-ext/src/ClassStatementsGatherer.cpp b/turbo-ext/src/ClassStatementsGatherer.cpp index 2754ebdc2ef..c4600b67776 100644 --- a/turbo-ext/src/ClassStatementsGatherer.cpp +++ b/turbo-ext/src/ClassStatementsGatherer.cpp @@ -19,7 +19,7 @@ * * State is the twin's properties in declaration order: the untyped * $nodeCallback, the eight collected arrays, then the promoted - * $classReflection. + * $phpDocPrivateClassConstFetchFinder and $classReflection. */ #include "ParserVisitors.h" @@ -99,8 +99,9 @@ class ClassStatementsGatherer public: explicit ClassStatementsGatherer(zend_object *self) : self(self) {} - void construct(zval *classReflection, zval *nodeCallback) + void construct(zval *phpDocPrivateClassConstFetchFinder, zval *classReflection, zval *nodeCallback) { + zv::ObjRef(self).propAtWrite(slots::phpDocPrivateClassConstFetchFinder, zv::Val::copyOf(zv::Ref(phpDocPrivateClassConstFetchFinder))); zv::ObjRef(self).propAtWrite(slots::classReflection, zv::Val::copyOf(zv::Ref(classReflection))); zv::ObjRef(self).propAtWrite(slots::nodeCallback, zv::Val::copyOf(zv::Ref(nodeCallback))); } @@ -235,6 +236,29 @@ class ClassStatementsGatherer return pt_type_call_static_ce(typeUtils, PT_LC("findthistype"), 1, type); } + /* foreach ($this->phpDocPrivateClassConstFetchFinder->findClassConstFetches($text, $scope) as $constFetch) + * $this->constantFetches[] = $constFetch; + * false = pending exception */ + bool gatherConstFetchesFromDocComment(zval *text, zval *scope) + { + zval *finder = OBJ_PROP_NUM(self, slots::phpDocPrivateClassConstFetchFinder); + if (UNEXPECTED(Z_TYPE_P(finder) != IS_OBJECT)) { + zend_throw_error(NULL, "Typed property PHPStan\\Node\\ClassStatementsGatherer::$phpDocPrivateClassConstFetchFinder must not be accessed before initialization"); + return false; + } + zv::Args argv{text, scope}; + zv::Val constFetches = pt_type_call(Z_OBJ_P(finder), PT_LC("findclassconstfetches"), 2, argv); + if (UNEXPECTED(constFetches.isUndef())) return false; + if (UNEXPECTED(Z_TYPE_P(constFetches.raw()) != IS_ARRAY)) { + zend_type_error("phpstan_turbo: findClassConstFetches() must return a list"); + return false; + } + for (zv::ArrayEntry entry : zv::ArrRef(constFetches.raw())) { + push(slots::constantFetches, entry.value().deref().raw()); + } + return true; + } + bool gatherNodes(zend_object *node, zval *scope) { bool inClass; @@ -251,6 +275,10 @@ class ClassStatementsGatherer zval nodeZv; ZVAL_OBJ(&nodeZv, node); + zv::Val docCommentText = pt_node_doc_comment_text(&nodeZv); + if (UNEXPECTED(docCommentText.isUndef())) return false; + if (!docCommentText.isNull() && UNEXPECTED(!gatherConstFetchesFromDocComment(docCommentText.raw(), scope))) return false; + if (isInstanceOf(node, PT_CLASS_CLASS_PROPERTY_NODE)) { push(slots::properties, &nodeZv); zval *isPromoted = pt_csg_class_property_node_is_promoted.of(node); @@ -581,16 +609,16 @@ using phpstanturbo::ClassStatementsGatherer; /* {{{ direct entries for ClassLikeHandler.cpp */ -zv::Val pt_class_statements_gatherer_new(zval *classReflection, zval *nodeCallback) +zv::Val pt_class_statements_gatherer_new(zval *phpDocPrivateClassConstFetchFinder, zval *classReflection, zval *nodeCallback) { zval object; if (UNEXPECTED(object_init_ex(&object, pt_ce_class_statements_gatherer) != SUCCESS)) return zv::Val(); zv::Val gatherer = zv::Val::adopt(object); if (UNEXPECTED(!zend_is_callable(nodeCallback, 0, NULL))) { - zend_type_error("PHPStan\\Node\\ClassStatementsGatherer::__construct(): Argument #2 ($nodeCallback) must be of type callable, %s given", zend_zval_value_name(nodeCallback)); + zend_type_error("PHPStan\\Node\\ClassStatementsGatherer::__construct(): Argument #3 ($nodeCallback) must be of type callable, %s given", zend_zval_value_name(nodeCallback)); return zv::Val(); } - ClassStatementsGatherer(Z_OBJ_P(gatherer.raw())).construct(classReflection, nodeCallback); + ClassStatementsGatherer(Z_OBJ_P(gatherer.raw())).construct(phpDocPrivateClassConstFetchFinder, classReflection, nodeCallback); return gatherer; } @@ -619,17 +647,18 @@ PT_MINIT_REGISTRATION(pt_register_class_statements_gatherer) cls.privateTypedArrayPropertyDefaultEmpty("constantFetches"); cls.privateTypedArrayPropertyDefaultEmpty("returnStatementNodes"); cls.privateTypedArrayPropertyDefaultEmpty("propertyAssigns"); + cls.privateTypedClassProperty("phpDocPrivateClassConstFetchFinder", "PHPStan\\PhpDoc\\PhpDocPrivateClassConstFetchFinder", false); cls.privateTypedClassProperty("classReflection", "PHPStan\\Reflection\\ClassReflection", false); cls.privateClassConstantValue("PROPERTY_ENUMERATING_FUNCTIONS", pt_csg_property_enumerating_functions_constant); cls.method(sigs::__construct, [](INTERNAL_FUNCTION_PARAMETERS) { - zval *classReflection, *nodeCallback; - if (!zp::parse(execute_data, classReflection, nodeCallback)) RETURN_THROWS(); + zval *phpDocPrivateClassConstFetchFinder, *classReflection, *nodeCallback; + if (!zp::parse(execute_data, phpDocPrivateClassConstFetchFinder, classReflection, nodeCallback)) RETURN_THROWS(); if (UNEXPECTED(!zend_is_callable(nodeCallback, 0, NULL))) { - zend_argument_type_error(2, "must be of type callable, %s given", zend_zval_value_name(nodeCallback)); + zend_argument_type_error(3, "must be of type callable, %s given", zend_zval_value_name(nodeCallback)); RETURN_THROWS(); } - ClassStatementsGatherer(Z_OBJ_P(ZEND_THIS)).construct(classReflection, nodeCallback); + ClassStatementsGatherer(Z_OBJ_P(ZEND_THIS)).construct(phpDocPrivateClassConstFetchFinder, classReflection, nodeCallback); }); cls.method(sigs::getProperties, [](INTERNAL_FUNCTION_PARAMETERS) { diff --git a/turbo-ext/src/generated/ClassLikeHandler.h b/turbo-ext/src/generated/ClassLikeHandler.h index 8593f19ac50..0d258a83662 100644 --- a/turbo-ext/src/generated/ClassLikeHandler.h +++ b/turbo-ext/src/generated/ClassLikeHandler.h @@ -16,6 +16,7 @@ inline constexpr uint32_t calledMethodProcessor = 2; inline constexpr uint32_t reflectionProvider = 3; inline constexpr uint32_t attributesHandler = 4; inline constexpr uint32_t readWritePropertiesExtensions = 5; +inline constexpr uint32_t phpDocPrivateClassConstFetchFinder = 6; } // namespace slot inline void declareClass(reg::Class &cls) @@ -33,6 +34,7 @@ inline void declareProperties(reg::Class &cls) cls.property("reflectionProvider", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Reflection\\ReflectionProvider"); cls.property("attributesHandler", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Analyser\\AttributesHandler"); cls.property("readWritePropertiesExtensions", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\DependencyInjection\\ExtensionsCollection"); + cls.property("phpDocPrivateClassConstFetchFinder", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\PhpDoc\\PhpDocPrivateClassConstFetchFinder"); } /* the string and parameter tables the signatures below index into (see reg::Sig) */ @@ -50,30 +52,32 @@ inline constexpr char strings[] = "PHPStan\\Analyser\\AttributesHandler\0" /* 256 */ "readWritePropertiesExtensions\0" /* 291 */ "PHPStan\\DependencyInjection\\ExtensionsCollection\0" /* 321 */ - "__construct\0" /* 370 */ - "stmt\0" /* 382 */ - "PhpParser\\Node\\Stmt\0" /* 387 */ - "\0" /* 407 */ - "supports\0" /* 408 */ - "nodeScopeResolver\0" /* 417 */ - "PHPStan\\Analyser\\NodeScopeResolver\0" /* 435 */ - "scope\0" /* 470 */ - "PHPStan\\Analyser\\MutatingScope\0" /* 476 */ - "storage\0" /* 507 */ - "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 515 */ - "nodeCallback\0" /* 556 */ - "context\0" /* 569 */ - "PHPStan\\Analyser\\StatementContext\0" /* 577 */ - "PHPStan\\Analyser\\InternalStatementResult\0" /* 611 */ - "processStmt\0" /* 652 */ - "PhpParser\\Node\\Stmt\\ClassLike\0" /* 664 */ - "PHPStan\\Dependency\\Dependencies\0" /* 694 */ - "getDeclarationDependencies\0" /* 726 */ - "className\0" /* 753 */ - "PHPStan\\Analyser\\Scope\0" /* 763 */ - "PHPStan\\Reflection\\ClassReflection\0" /* 786 */ - "getCurrentClassReflection\0" /* 821 */ - "createAstClassReflection"; /* 847 */ + "phpDocPrivateClassConstFetchFinder\0" /* 370 */ + "PHPStan\\PhpDoc\\PhpDocPrivateClassConstFetchFinder\0" /* 405 */ + "__construct\0" /* 455 */ + "stmt\0" /* 467 */ + "PhpParser\\Node\\Stmt\0" /* 472 */ + "\0" /* 492 */ + "supports\0" /* 493 */ + "nodeScopeResolver\0" /* 502 */ + "PHPStan\\Analyser\\NodeScopeResolver\0" /* 520 */ + "scope\0" /* 555 */ + "PHPStan\\Analyser\\MutatingScope\0" /* 561 */ + "storage\0" /* 592 */ + "PHPStan\\Analyser\\ExpressionResultStorage\0" /* 600 */ + "nodeCallback\0" /* 641 */ + "context\0" /* 654 */ + "PHPStan\\Analyser\\StatementContext\0" /* 662 */ + "PHPStan\\Analyser\\InternalStatementResult\0" /* 696 */ + "processStmt\0" /* 737 */ + "PhpParser\\Node\\Stmt\\ClassLike\0" /* 749 */ + "PHPStan\\Dependency\\Dependencies\0" /* 779 */ + "getDeclarationDependencies\0" /* 811 */ + "className\0" /* 838 */ + "PHPStan\\Analyser\\Scope\0" /* 848 */ + "PHPStan\\Reflection\\ClassReflection\0" /* 871 */ + "getCurrentClassReflection\0" /* 906 */ + "createAstClassReflection"; /* 932 */ inline constexpr reg::PackedArg args[] = { reg::packed(0, 0, 10), /* __construct $reflector */ reg::packed(55, 0, 78), /* __construct $classReflectionFactory */ @@ -81,38 +85,39 @@ inline constexpr reg::PackedArg args[] = { reg::packed(181, 0, 200), /* __construct $reflectionProvider */ reg::packed(238, 0, 256), /* __construct $attributesHandler */ reg::packed(291, 0, 321), /* __construct $readWritePropertiesExtensions */ - reg::packed(382, 0, 387), /* supports $stmt */ - reg::packed(407, MAY_BE_BOOL), /* supports return */ - reg::packed(417, 0, 435), /* processStmt $nodeScopeResolver */ - reg::packed(382, 0, 387), /* processStmt $stmt */ - reg::packed(470, 0, 476), /* processStmt $scope */ - reg::packed(507, 0, 515), /* processStmt $storage */ - reg::packed(556, MAY_BE_CALLABLE), /* processStmt $nodeCallback */ - reg::packed(569, 0, 577), /* processStmt $context */ - reg::packed(407, 0, 611), /* processStmt return */ - reg::packed(470, 0, 476), /* getDeclarationDependencies $scope */ - reg::packed(382, 0, 664), /* getDeclarationDependencies $stmt */ - reg::packed(407, MAY_BE_NULL, 694), /* getDeclarationDependencies return */ - reg::packed(382, 0, 664), /* getCurrentClassReflection $stmt */ - reg::packed(753, MAY_BE_STRING), /* getCurrentClassReflection $className */ - reg::packed(470, 0, 763), /* getCurrentClassReflection $scope */ - reg::packed(407, 0, 786), /* getCurrentClassReflection return */ - reg::packed(382, 0, 664), /* createAstClassReflection $stmt */ - reg::packed(753, MAY_BE_STRING), /* createAstClassReflection $className */ - reg::packed(470, 0, 763), /* createAstClassReflection $scope */ - reg::packed(407, 0, 786), /* createAstClassReflection return */ + reg::packed(370, 0, 405), /* __construct $phpDocPrivateClassConstFetchFinder */ + reg::packed(467, 0, 472), /* supports $stmt */ + reg::packed(492, MAY_BE_BOOL), /* supports return */ + reg::packed(502, 0, 520), /* processStmt $nodeScopeResolver */ + reg::packed(467, 0, 472), /* processStmt $stmt */ + reg::packed(555, 0, 561), /* processStmt $scope */ + reg::packed(592, 0, 600), /* processStmt $storage */ + reg::packed(641, MAY_BE_CALLABLE), /* processStmt $nodeCallback */ + reg::packed(654, 0, 662), /* processStmt $context */ + reg::packed(492, 0, 696), /* processStmt return */ + reg::packed(555, 0, 561), /* getDeclarationDependencies $scope */ + reg::packed(467, 0, 749), /* getDeclarationDependencies $stmt */ + reg::packed(492, MAY_BE_NULL, 779), /* getDeclarationDependencies return */ + reg::packed(467, 0, 749), /* getCurrentClassReflection $stmt */ + reg::packed(838, MAY_BE_STRING), /* getCurrentClassReflection $className */ + reg::packed(555, 0, 848), /* getCurrentClassReflection $scope */ + reg::packed(492, 0, 871), /* getCurrentClassReflection return */ + reg::packed(467, 0, 749), /* createAstClassReflection $stmt */ + reg::packed(838, MAY_BE_STRING), /* createAstClassReflection $className */ + reg::packed(555, 0, 848), /* createAstClassReflection $scope */ + reg::packed(492, 0, 871), /* createAstClassReflection return */ }; using Sig = reg::Sig; } // namespace sigtab /* the signatures of the methods the class declares itself (a used trait's are in the trait's header) */ namespace sig { -inline constexpr sigtab::Sig __construct = { { 370 /* __construct */, 6, 0, 6, reg::NoArg, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig supports = { { 408 /* supports */, 1, 6, 1, 7, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig processStmt = { { 652 /* processStmt */, 6, 8, 6, 14, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getDeclarationDependencies = { { 726 /* getDeclarationDependencies */, 2, 15, 2, 17, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig getCurrentClassReflection = { { 821 /* getCurrentClassReflection */, 3, 18, 3, 21, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig createAstClassReflection = { { 847 /* createAstClassReflection */, 3, 22, 3, 25, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig __construct = { { 455 /* __construct */, 7, 0, 7, reg::NoArg, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig supports = { { 493 /* supports */, 1, 7, 1, 8, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig processStmt = { { 737 /* processStmt */, 6, 9, 6, 15, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getDeclarationDependencies = { { 811 /* getDeclarationDependencies */, 2, 16, 2, 18, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig getCurrentClassReflection = { { 906 /* getCurrentClassReflection */, 3, 19, 3, 22, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig createAstClassReflection = { { 932 /* createAstClassReflection */, 3, 23, 3, 26, ZEND_ACC_PRIVATE } }; } // namespace sig } // namespace ptdecl::ClassLikeHandler diff --git a/turbo-ext/src/generated/ClassStatementsGatherer.h b/turbo-ext/src/generated/ClassStatementsGatherer.h index 866b703bc83..f27288e0577 100644 --- a/turbo-ext/src/generated/ClassStatementsGatherer.h +++ b/turbo-ext/src/generated/ClassStatementsGatherer.h @@ -19,7 +19,8 @@ inline constexpr uint32_t constants = 5; inline constexpr uint32_t constantFetches = 6; inline constexpr uint32_t returnStatementNodes = 7; inline constexpr uint32_t propertyAssigns = 8; -inline constexpr uint32_t classReflection = 9; +inline constexpr uint32_t phpDocPrivateClassConstFetchFinder = 9; +inline constexpr uint32_t classReflection = 10; } // namespace slot inline void declareClass(reg::Class &cls) @@ -39,84 +40,88 @@ inline void declareProperties(reg::Class &cls) cls.property("constantFetches", ZEND_ACC_PRIVATE, reg::PropertyKind::TypedEmptyArray, MAY_BE_ARRAY); cls.property("returnStatementNodes", ZEND_ACC_PRIVATE, reg::PropertyKind::TypedEmptyArray, MAY_BE_ARRAY); cls.property("propertyAssigns", ZEND_ACC_PRIVATE, reg::PropertyKind::TypedEmptyArray, MAY_BE_ARRAY); + cls.property("phpDocPrivateClassConstFetchFinder", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\PhpDoc\\PhpDocPrivateClassConstFetchFinder"); cls.property("classReflection", ZEND_ACC_PRIVATE, reg::PropertyKind::Typed, 0, "PHPStan\\Reflection\\ClassReflection"); } /* the string and parameter tables the signatures below index into (see reg::Sig) */ namespace sigtab { inline constexpr char strings[] = - "classReflection\0" /* 0 */ - "PHPStan\\Reflection\\ClassReflection\0" /* 16 */ - "nodeCallback\0" /* 51 */ - "__construct\0" /* 64 */ - "\0" /* 76 */ - "getProperties\0" /* 77 */ - "getMethods\0" /* 91 */ - "getMethodCalls\0" /* 102 */ - "getPropertyUsages\0" /* 117 */ - "getConstants\0" /* 135 */ - "getConstantFetches\0" /* 148 */ - "getReturnStatementsNodes\0" /* 167 */ - "getPropertyAssigns\0" /* 192 */ - "node\0" /* 211 */ - "PhpParser\\Node\0" /* 216 */ - "scope\0" /* 231 */ - "PHPStan\\Analyser\\Scope\0" /* 237 */ - "__invoke\0" /* 260 */ - "gatherNodes\0" /* 269 */ - "PhpParser\\Node\\Expr\\FuncCall\0" /* 281 */ - "tryToApplyPropertyReads\0" /* 310 */ - "PhpParser\\Node\\Expr\\Variable\0" /* 334 */ - "tryToApplyPromotedParameterRead\0" /* 363 */ - "ancestorConstructorCall\0" /* 395 */ - "PhpParser\\Node\\Expr\\StaticCall\0" /* 419 */ - "tryToApplyPropertyWritesFromAncestorConstructor"; /* 450 */ + "phpDocPrivateClassConstFetchFinder\0" /* 0 */ + "PHPStan\\PhpDoc\\PhpDocPrivateClassConstFetchFinder\0" /* 35 */ + "classReflection\0" /* 85 */ + "PHPStan\\Reflection\\ClassReflection\0" /* 101 */ + "nodeCallback\0" /* 136 */ + "__construct\0" /* 149 */ + "\0" /* 161 */ + "getProperties\0" /* 162 */ + "getMethods\0" /* 176 */ + "getMethodCalls\0" /* 187 */ + "getPropertyUsages\0" /* 202 */ + "getConstants\0" /* 220 */ + "getConstantFetches\0" /* 233 */ + "getReturnStatementsNodes\0" /* 252 */ + "getPropertyAssigns\0" /* 277 */ + "node\0" /* 296 */ + "PhpParser\\Node\0" /* 301 */ + "scope\0" /* 316 */ + "PHPStan\\Analyser\\Scope\0" /* 322 */ + "__invoke\0" /* 345 */ + "gatherNodes\0" /* 354 */ + "PhpParser\\Node\\Expr\\FuncCall\0" /* 366 */ + "tryToApplyPropertyReads\0" /* 395 */ + "PhpParser\\Node\\Expr\\Variable\0" /* 419 */ + "tryToApplyPromotedParameterRead\0" /* 448 */ + "ancestorConstructorCall\0" /* 480 */ + "PhpParser\\Node\\Expr\\StaticCall\0" /* 504 */ + "tryToApplyPropertyWritesFromAncestorConstructor"; /* 535 */ inline constexpr reg::PackedArg args[] = { - reg::packed(0, 0, 16), /* __construct $classReflection */ - reg::packed(51, MAY_BE_CALLABLE), /* __construct $nodeCallback */ - reg::packed(76, MAY_BE_ARRAY), /* getProperties return */ - reg::packed(76, MAY_BE_ARRAY), /* getMethods return */ - reg::packed(76, MAY_BE_ARRAY), /* getMethodCalls return */ - reg::packed(76, MAY_BE_ARRAY), /* getPropertyUsages return */ - reg::packed(76, MAY_BE_ARRAY), /* getConstants return */ - reg::packed(76, MAY_BE_ARRAY), /* getConstantFetches return */ - reg::packed(76, MAY_BE_ARRAY), /* getReturnStatementsNodes return */ - reg::packed(76, MAY_BE_ARRAY), /* getPropertyAssigns return */ - reg::packed(211, 0, 216), /* __invoke $node */ - reg::packed(231, 0, 237), /* __invoke $scope */ - reg::packed(76, MAY_BE_VOID), /* __invoke return */ - reg::packed(211, 0, 216), /* gatherNodes $node */ - reg::packed(231, 0, 237), /* gatherNodes $scope */ - reg::packed(76, MAY_BE_VOID), /* gatherNodes return */ - reg::packed(211, 0, 281), /* tryToApplyPropertyReads $node */ - reg::packed(231, 0, 237), /* tryToApplyPropertyReads $scope */ - reg::packed(76, MAY_BE_VOID), /* tryToApplyPropertyReads return */ - reg::packed(211, 0, 334), /* tryToApplyPromotedParameterRead $node */ - reg::packed(231, 0, 237), /* tryToApplyPromotedParameterRead $scope */ - reg::packed(76, MAY_BE_VOID), /* tryToApplyPromotedParameterRead return */ - reg::packed(395, 0, 419), /* tryToApplyPropertyWritesFromAncestorConstructor $ancestorConstructorCall */ - reg::packed(231, 0, 237), /* tryToApplyPropertyWritesFromAncestorConstructor $scope */ - reg::packed(76, MAY_BE_VOID), /* tryToApplyPropertyWritesFromAncestorConstructor return */ + reg::packed(0, 0, 35), /* __construct $phpDocPrivateClassConstFetchFinder */ + reg::packed(85, 0, 101), /* __construct $classReflection */ + reg::packed(136, MAY_BE_CALLABLE), /* __construct $nodeCallback */ + reg::packed(161, MAY_BE_ARRAY), /* getProperties return */ + reg::packed(161, MAY_BE_ARRAY), /* getMethods return */ + reg::packed(161, MAY_BE_ARRAY), /* getMethodCalls return */ + reg::packed(161, MAY_BE_ARRAY), /* getPropertyUsages return */ + reg::packed(161, MAY_BE_ARRAY), /* getConstants return */ + reg::packed(161, MAY_BE_ARRAY), /* getConstantFetches return */ + reg::packed(161, MAY_BE_ARRAY), /* getReturnStatementsNodes return */ + reg::packed(161, MAY_BE_ARRAY), /* getPropertyAssigns return */ + reg::packed(296, 0, 301), /* __invoke $node */ + reg::packed(316, 0, 322), /* __invoke $scope */ + reg::packed(161, MAY_BE_VOID), /* __invoke return */ + reg::packed(296, 0, 301), /* gatherNodes $node */ + reg::packed(316, 0, 322), /* gatherNodes $scope */ + reg::packed(161, MAY_BE_VOID), /* gatherNodes return */ + reg::packed(296, 0, 366), /* tryToApplyPropertyReads $node */ + reg::packed(316, 0, 322), /* tryToApplyPropertyReads $scope */ + reg::packed(161, MAY_BE_VOID), /* tryToApplyPropertyReads return */ + reg::packed(296, 0, 419), /* tryToApplyPromotedParameterRead $node */ + reg::packed(316, 0, 322), /* tryToApplyPromotedParameterRead $scope */ + reg::packed(161, MAY_BE_VOID), /* tryToApplyPromotedParameterRead return */ + reg::packed(480, 0, 504), /* tryToApplyPropertyWritesFromAncestorConstructor $ancestorConstructorCall */ + reg::packed(316, 0, 322), /* tryToApplyPropertyWritesFromAncestorConstructor $scope */ + reg::packed(161, MAY_BE_VOID), /* tryToApplyPropertyWritesFromAncestorConstructor return */ }; using Sig = reg::Sig; } // namespace sigtab /* the signatures of the methods the class declares itself (a used trait's are in the trait's header) */ namespace sig { -inline constexpr sigtab::Sig __construct = { { 64 /* __construct */, 2, 0, 2, reg::NoArg, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getProperties = { { 77 /* getProperties */, 0, 2, 0, 2, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getMethods = { { 91 /* getMethods */, 0, 3, 0, 3, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getMethodCalls = { { 102 /* getMethodCalls */, 0, 4, 0, 4, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getPropertyUsages = { { 117 /* getPropertyUsages */, 0, 5, 0, 5, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getConstants = { { 135 /* getConstants */, 0, 6, 0, 6, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getConstantFetches = { { 148 /* getConstantFetches */, 0, 7, 0, 7, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getReturnStatementsNodes = { { 167 /* getReturnStatementsNodes */, 0, 8, 0, 8, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig getPropertyAssigns = { { 192 /* getPropertyAssigns */, 0, 9, 0, 9, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig __invoke = { { 260 /* __invoke */, 2, 10, 2, 12, ZEND_ACC_PUBLIC } }; -inline constexpr sigtab::Sig gatherNodes = { { 269 /* gatherNodes */, 2, 13, 2, 15, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig tryToApplyPropertyReads = { { 310 /* tryToApplyPropertyReads */, 2, 16, 2, 18, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig tryToApplyPromotedParameterRead = { { 363 /* tryToApplyPromotedParameterRead */, 2, 19, 2, 21, ZEND_ACC_PRIVATE } }; -inline constexpr sigtab::Sig tryToApplyPropertyWritesFromAncestorConstructor = { { 450 /* tryToApplyPropertyWritesFromAncestorConstructor */, 2, 22, 2, 24, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig __construct = { { 149 /* __construct */, 3, 0, 3, reg::NoArg, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getProperties = { { 162 /* getProperties */, 0, 3, 0, 3, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getMethods = { { 176 /* getMethods */, 0, 4, 0, 4, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getMethodCalls = { { 187 /* getMethodCalls */, 0, 5, 0, 5, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getPropertyUsages = { { 202 /* getPropertyUsages */, 0, 6, 0, 6, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getConstants = { { 220 /* getConstants */, 0, 7, 0, 7, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getConstantFetches = { { 233 /* getConstantFetches */, 0, 8, 0, 8, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getReturnStatementsNodes = { { 252 /* getReturnStatementsNodes */, 0, 9, 0, 9, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig getPropertyAssigns = { { 277 /* getPropertyAssigns */, 0, 10, 0, 10, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig __invoke = { { 345 /* __invoke */, 2, 11, 2, 13, ZEND_ACC_PUBLIC } }; +inline constexpr sigtab::Sig gatherNodes = { { 354 /* gatherNodes */, 2, 14, 2, 16, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig tryToApplyPropertyReads = { { 395 /* tryToApplyPropertyReads */, 2, 17, 2, 19, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig tryToApplyPromotedParameterRead = { { 448 /* tryToApplyPromotedParameterRead */, 2, 20, 2, 22, ZEND_ACC_PRIVATE } }; +inline constexpr sigtab::Sig tryToApplyPropertyWritesFromAncestorConstructor = { { 535 /* tryToApplyPropertyWritesFromAncestorConstructor */, 2, 23, 2, 25, ZEND_ACC_PRIVATE } }; } // namespace sig } // namespace ptdecl::ClassStatementsGatherer diff --git a/turbo-ext/src/support.h b/turbo-ext/src/support.h index 6c0e26f9c3a..29005208426 100644 --- a/turbo-ext/src/support.h +++ b/turbo-ext/src/support.h @@ -2752,8 +2752,8 @@ zv::Val pt_class_reflection_get_file_name(zend_object *classReflection); * $flow) ($flow NULL or IS_NULL for null); UNDEF = pending exception */ zv::Val pt_variable_liveness_resolver_resolve(zval *function, zval *flow); -/* ClassStatementsGatherer.cpp — new ClassStatementsGatherer($classReflection, - * $nodeCallback) / its collected lists (getProperties() ... getPropertyAssigns() +/* ClassStatementsGatherer.cpp — new ClassStatementsGatherer( + * $phpDocPrivateClassConstFetchFinder, $classReflection, $nodeCallback) / its collected lists (getProperties() ... getPropertyAssigns() * of an instance of the shadowing class); UNDEF = pending exception */ enum pt_class_statements_gatherer_list { @@ -2766,7 +2766,7 @@ enum pt_class_statements_gatherer_list PT_CSG_LIST_RETURN_STATEMENT_NODES, PT_CSG_LIST_PROPERTY_ASSIGNS, }; -zv::Val pt_class_statements_gatherer_new(zval *classReflection, zval *nodeCallback); +zv::Val pt_class_statements_gatherer_new(zval *phpDocPrivateClassConstFetchFinder, zval *classReflection, zval *nodeCallback); zv::Val pt_class_statements_gatherer_get(zval *gatherer, pt_class_statements_gatherer_list list); /* }}} */ diff --git a/turbo-ext/tests/analyser-values.php b/turbo-ext/tests/analyser-values.php index 8d50161bb7e..e3db8a40f46 100644 --- a/turbo-ext/tests/analyser-values.php +++ b/turbo-ext/tests/analyser-values.php @@ -752,7 +752,7 @@ public function resolveConditionalTypes(\PHPStan\Type\Type $type): \PHPStan\Type // an internal function words the argument count error differently $r['too few arguments'] = $avCatch(static fn () => $recording($avN['one']))[0]; foreach (['native gatherer' => \PHPStanTurbo\ClassStatementsGatherer::class, 'php gatherer' => \PHPStan\Node\ClassStatementsGatherer::class] as $gathererLabel => $gathererClass) { - $gatherer = new $gathererClass($avGathererClass, $recording); + $gatherer = new $gathererClass($avContainer->getByType(\PHPStan\PhpDoc\PhpDocPrivateClassConstFetchFinder::class), $avGathererClass, $recording); $r['through ' . $gathererLabel] = $avCatch(static fn () => $gatherer($avN['dim'], $avScope)); } $r['pairs'] = array_map(static fn (array $pair): array => [$avDescribe($pair[0]), $avDescribe($pair[1]), array_keys($pair)], $recording->getPairs()); diff --git a/turbo-ext/tests/class-statements-gatherer-fixture.php b/turbo-ext/tests/class-statements-gatherer-fixture.php index 877b4249cba..c7f6c5c9dac 100644 --- a/turbo-ext/tests/class-statements-gatherer-fixture.php +++ b/turbo-ext/tests/class-statements-gatherer-fixture.php @@ -133,6 +133,18 @@ public function __toString(): string return $this->name; } + /** + * @param value-of $name + * @return self::LIMIT|self::LIM* + */ + public function phpDocConstants(string $name): int + { + /** @var key-of $key */ + $key = 0; + + return self::LIMIT + $key + strlen($name); + } + } final class WithoutConstructor extends Base diff --git a/turbo-ext/tests/class-statements-gatherer.php b/turbo-ext/tests/class-statements-gatherer.php index afc7819663e..6cf6febd318 100644 --- a/turbo-ext/tests/class-statements-gatherer.php +++ b/turbo-ext/tests/class-statements-gatherer.php @@ -116,9 +116,10 @@ function check(bool $cond, string $msg): void }; $csgGetters = ['getProperties', 'getMethods', 'getMethodCalls', 'getPropertyUsages', 'getConstants', 'getConstantFetches', 'getReturnStatementsNodes', 'getPropertyAssigns']; -$csgRun = static function (string $gathererClass, \PHPStan\Reflection\ClassReflection $classReflection, array $pairs) use ($csgDescribe, $csgGetters): array { +$csgFinder = $csgContainer->getByType(\PHPStan\PhpDoc\PhpDocPrivateClassConstFetchFinder::class); +$csgRun = static function (string $gathererClass, \PHPStan\Reflection\ClassReflection $classReflection, array $pairs) use ($csgDescribe, $csgGetters, $csgFinder): array { $forwarded = []; - $gatherer = new $gathererClass($classReflection, static function (\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) use (&$forwarded): void { + $gatherer = new $gathererClass($csgFinder, $classReflection, static function (\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) use (&$forwarded): void { $forwarded[] = [spl_object_id($node), spl_object_id($scope)]; }); foreach ($pairs as [$node, $scope]) { @@ -149,7 +150,7 @@ function check(bool $cond, string $msg): void if ($csgOutside !== null) { $csgThrown = []; foreach (['php' => \PHPStan\Node\ClassStatementsGatherer::class, 'native' => \PHPStanTurbo\ClassStatementsGatherer::class] as $csgSide => $csgClass) { - $csgGatherer = new $csgClass(reset($csgClasses), static function (): void { + $csgGatherer = new $csgClass($csgFinder, reset($csgClasses), static function (): void { }); try { $csgGatherer($csgOutside[0], $csgOutside[1]);