1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Namespace anonymous classes

Fixes vimeo/psalm#10755
This commit is contained in:
Bruce Weirdan 2024-03-03 16:18:48 +01:00
parent 20e8604b0c
commit 6b9b4b523d
4 changed files with 50 additions and 7 deletions

View File

@ -123,7 +123,7 @@ final class ClassAnalyzer extends ClassLikeAnalyzer
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 @@ final class ClassAnalyzer extends ClassLikeAnalyzer
}
/** @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(

View File

@ -159,7 +159,11 @@ final class NewAnalyzer extends CallAnalyzer
}
} 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,

View File

@ -161,7 +161,7 @@ final class ClassLikeNodeScanner
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);

View File

@ -606,6 +606,30 @@ class InternalAnnotationTest extends TestCase
}
',
],
'callToInternalMethodFromAnonymousClass' => [
'code' => <<<'PHP'
<?php
namespace X;
/**
* @internal
* @psalm-internal X
*/
class A
{
public function a(): void {}
}
new class (new A)
{
public function __construct(
private A $a
) {
$a->a();
}
};
PHP,
],
];
}