diff --git a/src/Transform/RuntimeAttributeFactoryLowering.php b/src/Transform/RuntimeAttributeFactoryLowering.php index ae8b15a4..0a884da2 100644 --- a/src/Transform/RuntimeAttributeFactoryLowering.php +++ b/src/Transform/RuntimeAttributeFactoryLowering.php @@ -78,14 +78,36 @@ final class RuntimeAttributeFactoryLowering extends NodeVisitorAbstract return null; } - if (!$node instanceof Node\Attribute) { - return null; + return null; + } + + public function leaveNode(Node $node): null + { + if ($node instanceof Node\Attribute) { + $this->lowerAttribute($node); + } elseif ($node instanceof Stmt\ClassLike) { + array_pop($this->classStack); + } elseif ($node instanceof Stmt\Namespace_) { + $factories = array_pop($this->namespaceFactories); + if ($factories !== []) { + array_push($node->stmts, ...$factories); + } + $this->namespace = ''; } - if (CompileTimeAttributeRegistry::get($node->name->toString()) !== null) { - return null; + return null; + } + + private function lowerAttribute(Node\Attribute $attribute): void + { + if (CompileTimeAttributeRegistry::get($attribute->name->toString()) !== null) { + return; } - foreach ($node->args as $argument) { + // Attribute children have now passed through NameResolver. Processing + // on enterNode() resolves imported enum names relative to the current + // namespace (for example `use A\\Status; Status::Active`) and misses + // the enum case, causing gen_stub to persist its backing scalar. + foreach ($attribute->args as $argument) { if (!$this->requiresFactory($argument->value)) { continue; } @@ -102,21 +124,6 @@ final class RuntimeAttributeFactoryLowering extends NodeVisitorAbstract $this->globalFactories[] = $factory['node']; } } - return null; - } - - public function leaveNode(Node $node): null - { - if ($node instanceof Stmt\ClassLike) { - array_pop($this->classStack); - } elseif ($node instanceof Stmt\Namespace_) { - $factories = array_pop($this->namespaceFactories); - if ($factories !== []) { - array_push($node->stmts, ...$factories); - } - $this->namespace = ''; - } - return null; } public function afterTraverse(array $nodes): ?array diff --git a/tests/compiler/attribute/imported-enum-defaults.phpt b/tests/compiler/attribute/imported-enum-defaults.phpt new file mode 100644 index 00000000..57c72aa3 --- /dev/null +++ b/tests/compiler/attribute/imported-enum-defaults.phpt @@ -0,0 +1,87 @@ +--TEST-- +Imported enum cases are preserved in property and parameter defaults +--FILE-- +explicit === IdType::Assigned); + var_dump($record->default === IdType::Auto); + var_dump($record->promoted === IdType::Auto); + var_dump($record->select() === IdType::Auto); + + $reflection = new ReflectionClass(Record::class); + $explicit = $reflection->getProperty('explicit')->getAttributes(TableId::class)[0]; + var_dump($explicit->getArguments()[0] === IdType::Assigned); + var_dump($explicit->newInstance()->type === IdType::Assigned); + + $default = $reflection->getProperty('default')->getAttributes(TableId::class)[0]; + var_dump($default->getArguments()); + var_dump($default->newInstance()->type === IdType::Auto); + + $parameter = $reflection->getMethod('select')->getParameters()[0]; + var_dump($parameter->getDefaultValue() === IdType::Auto); + } +} +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +array(0) { +} +bool(true) +bool(true)