diff --git a/lib/PhpParser/NodeVisitor/NameResolver.php b/lib/PhpParser/NodeVisitor/NameResolver.php index ccd014ebbd..99449c496f 100644 --- a/lib/PhpParser/NodeVisitor/NameResolver.php +++ b/lib/PhpParser/NodeVisitor/NameResolver.php @@ -110,6 +110,12 @@ public function enterNode(Node $node) { $node->type = $this->resolveType($node->type); } $this->resolveAttrGroups($node); + } elseif ($node instanceof Node\PropertyHook) { + foreach ($node->params as $param) { + $param->type = $this->resolveType($param->type); + $this->resolveAttrGroups($param); + } + $this->resolveAttrGroups($node); } elseif ($node instanceof Stmt\Const_) { foreach ($node->consts as $const) { $this->addNamespacedName($const); diff --git a/test/PhpParser/NodeVisitor/NameResolverTest.php b/test/PhpParser/NodeVisitor/NameResolverTest.php index 84dc33e658..e2d5c0386a 100644 --- a/test/PhpParser/NodeVisitor/NameResolverTest.php +++ b/test/PhpParser/NodeVisitor/NameResolverTest.php @@ -201,6 +201,18 @@ class A extends B implements C, D { public const X A = X::Bar; public const X\Foo B = X\Foo::Bar; public const \X\Foo C = \X\Foo::Bar; + + public Foo $foo { + #[X] + set(#[X] Bar $v) {} + } + + public function __construct( + public Foo $bar { + #[X] + set(#[X] Bar $v) {} + } + ) {} } #[X] @@ -269,6 +281,18 @@ class A extends \NS\B implements \NS\C, \NS\D public const \NS\X A = \NS\X::Bar; public const \NS\X\Foo B = \NS\X\Foo::Bar; public const \X\Foo C = \X\Foo::Bar; + public \NS\Foo $foo { + #[\NS\X] + set(#[\NS\X] \NS\Bar $v) { + } + } + public function __construct(public \NS\Foo $bar { + #[\NS\X] + set(#[\NS\X] \NS\Bar $v) { + } + }) + { + } } #[\NS\X] interface A extends \NS\C, \NS\D @@ -543,7 +567,7 @@ public function testAttributeOnlyMode(): void { } private function parseAndResolve(string $code): array { - $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative()); + $parser = new PhpParser\Parser\Php8(new PhpParser\Lexer\Emulative()); $traverser = new PhpParser\NodeTraverser(); $traverser->addVisitor(new NameResolver());