diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 7c2a0c8518..75806f547e 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -335,7 +335,10 @@ private function processStmtNode( if (isset($stmt->namespacedName)) { $classScope = $scope->enterClass($this->broker->getClass((string) $stmt->namespacedName)); } elseif ($stmt instanceof Class_) { - $classScope = $scope->enterAnonymousClass($this->broker->getAnonymousClassReflection($stmt, $scope)); + if ($stmt->name === null) { + throw new \PHPStan\ShouldNotHappenException(); + } + $classScope = $scope->enterClass($this->broker->getClass($stmt->name->toString())); } else { throw new \PHPStan\ShouldNotHappenException(); } @@ -1403,6 +1406,7 @@ function (Scope $scope) use ($expr, $nodeCallback, $depth): Scope { if ($expr->class instanceof Expr) { $scope = $this->processExprNode($expr->class, $scope, $nodeCallback, $depth + 1); } elseif ($expr->class instanceof Class_) { + $this->broker->getAnonymousClassReflection($expr->class, $scope); // populates $expr->class->name $this->processStmtNode($expr->class, $scope, $nodeCallback); } elseif ($this->broker->hasClass($expr->class->toString())) { $classReflection = $this->broker->getClass($expr->class->toString()); diff --git a/src/Analyser/Scope.php b/src/Analyser/Scope.php index 85fdef8e78..f67ed9a9f3 100644 --- a/src/Analyser/Scope.php +++ b/src/Analyser/Scope.php @@ -1972,11 +1972,6 @@ public function isInClosureBind(): bool return $this->inClosureBindScopeClass !== null; } - public function enterAnonymousClass(ClassReflection $anonymousClass): self - { - return $this->enterClass($anonymousClass); - } - public function enterAnonymousFunction( Expr\Closure $closure ): self diff --git a/src/Broker/Broker.php b/src/Broker/Broker.php index 23eadbd659..5fcc1c2908 100644 --- a/src/Broker/Broker.php +++ b/src/Broker/Broker.php @@ -292,12 +292,12 @@ public function getAnonymousClassReflection( $classNode, $filename ); + $classNode->name = new \PhpParser\Node\Identifier($className); if (isset(self::$anonymousClasses[$className])) { return self::$anonymousClasses[$className]; } - $classNode->name = new \PhpParser\Node\Identifier($className); eval($this->printer->prettyPrint([$classNode])); self::$anonymousClasses[$className] = $this->getClassFromReflection( diff --git a/tests/PHPStan/Analyser/AnonymousClassNameRule.php b/tests/PHPStan/Analyser/AnonymousClassNameRule.php new file mode 100644 index 0000000000..ab127eb834 --- /dev/null +++ b/tests/PHPStan/Analyser/AnonymousClassNameRule.php @@ -0,0 +1,45 @@ +broker = $broker; + } + + public function getNodeType(): string + { + return Class_::class; + } + + /** + * @param Class_ $node + * @param Scope $scope + * @return string[] + */ + public function processNode(Node $node, Scope $scope): array + { + $className = isset($node->namespacedName) + ? (string) $node->namespacedName + : (string) $node->name; + try { + $this->broker->getClass($className); + } catch (\PHPStan\Broker\ClassNotFoundException $e) { + return ['not found']; + } + + return ['found']; + } + +} diff --git a/tests/PHPStan/Analyser/AnonymousClassNameRuleTest.php b/tests/PHPStan/Analyser/AnonymousClassNameRuleTest.php new file mode 100644 index 0000000000..621320e403 --- /dev/null +++ b/tests/PHPStan/Analyser/AnonymousClassNameRuleTest.php @@ -0,0 +1,27 @@ +createBroker(); + return new AnonymousClassNameRule($broker); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/anonymous-class-name.php'], [ + [ + 'found', + 6, + ], + ]); + } + +}