Файл: gapps/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php
Строк: 330
<?php
namespace PhpParserNodeVisitor;
use PhpParserNodeVisitorAbstract;
use PhpParserError;
use PhpParserNode;
use PhpParserNodeName;
use PhpParserNodeNameFullyQualified;
use PhpParserNodeExpr;
use PhpParserNodeStmt;
class NameResolver extends NodeVisitorAbstract
{
/** @var null|Name Current namespace */
protected $namespace;
/** @var array Map of format [aliasType => [aliasName => originalName]] */
protected $aliases;
public function beforeTraverse(array $nodes) {
$this->resetState();
}
public function enterNode(Node $node) {
if ($node instanceof StmtNamespace_) {
$this->resetState($node->name);
} elseif ($node instanceof StmtUse_) {
foreach ($node->uses as $use) {
$this->addAlias($use, $node->type, null);
}
} elseif ($node instanceof StmtGroupUse) {
foreach ($node->uses as $use) {
$this->addAlias($use, $node->type, $node->prefix);
}
} elseif ($node instanceof StmtClass_) {
if (null !== $node->extends) {
$node->extends = $this->resolveClassName($node->extends);
}
foreach ($node->implements as &$interface) {
$interface = $this->resolveClassName($interface);
}
if (null !== $node->name) {
$this->addNamespacedName($node);
}
} elseif ($node instanceof StmtInterface_) {
foreach ($node->extends as &$interface) {
$interface = $this->resolveClassName($interface);
}
$this->addNamespacedName($node);
} elseif ($node instanceof StmtTrait_) {
$this->addNamespacedName($node);
} elseif ($node instanceof StmtFunction_) {
$this->addNamespacedName($node);
$this->resolveSignature($node);
} elseif ($node instanceof StmtClassMethod
|| $node instanceof ExprClosure
) {
$this->resolveSignature($node);
} elseif ($node instanceof StmtConst_) {
foreach ($node->consts as $const) {
$this->addNamespacedName($const);
}
} elseif ($node instanceof ExprStaticCall
|| $node instanceof ExprStaticPropertyFetch
|| $node instanceof ExprClassConstFetch
|| $node instanceof ExprNew_
|| $node instanceof ExprInstanceof_
) {
if ($node->class instanceof Name) {
$node->class = $this->resolveClassName($node->class);
}
} elseif ($node instanceof StmtCatch_) {
$node->type = $this->resolveClassName($node->type);
} elseif ($node instanceof ExprFuncCall) {
if ($node->name instanceof Name) {
$node->name = $this->resolveOtherName($node->name, StmtUse_::TYPE_FUNCTION);
}
} elseif ($node instanceof ExprConstFetch) {
$node->name = $this->resolveOtherName($node->name, StmtUse_::TYPE_CONSTANT);
} elseif ($node instanceof StmtTraitUse) {
foreach ($node->traits as &$trait) {
$trait = $this->resolveClassName($trait);
}
foreach ($node->adaptations as $adaptation) {
if (null !== $adaptation->trait) {
$adaptation->trait = $this->resolveClassName($adaptation->trait);
}
if ($adaptation instanceof StmtTraitUseAdaptationPrecedence) {
foreach ($adaptation->insteadof as &$insteadof) {
$insteadof = $this->resolveClassName($insteadof);
}
}
}
}
}
protected function resetState(Name $namespace = null) {
$this->namespace = $namespace;
$this->aliases = array(
StmtUse_::TYPE_NORMAL => array(),
StmtUse_::TYPE_FUNCTION => array(),
StmtUse_::TYPE_CONSTANT => array(),
);
}
protected function addAlias(StmtUseUse $use, $type, Name $prefix = null) {
// Add prefix for group uses
$name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
// Type is determined either by individual element or whole use declaration
$type |= $use->type;
// Constant names are case sensitive, everything else case insensitive
if ($type === StmtUse_::TYPE_CONSTANT) {
$aliasName = $use->alias;
} else {
$aliasName = strtolower($use->alias);
}
if (isset($this->aliases[$type][$aliasName])) {
$typeStringMap = array(
StmtUse_::TYPE_NORMAL => '',
StmtUse_::TYPE_FUNCTION => 'function ',
StmtUse_::TYPE_CONSTANT => 'const ',
);
throw new Error(
sprintf(
'Cannot use %s%s as %s because the name is already in use',
$typeStringMap[$type], $name, $use->alias
),
$use->getLine()
);
}
$this->aliases[$type][$aliasName] = $name;
}
/** @param StmtFunction_|StmtClassMethod|ExprClosure $node */
private function resolveSignature($node) {
foreach ($node->params as $param) {
if ($param->type instanceof Name) {
$param->type = $this->resolveClassName($param->type);
}
}
if ($node->returnType instanceof Name) {
$node->returnType = $this->resolveClassName($node->returnType);
}
}
protected function resolveClassName(Name $name) {
// don't resolve special class names
if (in_array(strtolower($name->toString()), array('self', 'parent', 'static'))) {
if (!$name->isUnqualified()) {
throw new Error(
sprintf("'\%s' is an invalid class name", $name->toString()),
$name->getLine()
);
}
return $name;
}
// fully qualified names are already resolved
if ($name->isFullyQualified()) {
return $name;
}
$aliasName = strtolower($name->getFirst());
if (!$name->isRelative() && isset($this->aliases[StmtUse_::TYPE_NORMAL][$aliasName])) {
// resolve aliases (for non-relative names)
$alias = $this->aliases[StmtUse_::TYPE_NORMAL][$aliasName];
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
}
if (null !== $this->namespace) {
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
return new FullyQualified($name->parts, $name->getAttributes());
}
protected function resolveOtherName(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[StmtUse_::TYPE_NORMAL][$aliasName])) {
$alias = $this->aliases[StmtUse_::TYPE_NORMAL][$aliasName];
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
}
if ($name->isUnqualified()) {
if ($type === StmtUse_::TYPE_CONSTANT) {
// constant aliases are case-sensitive, function aliases case-insensitive
$aliasName = $name->getFirst();
}
if (!isset($this->aliases[$type][$aliasName])) {
// unqualified, unaliased names cannot be resolved at compile-time
return $name;
}
// resolve unqualified aliases
return new FullyQualified($this->aliases[$type][$aliasName], $name->getAttributes());
}
if (null !== $this->namespace) {
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
return new FullyQualified($name->parts, $name->getAttributes());
}
protected function addNamespacedName(Node $node) {
if (null !== $this->namespace) {
$node->namespacedName = Name::concat($this->namespace, $node->name);
} else {
$node->namespacedName = new Name($node->name);
}
}
}