From a6c0991073fe3c7c022d5be1c561c34e0b205dc2 Mon Sep 17 00:00:00 2001 From: Brown Date: Sun, 7 Jun 2020 12:00:55 -0400 Subject: [PATCH] Fix #3532 - expand type alias types recursively --- .../Internal/Analyzer/CommentAnalyzer.php | 12 ++++--- .../Internal/PhpVisitor/ReflectorVisitor.php | 8 ++++- src/Psalm/Internal/Type/TypeExpander.php | 27 +++++++++++++- tests/TypeAnnotationTest.php | 36 +++++++++++++++++++ 4 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/CommentAnalyzer.php b/src/Psalm/Internal/Analyzer/CommentAnalyzer.php index 15f1db770..839778555 100644 --- a/src/Psalm/Internal/Analyzer/CommentAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/CommentAnalyzer.php @@ -264,7 +264,8 @@ class CommentAnalyzer public static function getTypeAliasesFromComment( PhpParser\Comment\Doc $comment, Aliases $aliases, - array $type_aliases = null + ?array $type_aliases, + ?string $self_fqcln ) { $parsed_docblock = DocComment::parsePreservingLength($comment); @@ -275,7 +276,8 @@ class CommentAnalyzer return self::getTypeAliasesFromCommentLines( $parsed_docblock->tags['psalm-type'], $aliases, - $type_aliases + $type_aliases, + $self_fqcln ); } @@ -291,7 +293,8 @@ class CommentAnalyzer private static function getTypeAliasesFromCommentLines( array $type_alias_comment_lines, Aliases $aliases, - array $type_aliases = null + ?array $type_aliases, + ?string $self_fqcln ) { $type_alias_tokens = []; @@ -344,7 +347,8 @@ class CommentAnalyzer $type_string, $aliases, null, - $type_alias_tokens + $type_aliases + $type_alias_tokens + $type_aliases, + $self_fqcln ); } catch (TypeParseTreeException $e) { throw new DocblockParseException($type_string . ' is not a valid type'); diff --git a/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php b/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php index 251bfbf51..775f67c2b 100644 --- a/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php +++ b/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php @@ -166,11 +166,17 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse { foreach ($node->getComments() as $comment) { if ($comment instanceof PhpParser\Comment\Doc) { + $self_fqcln = $node instanceof PhpParser\Node\Stmt\ClassLike + && $node->name !== null + ? ($this->aliases->namespace ? $this->aliases->namespace . '\\' : '') . $node->name->name + : null; + try { $type_aliases = CommentAnalyzer::getTypeAliasesFromComment( $comment, $this->aliases, - $this->type_aliases + $this->type_aliases, + $self_fqcln ); foreach ($type_aliases as $type_alias) { diff --git a/src/Psalm/Internal/Type/TypeExpander.php b/src/Psalm/Internal/Type/TypeExpander.php index c09076c88..e21e254b0 100644 --- a/src/Psalm/Internal/Type/TypeExpander.php +++ b/src/Psalm/Internal/Type/TypeExpander.php @@ -288,7 +288,32 @@ class TypeExpander $resolved_type_alias = $class_storage->type_aliases[$type_alias_name]; if ($resolved_type_alias->replacement_atomic_types) { - return $resolved_type_alias->replacement_atomic_types; + $replacement_atomic_types = $resolved_type_alias->replacement_atomic_types; + + $recursively_fleshed_out_types = []; + + foreach ($replacement_atomic_types as $replacement_atomic_type) { + $recursively_fleshed_out_type = self::expandAtomic( + $codebase, + $replacement_atomic_type, + $self_class, + $static_class_type, + $parent_class, + $evaluate_class_constants, + $evaluate_conditional_types + ); + + if (is_array($recursively_fleshed_out_type)) { + $recursively_fleshed_out_types = array_merge( + $recursively_fleshed_out_type, + $recursively_fleshed_out_types + ); + } else { + $recursively_fleshed_out_types[] = $recursively_fleshed_out_type; + } + } + + return $recursively_fleshed_out_types; } } } diff --git a/tests/TypeAnnotationTest.php b/tests/TypeAnnotationTest.php index 41f5d7299..df30f770f 100644 --- a/tests/TypeAnnotationTest.php +++ b/tests/TypeAnnotationTest.php @@ -253,6 +253,42 @@ class TypeAnnotationTest extends TestCase } }' ], + 'importTypeForParam' => [ + 'b($type); + } + + /** + * @psalm-param Type2 $type + */ + private function b(int $type): void + { + } + }' + ], ]; }