From 0e11f21f6722c41e3ccd3ebe42f00b33c9101eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20H=C3=A4ckel?= <65503128+dhaeckel@users.noreply.github.com> Date: Tue, 11 Mar 2025 13:23:36 +0100 Subject: [PATCH 1/2] Add option to avoid cyclic references in resolved names Breaks json encoding of nodes --- lib/PhpParser/NameContext.php | 10 +++++++--- lib/PhpParser/NodeVisitor/NameResolver.php | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/PhpParser/NameContext.php b/lib/PhpParser/NameContext.php index 2265ecce82..867fbb6cc8 100644 --- a/lib/PhpParser/NameContext.php +++ b/lib/PhpParser/NameContext.php @@ -19,13 +19,17 @@ class NameContext { /** @var ErrorHandler Error handler */ protected ErrorHandler $errorHandler; + protected bool $noCyclicRefs; + /** * Create a name context. * * @param ErrorHandler $errorHandler Error handling used to report errors + * @param array{noCyclicRefs?:bool} $options */ - public function __construct(ErrorHandler $errorHandler) { + public function __construct(ErrorHandler $errorHandler, array $options = []) { $this->errorHandler = $errorHandler; + $this->noCyclicRefs = $options['noCyclicRefs'] ?? false; } /** @@ -107,12 +111,12 @@ public function getResolvedName(Name $name, int $type): ?Name { $name->getAttributes() )); } - return $name; + return $this->noCyclicRefs ? clone $name : $name; } // fully qualified names are already resolved if ($name->isFullyQualified()) { - return $name; + return $this->noCyclicRefs ? clone $name : $name; } // Try to resolve aliases diff --git a/lib/PhpParser/NodeVisitor/NameResolver.php b/lib/PhpParser/NodeVisitor/NameResolver.php index 99449c496f..d72b2a0790 100644 --- a/lib/PhpParser/NodeVisitor/NameResolver.php +++ b/lib/PhpParser/NodeVisitor/NameResolver.php @@ -32,7 +32,7 @@ class NameResolver extends NodeVisitorAbstract { * namespacedName attribute, as usual.) * * @param ErrorHandler|null $errorHandler Error handler - * @param array{preserveOriginalNames?: bool, replaceNodes?: bool} $options Options + * @param array{preserveOriginalNames?: bool, replaceNodes?: bool, noCyclicRefs?: bool} $options Options */ public function __construct(?ErrorHandler $errorHandler = null, array $options = []) { $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing()); From 559212d699a5e734fa6e3b414a44c0bd10af0f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20H=C3=A4ckel?= <65503128+dhaeckel@users.noreply.github.com> Date: Tue, 11 Mar 2025 14:03:32 +0100 Subject: [PATCH 2/2] Pass trough noCyclicRefs option --- lib/PhpParser/NodeVisitor/NameResolver.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/PhpParser/NodeVisitor/NameResolver.php b/lib/PhpParser/NodeVisitor/NameResolver.php index d72b2a0790..aceb031b0e 100644 --- a/lib/PhpParser/NodeVisitor/NameResolver.php +++ b/lib/PhpParser/NodeVisitor/NameResolver.php @@ -35,7 +35,10 @@ class NameResolver extends NodeVisitorAbstract { * @param array{preserveOriginalNames?: bool, replaceNodes?: bool, noCyclicRefs?: bool} $options Options */ public function __construct(?ErrorHandler $errorHandler = null, array $options = []) { - $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing()); + $this->nameContext = new NameContext( + $errorHandler ?? new ErrorHandler\Throwing(), + ['noCyclicRefs' => $options['noCyclicRefs'] ?? false], + ); $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false; $this->replaceNodes = $options['replaceNodes'] ?? true; }