mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-11-30 04:29:15 +01:00
Add partial group use support
Supported via Stmt\GroupUse which has Name $prefix in addition to the usual. Still missing: Mixed group uses.
This commit is contained in:
parent
583b560f71
commit
9620f79cdc
@ -150,11 +150,24 @@ top_statement:
|
||||
| T_NAMESPACE namespace_name '{' top_statement_list '}' { $$ = Stmt\Namespace_[$2, $4]; }
|
||||
| T_NAMESPACE '{' top_statement_list '}' { $$ = Stmt\Namespace_[null, $3]; }
|
||||
| T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
||||
| T_USE T_FUNCTION use_declarations ';' { $$ = Stmt\Use_[$3, Stmt\Use_::TYPE_FUNCTION]; }
|
||||
| T_USE T_CONST use_declarations ';' { $$ = Stmt\Use_[$3, Stmt\Use_::TYPE_CONSTANT]; }
|
||||
| T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; }
|
||||
| group_use_declaration { $$ = $1; }
|
||||
| T_CONST constant_declaration_list ';' { $$ = Stmt\Const_[$2]; }
|
||||
;
|
||||
|
||||
use_type:
|
||||
T_FUNCTION { $$ = Stmt\Use_::TYPE_FUNCTION; }
|
||||
| T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; }
|
||||
;
|
||||
|
||||
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
|
||||
group_use_declaration:
|
||||
T_USE namespace_name_parts T_NS_SEPARATOR '{' use_declarations '}'
|
||||
{ $$ = Stmt\GroupUse[Name[$2], $5, Stmt\Use_::TYPE_NORMAL]; }
|
||||
| T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' use_declarations '}'
|
||||
{ $$ = Stmt\GroupUse[Name[$3], $6, $2]; }
|
||||
;
|
||||
|
||||
use_declarations:
|
||||
use_declarations ',' use_declaration { push($1, $3); }
|
||||
| use_declaration { init($1); }
|
||||
|
@ -109,7 +109,7 @@ class Name extends NodeAbstract
|
||||
* @param string|array|self $name The name to set the whole name to
|
||||
*/
|
||||
public function set($name) {
|
||||
$this->parts = $this->prepareName($name);
|
||||
$this->parts = self::prepareName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +118,7 @@ class Name extends NodeAbstract
|
||||
* @param string|array|self $name Name to prepend
|
||||
*/
|
||||
public function prepend($name) {
|
||||
$this->parts = array_merge($this->prepareName($name), $this->parts);
|
||||
$this->parts = array_merge(self::prepareName($name), $this->parts);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,7 +127,7 @@ class Name extends NodeAbstract
|
||||
* @param string|array|self $name Name to append
|
||||
*/
|
||||
public function append($name) {
|
||||
$this->parts = array_merge($this->parts, $this->prepareName($name));
|
||||
$this->parts = array_merge($this->parts, self::prepareName($name));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,7 +136,7 @@ class Name extends NodeAbstract
|
||||
* @param string|array|self $name The name to set the first part to
|
||||
*/
|
||||
public function setFirst($name) {
|
||||
array_splice($this->parts, 0, 1, $this->prepareName($name));
|
||||
array_splice($this->parts, 0, 1, self::prepareName($name));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +145,18 @@ class Name extends NodeAbstract
|
||||
* @param string|array|self $name The name to set the last part to
|
||||
*/
|
||||
public function setLast($name) {
|
||||
array_splice($this->parts, -1, 1, $this->prepareName($name));
|
||||
array_splice($this->parts, -1, 1, self::prepareName($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two names, yielding a new Name instance
|
||||
*
|
||||
* @param string|array|self The first name
|
||||
* @param string|array|self The second name
|
||||
* @return Name Concatenated name
|
||||
*/
|
||||
public static function concat($name1, $name2) {
|
||||
return new Name(array_merge(self::prepareName($name1), self::prepareName($name2)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,7 +167,7 @@ class Name extends NodeAbstract
|
||||
*
|
||||
* @return array Prepared name
|
||||
*/
|
||||
protected function prepareName($name) {
|
||||
private static function prepareName($name) {
|
||||
if (is_string($name)) {
|
||||
return explode('\\', $name);
|
||||
} elseif (is_array($name)) {
|
||||
|
35
lib/PhpParser/Node/Stmt/GroupUse.php
Normal file
35
lib/PhpParser/Node/Stmt/GroupUse.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace PhpParser\Node\Stmt;
|
||||
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Name;
|
||||
|
||||
class GroupUse extends Stmt
|
||||
{
|
||||
/** @var int Type of group use */
|
||||
public $type;
|
||||
/** @var Name Prefix for uses */
|
||||
public $prefix;
|
||||
/** @var UseUse[] Uses */
|
||||
public $uses;
|
||||
|
||||
/**
|
||||
* Constructs a group use node.
|
||||
*
|
||||
* @param Name $prefix Prefix for uses
|
||||
* @param UseUse[] $uses Uses
|
||||
* @param int $type Type of group use
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Name $prefix, array $uses, $type = Use_::TYPE_NORMAL, array $attributes = array()) {
|
||||
parent::__construct($attributes);
|
||||
$this->type = $type;
|
||||
$this->prefix = $prefix;
|
||||
$this->uses = $uses;
|
||||
}
|
||||
|
||||
public function getSubNodeNames() {
|
||||
return array('type', 'prefix', 'uses');
|
||||
}
|
||||
}
|
@ -26,7 +26,11 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$this->resetState($node->name);
|
||||
} elseif ($node instanceof Stmt\Use_) {
|
||||
foreach ($node->uses as $use) {
|
||||
$this->addAlias($use, $node->type);
|
||||
$this->addAlias($use, $node->type, null);
|
||||
}
|
||||
} elseif ($node instanceof Stmt\GroupUse) {
|
||||
foreach ($node->uses as $use) {
|
||||
$this->addAlias($use, $node->type, $node->prefix);
|
||||
}
|
||||
} elseif ($node instanceof Stmt\Class_) {
|
||||
if (null !== $node->extends) {
|
||||
@ -105,7 +109,7 @@ class NameResolver extends NodeVisitorAbstract
|
||||
);
|
||||
}
|
||||
|
||||
protected function addAlias(Stmt\UseUse $use, $type) {
|
||||
protected function addAlias(Stmt\UseUse $use, $type, Name $prefix = null) {
|
||||
// Constant names are case sensitive, everything else case insensitive
|
||||
if ($type === Stmt\Use_::TYPE_CONSTANT) {
|
||||
$aliasName = $use->alias;
|
||||
@ -113,6 +117,9 @@ class NameResolver extends NodeVisitorAbstract
|
||||
$aliasName = strtolower($use->alias);
|
||||
}
|
||||
|
||||
// Add prefix for group uses
|
||||
$name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
|
||||
|
||||
if (isset($this->aliases[$type][$aliasName])) {
|
||||
$typeStringMap = array(
|
||||
Stmt\Use_::TYPE_NORMAL => '',
|
||||
@ -123,13 +130,13 @@ class NameResolver extends NodeVisitorAbstract
|
||||
throw new Error(
|
||||
sprintf(
|
||||
'Cannot use %s%s as %s because the name is already in use',
|
||||
$typeStringMap[$type], $use->name, $use->alias
|
||||
$typeStringMap[$type], $name, $use->alias
|
||||
),
|
||||
$use->getLine()
|
||||
);
|
||||
}
|
||||
|
||||
$this->aliases[$type][$aliasName] = $use->name;
|
||||
$this->aliases[$type][$aliasName] = $name;
|
||||
}
|
||||
|
||||
/** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -516,17 +516,25 @@ class Standard extends PrettyPrinterAbstract
|
||||
}
|
||||
|
||||
public function pStmt_Use(Stmt\Use_ $node) {
|
||||
return 'use '
|
||||
. ($node->type === Stmt\Use_::TYPE_FUNCTION ? 'function ' : '')
|
||||
. ($node->type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : '')
|
||||
return 'use ' . $this->pUseType($node->type)
|
||||
. $this->pCommaSeparated($node->uses) . ';';
|
||||
}
|
||||
|
||||
public function pStmt_GroupUse(Stmt\GroupUse $node) {
|
||||
return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix)
|
||||
. '\{' . $this->pCommaSeparated($node->uses) . '};';
|
||||
}
|
||||
|
||||
public function pStmt_UseUse(Stmt\UseUse $node) {
|
||||
return $this->p($node->name)
|
||||
. ($node->name->getLast() !== $node->alias ? ' as ' . $node->alias : '');
|
||||
}
|
||||
|
||||
private function pUseType($type) {
|
||||
return ($type === Stmt\Use_::TYPE_FUNCTION ? 'function ' : '')
|
||||
. ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : '');
|
||||
}
|
||||
|
||||
public function pStmt_Interface(Stmt\Interface_ $node) {
|
||||
return 'interface ' . $node->name
|
||||
. (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')
|
||||
|
@ -76,6 +76,20 @@ namespace Bar {
|
||||
BAR\FOO;
|
||||
BAZ\FOO;
|
||||
}
|
||||
namespace Baz {
|
||||
use A\T\{B\C, D\E};
|
||||
use function X\T\{b\c, d\e};
|
||||
use const Y\T\{B\C, D\E};
|
||||
|
||||
new C;
|
||||
new E;
|
||||
new C\D;
|
||||
new E\F;
|
||||
c();
|
||||
e();
|
||||
C;
|
||||
E;
|
||||
}
|
||||
EOC;
|
||||
$expectedCode = <<<'EOC'
|
||||
namespace Foo {
|
||||
@ -127,6 +141,19 @@ namespace Bar {
|
||||
\foo\FOO;
|
||||
\Bar\BAZ\FOO;
|
||||
}
|
||||
namespace Baz {
|
||||
use A\T\{B\C, D\E};
|
||||
use function X\T\{b\c, d\e};
|
||||
use const Y\T\{B\C, D\E};
|
||||
new \A\T\B\C();
|
||||
new \A\T\D\E();
|
||||
new \A\T\B\C\D();
|
||||
new \A\T\D\E\F();
|
||||
\X\T\b\c();
|
||||
\X\T\d\e();
|
||||
\Y\T\B\C;
|
||||
\Y\T\D\E;
|
||||
}
|
||||
EOC;
|
||||
|
||||
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
|
||||
|
138
test/code/parser/stmt/namespace/groupUse.test
Normal file
138
test/code/parser/stmt/namespace/groupUse.test
Normal file
@ -0,0 +1,138 @@
|
||||
Group use declarations
|
||||
-----
|
||||
<?php
|
||||
use A\{B};
|
||||
use A\{B\C, D};
|
||||
use A\B\{C\D, E};
|
||||
use function A\{b\c, d};
|
||||
use const A\{B\C, D};
|
||||
-----
|
||||
array(
|
||||
0: Stmt_GroupUse(
|
||||
type: 1
|
||||
prefix: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
0: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: B
|
||||
)
|
||||
)
|
||||
alias: B
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_GroupUse(
|
||||
type: 1
|
||||
prefix: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
0: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: B
|
||||
1: C
|
||||
)
|
||||
)
|
||||
alias: C
|
||||
)
|
||||
1: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: D
|
||||
)
|
||||
)
|
||||
alias: D
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_GroupUse(
|
||||
type: 1
|
||||
prefix: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
1: B
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
0: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: C
|
||||
1: D
|
||||
)
|
||||
)
|
||||
alias: D
|
||||
)
|
||||
1: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: E
|
||||
)
|
||||
)
|
||||
alias: E
|
||||
)
|
||||
)
|
||||
)
|
||||
3: Stmt_GroupUse(
|
||||
type: 2
|
||||
prefix: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
0: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: b
|
||||
1: c
|
||||
)
|
||||
)
|
||||
alias: c
|
||||
)
|
||||
1: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: d
|
||||
)
|
||||
)
|
||||
alias: d
|
||||
)
|
||||
)
|
||||
)
|
||||
4: Stmt_GroupUse(
|
||||
type: 3
|
||||
prefix: Name(
|
||||
parts: array(
|
||||
0: A
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
0: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: B
|
||||
1: C
|
||||
)
|
||||
)
|
||||
alias: C
|
||||
)
|
||||
1: Stmt_UseUse(
|
||||
name: Name(
|
||||
parts: array(
|
||||
0: D
|
||||
)
|
||||
)
|
||||
alias: D
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
14
test/code/prettyPrinter/groupUse.test
Normal file
14
test/code/prettyPrinter/groupUse.test
Normal file
@ -0,0 +1,14 @@
|
||||
Group use declaration
|
||||
-----
|
||||
<?php
|
||||
use A\{B};
|
||||
use A\{B\C, D};
|
||||
use A\B\{C\D, E};
|
||||
use function A\{b\c, d};
|
||||
use const A\{B\C, D};
|
||||
-----
|
||||
use A\{B};
|
||||
use A\{B\C, D};
|
||||
use A\B\{C\D, E};
|
||||
use function A\{b\c, d};
|
||||
use const A\{B\C, D};
|
Loading…
Reference in New Issue
Block a user