mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2025-01-22 13:21:12 +01:00
Add NameResolver mode that does not modify nodes
This commit is contained in:
parent
f581318dd5
commit
f21309f52f
@ -25,11 +25,18 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
/** @var bool Whether to preserve original names */
|
/** @var bool Whether to preserve original names */
|
||||||
protected $preserveOriginalNames;
|
protected $preserveOriginalNames;
|
||||||
|
|
||||||
|
/** @var bool Whether to replace resolved nodes in place, or to add resolvedNode attributes */
|
||||||
|
protected $replaceNodes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a name resolution visitor.
|
* Constructs a name resolution visitor.
|
||||||
*
|
*
|
||||||
* Options: If "preserveOriginalNames" is enabled, an "originalName" attribute will be added to
|
* Options:
|
||||||
* all name nodes that underwent resolution.
|
* * preserveOriginalNames (default false): An "originalName" attribute will be added to
|
||||||
|
* all name nodes that underwent resolution.
|
||||||
|
* * replaceNodes (default true): Resolved names are not replaced in-place. Instead a
|
||||||
|
* resolvedName attribute is added. (Names that cannot be statically resolved receive a
|
||||||
|
* namespacedName attribute, as usual.)
|
||||||
*
|
*
|
||||||
* @param ErrorHandler|null $errorHandler Error handler
|
* @param ErrorHandler|null $errorHandler Error handler
|
||||||
* @param array $options Options
|
* @param array $options Options
|
||||||
@ -37,6 +44,7 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
public function __construct(ErrorHandler $errorHandler = null, array $options = []) {
|
public function __construct(ErrorHandler $errorHandler = null, array $options = []) {
|
||||||
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
|
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
|
||||||
$this->preserveOriginalNames = !empty($options['preserveOriginalNames']);
|
$this->preserveOriginalNames = !empty($options['preserveOriginalNames']);
|
||||||
|
$this->replaceNodes = isset($options['replaceNodes']) ? $options['replaceNodes'] : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function beforeTraverse(array $nodes) {
|
public function beforeTraverse(array $nodes) {
|
||||||
@ -182,6 +190,11 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function resolveClassName(Name $name) {
|
protected function resolveClassName(Name $name) {
|
||||||
|
if (!$this->replaceNodes) {
|
||||||
|
$name->setAttribute('resolvedName', $this->getResolvedClassName($name));
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->preserveOriginalNames) {
|
if ($this->preserveOriginalNames) {
|
||||||
// Save the original name
|
// Save the original name
|
||||||
$originalName = $name;
|
$originalName = $name;
|
||||||
@ -189,6 +202,41 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
$name->setAttribute('originalName', $originalName);
|
$name->setAttribute('originalName', $originalName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->getResolvedClassName($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function resolveOtherName(Name $name, $type) {
|
||||||
|
if (!$this->replaceNodes) {
|
||||||
|
$resolvedName = $this->getResolvedOtherName($name, $type);
|
||||||
|
if (null !== $resolvedName) {
|
||||||
|
$name->setAttribute('resolvedName', $resolvedName);
|
||||||
|
} else {
|
||||||
|
$name->setAttribute('namespacedName',
|
||||||
|
FullyQualified::concat($this->namespace, $name, $name->getAttributes()));
|
||||||
|
}
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->preserveOriginalNames) {
|
||||||
|
// Save the original name
|
||||||
|
$originalName = $name;
|
||||||
|
$name = clone $originalName;
|
||||||
|
$name->setAttribute('originalName', $originalName);
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolvedName = $this->getResolvedOtherName($name, $type);
|
||||||
|
if (null !== $resolvedName) {
|
||||||
|
return $resolvedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unqualified names inside a namespace cannot be resolved at compile-time
|
||||||
|
// add the namespaced version of the name as an attribute
|
||||||
|
$name->setAttribute('namespacedName',
|
||||||
|
FullyQualified::concat($this->namespace, $name, $name->getAttributes()));
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getResolvedClassName(Name $name) {
|
||||||
// don't resolve special class names
|
// don't resolve special class names
|
||||||
if (in_array(strtolower($name->toString()), array('self', 'parent', 'static'))) {
|
if (in_array(strtolower($name->toString()), array('self', 'parent', 'static'))) {
|
||||||
if (!$name->isUnqualified()) {
|
if (!$name->isUnqualified()) {
|
||||||
@ -216,14 +264,7 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function resolveOtherName(Name $name, $type) {
|
protected function getResolvedOtherName(Name $name, $type) {
|
||||||
if ($this->preserveOriginalNames) {
|
|
||||||
// Save the original name
|
|
||||||
$originalName = $name;
|
|
||||||
$name = clone $originalName;
|
|
||||||
$name->setAttribute('originalName', $originalName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fully qualified names are already resolved
|
// fully qualified names are already resolved
|
||||||
if ($name->isFullyQualified()) {
|
if ($name->isFullyQualified()) {
|
||||||
return $name;
|
return $name;
|
||||||
@ -252,11 +293,8 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
return new FullyQualified($name, $name->getAttributes());
|
return new FullyQualified($name, $name->getAttributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
// unqualified names inside a namespace cannot be resolved at compile-time
|
// Cannot resolve statically
|
||||||
// add the namespaced version of the name as an attribute
|
return null;
|
||||||
$name->setAttribute('namespacedName',
|
|
||||||
FullyQualified::concat($this->namespace, $name, $name->getAttributes()));
|
|
||||||
return $name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if no alias exists prepend current namespace
|
// if no alias exists prepend current namespace
|
||||||
@ -264,6 +302,6 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function addNamespacedName(Node $node) {
|
protected function addNamespacedName(Node $node) {
|
||||||
$node->namespacedName = Name::concat($this->namespace, $node->name);
|
$node->namespacedName = Name::concat($this->namespace, (string) $node->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -465,4 +465,26 @@ EOC;
|
|||||||
$this->assertSame($n1, $stmts[0]->stmts[0]->class->getAttribute('originalName'));
|
$this->assertSame($n1, $stmts[0]->stmts[0]->class->getAttribute('originalName'));
|
||||||
$this->assertSame($n2, $stmts[0]->stmts[1]->name->getAttribute('originalName'));
|
$this->assertSame($n2, $stmts[0]->stmts[1]->name->getAttribute('originalName'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAttributeOnlyMode() {
|
||||||
|
$traverser = new PhpParser\NodeTraverser;
|
||||||
|
$traverser->addVisitor(new NameResolver(null, ['replaceNodes' => false]));
|
||||||
|
|
||||||
|
$n1 = new Name('Bar');
|
||||||
|
$n2 = new Name('bar');
|
||||||
|
$origStmts = [
|
||||||
|
new Stmt\Namespace_(new Name('Foo'), [
|
||||||
|
new Expr\ClassConstFetch($n1, 'FOO'),
|
||||||
|
new Expr\FuncCall($n2),
|
||||||
|
])
|
||||||
|
];
|
||||||
|
|
||||||
|
$traverser->traverse($origStmts);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
new Name\FullyQualified('Foo\Bar'), $n1->getAttribute('resolvedName'));
|
||||||
|
$this->assertFalse($n2->hasAttribute('resolvedName'));
|
||||||
|
$this->assertEquals(
|
||||||
|
new Name\FullyQualified('Foo\bar'), $n2->getAttribute('namespacedName'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user