⬆️ Upgrade lib : nikic/php-parser

We were on v3 that is no longer maintained and compatibility is annonced for PHP 7.2.
v4 is active and supports PHP up to 8.0
No problem to update as this is only used in the config editor (\Combodo\iTop\Config\Validator\iTopConfigAstValidator)
This commit is contained in:
Pierre Goiffon
2021-03-29 16:35:30 +02:00
parent c11fd4f0ab
commit a7e7e62245
279 changed files with 17983 additions and 13776 deletions

View File

@@ -0,0 +1,20 @@
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
/**
* Visitor cloning all nodes and linking to the original nodes using an attribute.
*
* This visitor is required to perform format-preserving pretty prints.
*/
class CloningVisitor extends NodeVisitorAbstract
{
public function enterNode(Node $origNode) {
$node = clone $origNode;
$node->setAttribute('origNode', $origNode);
return $node;
}
}

View File

@@ -0,0 +1,48 @@
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
/**
* This visitor can be used to find and collect all nodes satisfying some criterion determined by
* a filter callback.
*/
class FindingVisitor extends NodeVisitorAbstract
{
/** @var callable Filter callback */
protected $filterCallback;
/** @var Node[] Found nodes */
protected $foundNodes;
public function __construct(callable $filterCallback) {
$this->filterCallback = $filterCallback;
}
/**
* Get found nodes satisfying the filter callback.
*
* Nodes are returned in pre-order.
*
* @return Node[] Found nodes
*/
public function getFoundNodes() : array {
return $this->foundNodes;
}
public function beforeTraverse(array $nodes) {
$this->foundNodes = [];
return null;
}
public function enterNode(Node $node) {
$filterCallback = $this->filterCallback;
if ($filterCallback($node)) {
$this->foundNodes[] = $node;
}
return null;
}
}

View File

@@ -0,0 +1,50 @@
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser\Node;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
/**
* This visitor can be used to find the first node satisfying some criterion determined by
* a filter callback.
*/
class FirstFindingVisitor extends NodeVisitorAbstract
{
/** @var callable Filter callback */
protected $filterCallback;
/** @var null|Node Found node */
protected $foundNode;
public function __construct(callable $filterCallback) {
$this->filterCallback = $filterCallback;
}
/**
* Get found node satisfying the filter callback.
*
* Returns null if no node satisfies the filter callback.
*
* @return null|Node Found node (or null if not found)
*/
public function getFoundNode() {
return $this->foundNode;
}
public function beforeTraverse(array $nodes) {
$this->foundNode = null;
return null;
}
public function enterNode(Node $node) {
$filterCallback = $this->filterCallback;
if ($filterCallback($node)) {
$this->foundNode = $node;
return NodeTraverser::STOP_TRAVERSAL;
}
return null;
}
}

View File

