mirror of
https://github.com/danog/PHP-Parser.git
synced 2025-01-22 22:01:18 +01:00
168 lines
5.5 KiB
PHP
168 lines
5.5 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace PhpParser;
|
||
|
|
||
|
use PhpParser\Node\Name;
|
||
|
use PhpParser\Node\Name\FullyQualified;
|
||
|
use PhpParser\Node\Stmt;
|
||
|
|
||
|
class NameContext {
|
||
|
/** @var null|Name Current namespace */
|
||
|
protected $namespace;
|
||
|
|
||
|
/** @var array Map of format [aliasType => [aliasName => originalName]] */
|
||
|
protected $aliases = [];
|
||
|
|
||
|
/** @var ErrorHandler Error handler */
|
||
|
protected $errorHandler;
|
||
|
|
||
|
/**
|
||
|
* Create a name context.
|
||
|
*
|
||
|
* @param ErrorHandler $errorHandler Error handling used to report errors
|
||
|
*/
|
||
|
public function __construct(ErrorHandler $errorHandler) {
|
||
|
$this->errorHandler = $errorHandler;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Start a new namespace.
|
||
|
*
|
||
|
* This also resets the alias table.
|
||
|
*
|
||
|
* @param Name|null $namespace Null is the global namespace
|
||
|
*/
|
||
|
public function startNamespace(Name $namespace = null) {
|
||
|
$this->namespace = $namespace;
|
||
|
$this->aliases = [
|
||
|
Stmt\Use_::TYPE_NORMAL => [],
|
||
|
Stmt\Use_::TYPE_FUNCTION => [],
|
||
|
Stmt\Use_::TYPE_CONSTANT => [],
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add an alias / import.
|
||
|
*
|
||
|
* @param Name $name Original name
|
||
|
* @param string $aliasName Aliased name
|
||
|
* @param int $type One of Stmt\Use_::TYPE_*
|
||
|
* @param array $errorAttrs Attributes to use to report an error
|
||
|
*/
|
||
|
public function addAlias(Name $name, $aliasName, $type, array $errorAttrs = []) {
|
||
|
// Constant names are case sensitive, everything else case insensitive
|
||
|
if ($type === Stmt\Use_::TYPE_CONSTANT) {
|
||
|
$aliasLookupName = $aliasName;
|
||
|
} else {
|
||
|
$aliasLookupName = strtolower($aliasName);
|
||
|
}
|
||
|
|
||
|
if (isset($this->aliases[$type][$aliasLookupName])) {
|
||
|
$typeStringMap = array(
|
||
|
Stmt\Use_::TYPE_NORMAL => '',
|
||
|
Stmt\Use_::TYPE_FUNCTION => 'function ',
|
||
|
Stmt\Use_::TYPE_CONSTANT => 'const ',
|
||
|
);
|
||
|
|
||
|
$this->errorHandler->handleError(new Error(
|
||
|
sprintf(
|
||
|
'Cannot use %s%s as %s because the name is already in use',
|
||
|
$typeStringMap[$type], $name, $aliasName
|
||
|
),
|
||
|
$errorAttrs
|
||
|
));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$this->aliases[$type][$aliasLookupName] = $name;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get current namespace.
|
||
|
*
|
||
|
* @return null|Name Namespace (or null if global namespace)
|
||
|
*/
|
||
|
public function getNamespace() {
|
||
|
return $this->namespace;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get resolved class name.
|
||
|
*
|
||
|
* @param Name $name Class ame to resolve
|
||
|
*
|
||
|
* @return Name Resolved name
|
||
|
*/
|
||
|
public function getResolvedClassName(Name $name) {
|
||
|
// don't resolve special class names
|
||
|
if (in_array(strtolower($name->toString()), array('self', 'parent', 'static'))) {
|
||
|
if (!$name->isUnqualified()) {
|
||
|
$this->errorHandler->handleError(new Error(
|
||
|
sprintf("'\\%s' is an invalid class name", $name->toString()),
|
||
|
$name->getAttributes()
|
||
|
));
|
||
|
}
|
||
|
return $name;
|
||
|
}
|
||
|
|
||
|
// fully qualified names are already resolved
|
||
|
if ($name->isFullyQualified()) {
|
||
|
return $name;
|
||
|
}
|
||
|
|
||
|
$aliasName = strtolower($name->getFirst());
|
||
|
if (!$name->isRelative() && isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName])) {
|
||
|
// resolve aliases (for non-relative names)
|
||
|
$alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName];
|
||
|
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
|
||
|
}
|
||
|
|
||
|
// if no alias exists prepend current namespace
|
||
|
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get resolved function or constant name.
|
||
|
*
|
||
|
* @param Name $name Function or constant name to resolve
|
||
|
* @param int $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT}
|
||
|
*
|
||
|
* @return null|Name Resolved name, or null if static resolution is not possible
|
||
|
*/
|
||
|
public function getResolvedOtherName(Name $name, $type) {
|
||
|
// fully qualified names are already resolved
|
||
|
if ($name->isFullyQualified()) {
|
||
|
return $name;
|
||
|
}
|
||
|
|
||
|
// resolve aliases for qualified names
|
||
|
$aliasName = strtolower($name->getFirst());
|
||
|
if ($name->isQualified() && isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName])) {
|
||
|
$alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName];
|
||
|
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
|
||
|
}
|
||
|
|
||
|
if ($name->isUnqualified()) {
|
||
|
if ($type === Stmt\Use_::TYPE_CONSTANT) {
|
||
|
// constant aliases are case-sensitive, function aliases case-insensitive
|
||
|
$aliasName = $name->getFirst();
|
||
|
}
|
||
|
|
||
|
if (isset($this->aliases[$type][$aliasName])) {
|
||
|
// resolve unqualified aliases
|
||
|
return new FullyQualified($this->aliases[$type][$aliasName], $name->getAttributes());
|
||
|
}
|
||
|
|
||
|
if (null === $this->namespace) {
|
||
|
// outside of a namespace unaliased unqualified is same as fully qualified
|
||
|
return new FullyQualified($name, $name->getAttributes());
|
||
|
}
|
||
|
|
||
|
// Cannot resolve statically
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// if no alias exists prepend current namespace
|
||
|
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
||
|
}
|
||
|
}
|