diff --git a/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php b/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php index 14f90935510..315bc0bbb8f 100644 --- a/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php +++ b/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php @@ -169,7 +169,7 @@ public function __construct( public function enterNode(PhpParser\Node $node) { foreach ($node->getComments() as $comment) { - if ($comment instanceof PhpParser\Comment\Doc) { + if ($comment instanceof PhpParser\Comment\Doc && !$node instanceof PhpParser\Node\Stmt\ClassLike) { $self_fqcln = $node instanceof PhpParser\Node\Stmt\ClassLike && $node->name !== null ? ($this->aliases->namespace ? $this->aliases->namespace . '\\' : '') . $node->name->name @@ -189,12 +189,6 @@ public function enterNode(PhpParser\Node $node) } $this->type_aliases += $type_aliases; - - if ($type_aliases - && $node instanceof PhpParser\Node\Stmt\ClassLike - ) { - $this->classlike_type_aliases = $type_aliases; - } } catch (DocblockParseException $e) { $this->file_storage->docblock_issues[] = new InvalidDocblock( (string)$e->getMessage(), @@ -1477,6 +1471,42 @@ function (array $l, array $r) : int { } } + foreach ($node->getComments() as $comment) { + if (!$comment instanceof PhpParser\Comment\Doc) { + continue; + } + + try { + $type_aliases = CommentAnalyzer::getTypeAliasesFromComment( + $comment, + $this->aliases, + $this->type_aliases, + $fq_classlike_name + ); + + foreach ($type_aliases as $type_alias) { + // finds issues, if there are any + TypeParser::parseTokens($type_alias->replacement_tokens); + } + + $this->type_aliases += $type_aliases; + + if ($type_aliases) { + $this->classlike_type_aliases = $type_aliases; + } + } catch (DocblockParseException $e) { + $storage->docblock_issues[] = new InvalidDocblock( + (string)$e->getMessage(), + new CodeLocation($this->file_scanner, $node, null, true) + ); + } catch (TypeParseTreeException $e) { + $storage->docblock_issues[] = new InvalidDocblock( + (string)$e->getMessage(), + new CodeLocation($this->file_scanner, $node, null, true) + ); + } + } + foreach ($node->stmts as $node_stmt) { if ($node_stmt instanceof PhpParser\Node\Stmt\ClassConst) { $this->visitClassConstDeclaration($node_stmt, $storage, $fq_classlike_name); diff --git a/tests/TypeAnnotationTest.php b/tests/TypeAnnotationTest.php index 736e807c4db..86a1d041074 100644 --- a/tests/TypeAnnotationTest.php +++ b/tests/TypeAnnotationTest.php @@ -14,6 +14,8 @@ public function providerValidCodeParse() return [ 'typeAliasBeforeClass' => [ ' [ ' [ ' [ ' */ class Bar { @@ -155,8 +163,10 @@ function f($p) { return $r; }', ], - 'classTypeAlias' => [ + 'classTypeAliasSimple' => [ ' [ ' [ ' [ ' [ ' */ @@ -309,6 +327,8 @@ class A {}', ], 'typeAliasInObjectLike' => [ ' [ ' [ ' "Matt"]; + namespace Barrr; + + class Phone { + function toArray(): array { + return ["name" => "Matt"]; + } } - } - /** - * @psalm-import-type PhoneType from Phone - */ - class User {}', + /** + * @psalm-import-type PhoneType from Phone + */ + class User {}', 'error_message' => 'InvalidTypeImport', ], 'classTypeAliasFromInvalidClass' => [ ' 'UndefinedDocblockClass', ], 'malformedImportMissingFrom' => [ ' [ ' [ ' [ ' [ ' 'InvalidDocblock', + 'error_message' => 'UndefinedDocblockClass', ], 'mergeImportedTypes' => [ '