@@ -1,9 +1,9 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser\Error;
use PhpParser\ErrorHandler;
use PhpParser\NameContext;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
@@ -13,39 +13,51 @@ use PhpParser\NodeVisitorAbstract;
class NameResolver extends NodeVisitorAbstract
{
/** @var null|Name Current namespace */
protected $namespace;
/** @var array Map of format [aliasType => [aliasName => originalName]] */
protected $aliases;
/** @var ErrorHandler Error handler */
protected $errorHandler;
/** @var NameContext Naming context */
protected $nameContext;
/** @var bool Whether to preserve original names */
protected $preserveOriginalNames;
/** @var bool Whether to replace resolved nodes in place, or to add resolvedNode attributes */
protected $replaceNodes;
/**
* Constructs a name resolution visitor.
*
* Options: If "preserveOriginalNames" is enabled, an "originalName" attribute will be added to
* all name nodes that underwent resolution.
* Options:
* * preserveOriginalNames (default false): An "originalName" attribute will be added to
* all name nodes that underwent resolution.
* * replaceNodes (default true): Resolved names are replaced in-place. Otherwise, a
* resolvedName attribute is added. (Names that cannot be statically resolved receive a
* namespacedName attribute, as usual.)
*
* @param ErrorHandler|null $errorHandler Error handler
* @param array $options Options
*/
public function __construct(ErrorHandler $errorHandler = null, array $options = []) {
$this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
$this->preserveOriginalNames = !empty($options['preserveOriginalNames']);
$this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing);
$this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;
$this->replaceNodes = $options['replaceNodes'] ?? true;
}
/**
* Get name resolution context.
*
* @return NameContext
*/
public function getNameContext() : NameContext {
return $this->nameContext;
}
public function beforeTraverse(array $nodes) {
$this->resetState();
$this->nameContext->startNamespace();
return null;
}
public function enterNode(Node $node) {
if ($node instanceof Stmt\Namespace_) {
$this->resetState($node->name);
$this->nameContext->startNamespace($node->name);
} elseif ($node instanceof Stmt\Use_) {
foreach ($node->uses as $use) {
$this->addAlias($use, $node->type, null);
@@ -63,6 +75,7 @@ class NameResolver extends NodeVisitorAbstract
$interface = $this->resolveClassName($interface);
}
$this->resolveAttrGroups($node);
if (null !== $node->name) {
$this->addNamespacedName($node);
}
@@ -71,20 +84,32 @@ class NameResolver extends NodeVisitorAbstract
$interface = $this->resolveClassName($interface);
}
$this->resolveAttrGroups($node);
$this->addNamespacedName($node);
} elseif ($node instanceof Stmt\Trait_) {
$this->resolveAttrGroups($node);
$this->addNamespacedName($node);
} elseif ($node instanceof Stmt\Function_) {
$this->addNamespacedName($node);
$this->resolveSignature($node);
$this->resolveAttrGroups($node);
$this->addNamespacedName($node);
} elseif ($node instanceof Stmt\ClassMethod
|| $node instanceof Expr\Closure
|| $node instanceof Expr\ArrowFunction
) {
$this->resolveSignature($node);
$this->resolveAttrGroups($node);
} elseif ($node instanceof Stmt\Property) {
if (null !== $node->type) {
$node->type = $this->resolveType($node->type);
}
$this->resolveAttrGroups($node);
} elseif ($node instanceof Stmt\Const_) {
foreach ($node->consts as $const) {
$this->addNamespacedName($const);
}
} else if ($node instanceof Stmt\ClassConst) {
$this->resolveAttrGroups($node);
} elseif ($node instanceof Expr\StaticCall
|| $node instanceof Expr\StaticPropertyFetch
|| $node instanceof Expr\ClassConstFetch
@@ -100,10 +125,10 @@ class NameResolver extends NodeVisitorAbstract
}
} elseif ($node instanceof Expr\FuncCall) {
if ($node->name instanceof Name) {
$node->name = $this->resolveOtherName($node->name, Stmt\Use_::TYPE_FUNCTION);
$node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION);
}
} elseif ($node instanceof Expr\ConstFetch) {
$node->name = $this->resolveOtherName($node->name, Stmt\Use_::TYPE_CONSTANT);
$node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT);
} elseif ($node instanceof Stmt\TraitUse) {
foreach ($node->traits as &$trait) {
$trait = $this->resolveClassName($trait);
@@ -121,70 +146,67 @@ class NameResolver extends NodeVisitorAbstract
}
}
}
return null;
}
protected function resetState(Name $namespace = null) {
$this->namespace = $namespace;
$this->aliases = array(
Stmt\Use_::TYPE_NORMAL => array(),
Stmt\Use_::TYPE_FUNCTION => array(),
Stmt\Use_::TYPE_CONSTANT => array(),
);
}
protected function addAlias(Stmt\UseUse $use, $type, Name $prefix = null) {
private function addAlias(Stmt\UseUse $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 === Stmt\Use_::TYPE_CONSTANT) {
$aliasName = $use->alias;
} else {
$aliasName = strtolower($use->alias);
}
if (isset($this->aliases[$type][$aliasName])) {
$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, $use->alias
),
$use->getAttributes()
));
return;
}
$this->aliases[$type][$aliasName] = $name;
$this->nameContext->addAlias(
$name, (string) $use->getAlias(), $type, $use->getAttributes()
);
}
/** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */
private function resolveSignature($node) {
foreach ($node->params as $param) {
$param->type = $this->resolveType($param->type);
$this->resolveAttrGroups($param);
}
$node->returnType = $this->resolveType($node->returnType);
}
private function resolveType($node) {
if ($node instanceof Name) {
return $this->resolveClassName($node);
}
if ($node instanceof Node\NullableType) {
$node->type = $this->resolveType($node->type);
return $node;
}
if ($node instanceof Name) {
return $this->resolveClassName($node);
if ($node instanceof Node\UnionType) {
foreach ($node->types as &$type) {
$type = $this->resolveType($type);
}
return $node;
}
return $node;
}
protected function resolveClassName(Name $name) {
/**
* Resolve name, according to name resolver options.
*
* @param Name $name Function or constant name to resolve
* @param int $type One of Stmt\Use_::TYPE_*
*
* @return Name Resolved name, or original name with attribute
*/
protected function resolveName(Name $name, int $type) : Name {
if (!$this->replaceNodes) {
$resolvedName = $this->nameContext->getResolvedName($name, $type);
if (null !== $resolvedName) {
$name->setAttribute('resolvedName', $resolvedName);
} else {
$name->setAttribute('namespacedName', FullyQualified::concat(
$this->nameContext->getNamespace(), $name, $name->getAttributes()));
}
return $name;
}
if ($this->preserveOriginalNames) {
// Save the original name
$originalName = $name;
@@ -192,81 +214,33 @@ class NameResolver extends NodeVisitorAbstract
$name->setAttribute('originalName', $originalName);
}
// 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;
$resolvedName = $this->nameContext->getResolvedName($name, $type);
if (null !== $resolvedName) {
return $resolvedName;
}
// 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());
// 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->nameContext->getNamespace(), $name, $name->getAttributes()));
return $name;
}
protected function resolveOtherName(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
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());
}
// 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;
}
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
protected function resolveClassName(Name $name) {
return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL);
}
protected function addNamespacedName(Node $node) {
$node->namespacedName = Name::concat($this->namespace, $node->name);
$node->namespacedName = Name::concat(
$this->nameContext->getNamespace(), (string) $node->name);
}
protected function resolveAttrGroups(Node $node)
{
foreach ($node->attrGroups as $attrGroup) {
foreach ($attrGroup->attrs as $attr) {
$attr->name = $this->resolveClassName($attr->name);
}
}
}
}

