diff --git a/src/Psalm/Internal/Analyzer/ClassAnalyzer.php b/src/Psalm/Internal/Analyzer/ClassAnalyzer.php index 0db77ba83e2..8bd9884bd2a 100644 --- a/src/Psalm/Internal/Analyzer/ClassAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ClassAnalyzer.php @@ -123,7 +123,7 @@ public function __construct(PhpParser\Node\Stmt $class, SourceAnalyzer $source, throw new UnexpectedValueException('Anonymous enums are not allowed'); } - $fq_class_name = self::getAnonymousClassName($class, $source->getFilePath()); + $fq_class_name = self::getAnonymousClassName($class, $source->getAliases(), $source->getFilePath()); } parent::__construct($class, $source, $fq_class_name); @@ -137,10 +137,25 @@ public function __construct(PhpParser\Node\Stmt $class, SourceAnalyzer $source, } /** @return non-empty-string */ - public static function getAnonymousClassName(PhpParser\Node\Stmt\Class_ $class, string $file_path): string - { - return preg_replace('/[^A-Za-z0-9]/', '_', $file_path) - . '_' . $class->getLine() . '_' . (int)$class->getAttribute('startFilePos'); + public static function getAnonymousClassName( + PhpParser\Node\Stmt\Class_ $class, + Aliases $aliases, + string $file_path + ): string { + $class_name = preg_replace('/[^A-Za-z0-9]/', '_', $file_path) + . '_' . $class->getLine() + . '_' . (int)$class->getAttribute('startFilePos'); + + $fq_class_name = Type::getFQCLNFromString( + $class_name, + $aliases, + ); + + if ($fq_class_name === '') { + throw new LogicException('Invalid class name, should never happen'); + } + + return $fq_class_name; } public function analyze( diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php index db767a30339..019f159d403 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NewAnalyzer.php @@ -159,7 +159,11 @@ public static function analyze( } } elseif ($stmt->class instanceof PhpParser\Node\Stmt\Class_) { $statements_analyzer->analyze([$stmt->class], $context); - $fq_class_name = ClassAnalyzer::getAnonymousClassName($stmt->class, $statements_analyzer->getFilePath()); + $fq_class_name = ClassAnalyzer::getAnonymousClassName( + $stmt->class, + $statements_analyzer->getAliases(), + $statements_analyzer->getFilePath(), + ); } else { self::analyzeConstructorExpression( $statements_analyzer, diff --git a/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php b/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php index 828012fa790..14309b4349a 100644 --- a/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php +++ b/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php @@ -161,7 +161,7 @@ public function start(PhpParser\Node\Stmt\ClassLike $node): ?bool throw new LogicException('Anonymous classes are always classes'); } - $fq_classlike_name = ClassAnalyzer::getAnonymousClassName($node, $this->file_path); + $fq_classlike_name = ClassAnalyzer::getAnonymousClassName($node, $this->aliases, $this->file_path); } else { $name_location = new CodeLocation($this->file_scanner, $node->name); diff --git a/tests/InternalAnnotationTest.php b/tests/InternalAnnotationTest.php index 7d0341e8d0c..dc42641d6d5 100644 --- a/tests/InternalAnnotationTest.php +++ b/tests/InternalAnnotationTest.php @@ -606,6 +606,30 @@ public function baz(): void } ', ], + 'callToInternalMethodFromAnonymousClass' => [ + 'code' => <<<'PHP' + a(); + } + }; + PHP, + ], ]; }