mirror of
https://github.com/danog/PHP-Parser.git
synced 2024-11-26 20:04:48 +01:00
Switch NameResolver resolve methods to be immutable
To make it theoretically possible to expose this as API. Add slice() method to Name to allow this. Deprecate existing mutable Name APIs.
This commit is contained in:
parent
5bd8cb84de
commit
0265c28e6e
@ -106,6 +106,8 @@ class Name extends NodeAbstract
|
||||
/**
|
||||
* Sets the whole name.
|
||||
*
|
||||
* @deprecated Create a new Name instead, or manually modify the $parts property
|
||||
*
|
||||
* @param string|array|self $name The name to set the whole name to
|
||||
*/
|
||||
public function set($name) {
|
||||
@ -115,6 +117,8 @@ class Name extends NodeAbstract
|
||||
/**
|
||||
* Prepends a name to this name.
|
||||
*
|
||||
* @deprecated Use Name::concat($name1, $name2) instead
|
||||
*
|
||||
* @param string|array|self $name Name to prepend
|
||||
*/
|
||||
public function prepend($name) {
|
||||
@ -124,6 +128,8 @@ class Name extends NodeAbstract
|
||||
/**
|
||||
* Appends a name to this name.
|
||||
*
|
||||
* @deprecated Use Name::concat($name1, $name2) instead
|
||||
*
|
||||
* @param string|array|self $name Name to append
|
||||
*/
|
||||
public function append($name) {
|
||||
@ -133,6 +139,8 @@ class Name extends NodeAbstract
|
||||
/**
|
||||
* Sets the first part of the name.
|
||||
*
|
||||
* @deprecated Use concat($first, $name->slice(1)) instead
|
||||
*
|
||||
* @param string|array|self $name The name to set the first part to
|
||||
*/
|
||||
public function setFirst($name) {
|
||||
@ -149,14 +157,43 @@ class Name extends NodeAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two names, yielding a new Name instance
|
||||
* Gets a slice of a name (similar to array_slice).
|
||||
*
|
||||
* @param string|array|self The first name
|
||||
* @param string|array|self The second name
|
||||
* @return Name Concatenated name
|
||||
* This method returns a new instance of the same type as the original and with the same
|
||||
* attributes.
|
||||
*
|
||||
* If the slice is empty, a Name with an empty parts array is returned. While this is
|
||||
* meaningless in itself, it works correctly in conjunction with concat().
|
||||
*
|
||||
* @param int $offset Offset to start the slice at
|
||||
*
|
||||
* @return static Sliced name
|
||||
*/
|
||||
public static function concat($name1, $name2) {
|
||||
return new Name(array_merge(self::prepareName($name1), self::prepareName($name2)));
|
||||
public function slice($offset) {
|
||||
// TODO negative offset and length
|
||||
if ($offset < 0 || $offset > count($this->parts)) {
|
||||
throw new \OutOfBoundsException(sprintf('Offset %d is out of bounds', $offset));
|
||||
}
|
||||
|
||||
return new static(array_slice($this->parts, $offset), $this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two names, yielding a new Name instance.
|
||||
*
|
||||
* The type of the generated instance depends on which class this method is called on, for
|
||||
* example Name\FullyQualified::concat() will yield a Name\FullyQualified instance.
|
||||
*
|
||||
* @param string|array|self $name1 The first name
|
||||
* @param string|array|self $name2 The second name
|
||||
* @param array $attributes Attributes to assign to concatenated name
|
||||
*
|
||||
* @return static Concatenated name
|
||||
*/
|
||||
public static function concat($name1, $name2, array $attributes = []) {
|
||||
return new static(
|
||||
array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@ use PhpParser\NodeVisitorAbstract;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Stmt;
|
||||
|
||||
@ -174,13 +175,16 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$aliasName = strtolower($name->getFirst());
|
||||
if (!$name->isRelative() && isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName])) {
|
||||
// resolve aliases (for non-relative names)
|
||||
$name->setFirst($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName]);
|
||||
} elseif (null !== $this->namespace) {
|
||||
// if no alias exists prepend current namespace
|
||||
$name->prepend($this->namespace);
|
||||
$alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName];
|
||||
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
|
||||
}
|
||||
|
||||
return new Name\FullyQualified($name->parts, $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) {
|
||||
@ -192,34 +196,38 @@ class NameResolver extends NodeVisitorAbstract
|
||||
// resolve aliases for qualified names
|
||||
$aliasName = strtolower($name->getFirst());
|
||||
if ($name->isQualified() && isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName])) {
|
||||
$name->setFirst($this->aliases[Stmt\Use_::TYPE_NORMAL][$aliasName]);
|
||||
} elseif ($name->isUnqualified()) {
|
||||
$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
|
||||
$name->set($this->aliases[$type][$aliasName]);
|
||||
} else {
|
||||
if (!isset($this->aliases[$type][$aliasName])) {
|
||||
// unqualified, unaliased names cannot be resolved at compile-time
|
||||
return $name;
|
||||
}
|
||||
} elseif (null !== $this->namespace) {
|
||||
// if no alias exists prepend current namespace
|
||||
$name->prepend($this->namespace);
|
||||
|
||||
// resolve unqualified aliases
|
||||
return new FullyQualified($this->aliases[$type][$aliasName], $name->getAttributes());
|
||||
}
|
||||
|
||||
return new Name\FullyQualified($name->parts, $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 = clone $this->namespace;
|
||||
$node->namespacedName->append($node->name);
|
||||
$node->namespacedName = Name::concat($this->namespace, $node->name);
|
||||
} else {
|
||||
$node->namespacedName = new Name($node->name, $node->getAttributes());
|
||||
$node->namespacedName = new Name($node->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,38 @@ class NameTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame('foo\bar\bar\foo', $name->toString());
|
||||
}
|
||||
|
||||
public function testSlice() {
|
||||
$name = new Name('foo\bar');
|
||||
$this->assertEquals(new Name('foo\bar'), $name->slice(0));
|
||||
$this->assertEquals(new Name('bar'), $name->slice(1));
|
||||
$this->assertEquals(new Name([]), $name->slice(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OutOfBoundsException
|
||||
* @expectedExceptionMessage Offset 4 is out of bounds
|
||||
*/
|
||||
public function testSliceException() {
|
||||
(new Name('foo\bar\baz'))->slice(4);
|
||||
}
|
||||
|
||||
public function testConcat() {
|
||||
$this->assertEquals(new Name('foo\bar\baz'), Name::concat('foo', 'bar\baz'));
|
||||
$this->assertEquals(
|
||||
new Name\FullyQualified('foo\bar'),
|
||||
Name\FullyQualified::concat(['foo'], new Name('bar'))
|
||||
);
|
||||
|
||||
$attributes = ['foo' => 'bar'];
|
||||
$this->assertEquals(
|
||||
new Name\Relative('foo\bar\baz', $attributes),
|
||||
Name\Relative::concat(new Name\FullyQualified('foo\bar'), 'baz', $attributes)
|
||||
);
|
||||
|
||||
$this->assertEquals(new Name('foo'), Name::concat([], 'foo'));
|
||||
$this->assertEquals(new Name([]), Name::concat([], []));
|
||||
}
|
||||
|
||||
public function testIs() {
|
||||
$name = new Name('foo');
|
||||
$this->assertTrue ($name->isUnqualified());
|
||||
|
Loading…
Reference in New Issue
Block a user