2011-09-28 20:14:27 +02:00
|
|
|
<?php
|
|
|
|
|
2014-02-06 14:44:16 +01:00
|
|
|
namespace PhpParser\NodeVisitor;
|
|
|
|
|
|
|
|
use PhpParser\NodeVisitorAbstract;
|
|
|
|
use PhpParser\Error;
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Name;
|
|
|
|
use PhpParser\Node\Expr;
|
|
|
|
use PhpParser\Node\Stmt;
|
|
|
|
|
|
|
|
class NameResolver extends NodeVisitorAbstract
|
2011-09-28 20:14:27 +02:00
|
|
|
{
|
|
|
|
/**
|
2014-02-06 14:44:16 +01:00
|
|
|
* @var null|Name Current namespace
|
2011-09-28 20:14:27 +02:00
|
|
|
*/
|
|
|
|
protected $namespace;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array Currently defined namespace and class aliases
|
|
|
|
*/
|
|
|
|
protected $aliases;
|
|
|
|
|
|
|
|
public function beforeTraverse(array $nodes) {
|
|
|
|
$this->namespace = null;
|
|
|
|
$this->aliases = array();
|
|
|
|
}
|
|
|
|
|
2014-02-06 14:44:16 +01:00
|
|
|
public function enterNode(Node $node) {
|
|
|
|
if ($node instanceof Stmt\Namespace_) {
|
2011-09-28 20:14:27 +02:00
|
|
|
$this->namespace = $node->name;
|
|
|
|
$this->aliases = array();
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\UseUse) {
|
2013-11-13 11:49:45 +01:00
|
|
|
$aliasName = strtolower($node->alias);
|
|
|
|
if (isset($this->aliases[$aliasName])) {
|
2014-02-06 14:44:16 +01:00
|
|
|
throw new Error(
|
2011-09-28 20:14:27 +02:00
|
|
|
sprintf(
|
2011-12-10 12:11:53 +01:00
|
|
|
'Cannot use "%s" as "%s" because the name is already in use',
|
2011-09-28 20:14:27 +02:00
|
|
|
$node->name, $node->alias
|
|
|
|
),
|
|
|
|
$node->getLine()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-11-13 11:49:45 +01:00
|
|
|
$this->aliases[$aliasName] = $node->name;
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\Class_) {
|
2011-09-28 20:14:27 +02:00
|
|
|
if (null !== $node->extends) {
|
|
|
|
$node->extends = $this->resolveClassName($node->extends);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($node->implements as &$interface) {
|
|
|
|
$interface = $this->resolveClassName($interface);
|
|
|
|
}
|
2011-11-12 13:24:59 +01:00
|
|
|
|
|
|
|
$this->addNamespacedName($node);
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\Interface_) {
|
2011-09-28 20:14:27 +02:00
|
|
|
foreach ($node->extends as &$interface) {
|
|
|
|
$interface = $this->resolveClassName($interface);
|
|
|
|
}
|
2011-11-12 13:24:59 +01:00
|
|
|
|
2011-11-12 18:29:50 +01:00
|
|
|
$this->addNamespacedName($node);
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\Trait_) {
|
2011-11-12 13:24:59 +01:00
|
|
|
$this->addNamespacedName($node);
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\Function_) {
|
2011-11-12 13:24:59 +01:00
|
|
|
$this->addNamespacedName($node);
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\Const_) {
|
2011-11-12 13:24:59 +01:00
|
|
|
foreach ($node->consts as $const) {
|
|
|
|
$this->addNamespacedName($const);
|
|
|
|
}
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Expr\StaticCall
|
|
|
|
|| $node instanceof Expr\StaticPropertyFetch
|
|
|
|
|| $node instanceof Expr\ClassConstFetch
|
|
|
|
|| $node instanceof Expr\New_
|
|
|
|
|| $node instanceof Expr\Instanceof_
|
2011-09-28 20:14:27 +02:00
|
|
|
) {
|
2014-02-06 14:44:16 +01:00
|
|
|
if ($node->class instanceof Name) {
|
2011-11-06 17:16:40 +01:00
|
|
|
$node->class = $this->resolveClassName($node->class);
|
|
|
|
}
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\Catch_) {
|
2012-05-04 06:52:39 +02:00
|
|
|
$node->type = $this->resolveClassName($node->type);
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Expr\FuncCall
|
|
|
|
|| $node instanceof Expr\ConstFetch
|
2011-09-28 20:14:27 +02:00
|
|
|
) {
|
2014-02-06 14:44:16 +01:00
|
|
|
if ($node->name instanceof Name) {
|
2011-11-06 17:16:40 +01:00
|
|
|
$node->name = $this->resolveOtherName($node->name);
|
|
|
|
}
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Stmt\TraitUse) {
|
2011-12-10 12:11:53 +01:00
|
|
|
foreach ($node->traits as &$trait) {
|
|
|
|
$trait = $this->resolveClassName($trait);
|
|
|
|
}
|
2014-02-06 14:44:16 +01:00
|
|
|
} elseif ($node instanceof Node\Param
|
|
|
|
&& $node->type instanceof Name
|
2011-11-06 17:16:40 +01:00
|
|
|
) {
|
2011-09-28 20:14:27 +02:00
|
|
|
$node->type = $this->resolveClassName($node->type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-06 14:44:16 +01:00
|
|
|
protected function resolveClassName(Name $name) {
|
2011-09-28 20:14:27 +02:00
|
|
|
// don't resolve special class names
|
|
|
|
if (in_array((string) $name, array('self', 'parent', 'static'))) {
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fully qualified names are already resolved
|
|
|
|
if ($name->isFullyQualified()) {
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
// resolve aliases (for non-relative names)
|
2013-11-13 11:49:45 +01:00
|
|
|
$aliasName = strtolower($name->getFirst());
|
|
|
|
if (!$name->isRelative() && isset($this->aliases[$aliasName])) {
|
|
|
|
$name->setFirst($this->aliases[$aliasName]);
|
2011-09-28 20:14:27 +02:00
|
|
|
// if no alias exists prepend current namespace
|
|
|
|
} elseif (null !== $this->namespace) {
|
|
|
|
$name->prepend($this->namespace);
|
|
|
|
}
|
|
|
|
|
2014-02-06 14:44:16 +01:00
|
|
|
return new Name\FullyQualified($name->parts, $name->getAttributes());
|
2011-09-28 20:14:27 +02:00
|
|
|
}
|
|
|
|
|
2014-02-06 14:44:16 +01:00
|
|
|
protected function resolveOtherName(Name $name) {
|
2011-09-28 20:29:19 +02:00
|
|
|
// fully qualified names are already resolved and we can't do anything about unqualified
|
|
|
|
// ones at compiler-time
|
|
|
|
if ($name->isFullyQualified() || $name->isUnqualified()) {
|
2011-09-28 20:14:27 +02:00
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
// resolve aliases for qualified names
|
2013-11-13 11:49:45 +01:00
|
|
|
$aliasName = strtolower($name->getFirst());
|
|
|
|
if ($name->isQualified() && isset($this->aliases[$aliasName])) {
|
|
|
|
$name->setFirst($this->aliases[$aliasName]);
|
2011-09-28 20:29:19 +02:00
|
|
|
// prepend namespace for relative names
|
|
|
|
} elseif (null !== $this->namespace) {
|
|
|
|
$name->prepend($this->namespace);
|
2011-09-28 20:14:27 +02:00
|
|
|
}
|
|
|
|
|
2014-02-06 14:44:16 +01:00
|
|
|
return new Name\FullyQualified($name->parts, $name->getAttributes());
|
2011-09-28 20:14:27 +02:00
|
|
|
}
|
2011-11-12 13:24:59 +01:00
|
|
|
|
2014-02-06 14:44:16 +01:00
|
|
|
protected function addNamespacedName(Node $node) {
|
2011-11-12 13:24:59 +01:00
|
|
|
if (null !== $this->namespace) {
|
|
|
|
$node->namespacedName = clone $this->namespace;
|
|
|
|
$node->namespacedName->append($node->name);
|
|
|
|
} else {
|
2014-02-06 14:44:16 +01:00
|
|
|
$node->namespacedName = new Name($node->name, $node->getAttributes());
|
2011-11-12 13:24:59 +01:00
|
|
|
}
|
|
|
|
}
|
2013-11-13 11:49:45 +01:00
|
|
|
}
|