View File

@@ -0,0 +1,52 @@
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
/**
* Visitor that connects a child node to its parent node
* as well as its sibling nodes.
*
* On the child node, the parent node can be accessed through
* <code>$node->getAttribute('parent')</code>, the previous
* node can be accessed through <code>$node->getAttribute('previous')</code>,
* and the next node can be accessed through <code>$node->getAttribute('next')</code>.
*/
final class NodeConnectingVisitor extends NodeVisitorAbstract
{
/**
* @var Node[]
*/
private $stack = [];
/**
* @var ?Node
*/
private $previous;
public function beforeTraverse(array $nodes) {
$this->stack = [];
$this->previous = null;
}
public function enterNode(Node $node) {
if (!empty($this->stack)) {
$node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
}
if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) {
$node->setAttribute('previous', $this->previous);
$this->previous->setAttribute('next', $node);
}
$this->stack[] = $node;
}
public function leaveNode(Node $node) {
$this->previous = $node;
array_pop($this->stack);
}
}

View File

@@ -0,0 +1,41 @@
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use function array_pop;
use function count;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
/**
* Visitor that connects a child node to its parent node.
*
* On the child node, the parent node can be accessed through
* <code>$node->getAttribute('parent')</code>.
*/
final class ParentConnectingVisitor extends NodeVisitorAbstract
{
/**
* @var Node[]
*/
private $stack = [];
public function beforeTraverse(array $nodes)
{
$this->stack = [];
}
public function enterNode(Node $node)
{
if (!empty($this->stack)) {
$node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
}
$this->stack[] = $node;
}
public function leaveNode(Node $node)
{
array_pop($this->stack);
}
}