Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Initial version of grouped use declarations
  • Loading branch information
Manuel Pichler committed Jan 4, 2017
1 parent b5d708e commit fd4aaca
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/main/php/PDepend/Source/AST/ASTArtifact.php
Expand Up @@ -50,7 +50,7 @@
* @copyright 2008-2015 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface ASTArtifact //extends ASTNode
interface ASTArtifact /* extends ASTNode */
{
/**
* Returns the artifact name.
Expand Down
61 changes: 46 additions & 15 deletions src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php
Expand Up @@ -155,7 +155,7 @@ abstract class AbstractPHPParser
*
* @var boolean
*/
private $namespacePrefixReplaced = false;
protected $namespacePrefixReplaced = false;

/**
* The name of the last detected namespace.
Expand Down Expand Up @@ -197,7 +197,7 @@ abstract class AbstractPHPParser
*
* @var \PDepend\Source\Parser\SymbolTable
*/
private $useSymbolTable;
protected $useSymbolTable;

/**
* The last parsed doc comment or <b>null</b>.
Expand Down Expand Up @@ -5851,7 +5851,7 @@ protected function parseQualifiedName()
* @return array(string)
* @since 0.9.5
*/
private function parseQualifiedNameRaw()
protected function parseQualifiedNameRaw()
{
// Reset namespace prefix flag
$this->namespacePrefixReplaced = false;
Expand Down Expand Up @@ -5891,7 +5891,10 @@ private function parseQualifiedNameRaw()

// Append to qualified name
$qualifiedName[] = '\\';
$qualifiedName[] = $this->parseClassName();

if ($nextElement = $this->parseQualifiedNameElement($qualifiedName)) {
$qualifiedName[] = $nextElement;
}

$this->consumeComments();

Expand All @@ -5902,6 +5905,15 @@ private function parseQualifiedNameRaw()
return $qualifiedName;
}

/**
* @param array $previousElements
* @return string
*/
protected function parseQualifiedNameElement(array $previousElements)
{
return $this->parseClassName();
}

/**
* This method parses a PHP 5.3 namespace declaration.
*
Expand Down Expand Up @@ -6003,27 +6015,46 @@ protected function parseUseDeclaration()
array_unshift($fragments, '\\');
}

if ($this->tokenizer->peek() === Tokens::T_AS) {
$this->consumeToken(Tokens::T_AS);
$this->consumeComments();
$this->parseUseDeclarationForVersion($fragments);

$image = $this->consumeToken(Tokens::T_STRING)->image;
// Check for a following use declaration
if ($this->tokenizer->peek() === Tokens::T_COMMA) {
// Consume comma token and comments
$this->consumeToken(Tokens::T_COMMA);
$this->consumeComments();
} else {
$image = end($fragments);

$this->parseUseDeclaration();
}
}

/**
* @param array $fragments
* @return void
*/
protected function parseUseDeclarationForVersion(array $fragments)
{
$image = $this->parseNamespaceImage($fragments);

// Add mapping between image and qualified name to symbol table
$this->useSymbolTable->add($image, join('', $fragments));
}

// Check for a following use declaration
if ($this->tokenizer->peek() === Tokens::T_COMMA) {
// Consume comma token and comments
$this->consumeToken(Tokens::T_COMMA);
/**
* @param array $fragments
* @return string
*/
protected function parseNamespaceImage(array $fragments)
{
if ($this->tokenizer->peek() === Tokens::T_AS) {
$this->consumeToken(Tokens::T_AS);
$this->consumeComments();

$this->parseUseDeclaration();
$image = $this->consumeToken(Tokens::T_STRING)->image;
$this->consumeComments();
} else {
$image = end($fragments);
}
return $image;
}

/**
Expand Down
Expand Up @@ -225,7 +225,6 @@ protected function parseStaticValueVersionSpecific(ASTValue $value)
if ($count == 0) {
return null;
} elseif ($count == 1) {

// @todo ASTValue must be a valid node.
$value->setValue($expressions[0]);

Expand Down
63 changes: 63 additions & 0 deletions src/main/php/PDepend/Source/Language/PHP/PHPParserVersion70.php
Expand Up @@ -340,4 +340,67 @@ protected function parseFormalParameter()

return $parameter;
}

/**
* @param array $fragments
* @return void
*/
protected function parseUseDeclarationForVersion(array $fragments)
{
if (Tokens::T_CURLY_BRACE_OPEN === $this->tokenizer->peek()) {
return $this->parseUseDeclarationVersion70($fragments);
}
return parent::parseUseDeclarationForVersion($fragments);
}

/**
* @param array $fragments
* @return void
*/
protected function parseUseDeclarationVersion70(array $fragments)
{
$namespacePrefixReplaced = $this->namespacePrefixReplaced;

$this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);
$this->consumeComments();

do {
$subFragments = $this->parseQualifiedNameRaw();
$this->consumeComments();

$image = $this->parseNamespaceImage($subFragments);

if (Tokens::T_COMMA != $this->tokenizer->peek()) {
break;
}

$this->consumeToken(Tokens::T_COMMA);
$this->consumeComments();

// Add mapping between image and qualified name to symbol table
$this->useSymbolTable->add($image, join('', array_merge($fragments, $subFragments)));
} while (true);

$this->useSymbolTable->add($image, join('', array_merge($fragments, $subFragments)));

$this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);
$this->consumeComments();

$this->namespacePrefixReplaced = $namespacePrefixReplaced;
}

/**
* @param array $previousElements
* @return string
*/
protected function parseQualifiedNameElement(array $previousElements)
{
if (Tokens::T_CURLY_BRACE_OPEN !== $this->tokenizer->peek()) {
return parent::parseQualifiedNameElement($previousElements);
}
if (count($previousElements) > 2 && '\\' === end($previousElements)) {
return null;
}
$this->throwUnexpectedTokenException($this->tokenizer->next());
}
}
Expand Up @@ -45,6 +45,7 @@

use PDepend\AbstractTest;
use PDepend\Source\AST\ASTExpression;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Tokenizer\Tokenizer;
use PDepend\Util\Cache\CacheDriver;
Expand Down Expand Up @@ -431,6 +432,49 @@ public function testListKeywordAsFunctionNameThrowsException()
$this->parseCodeResourceForTest();
}

/**
* @return \PDepend\Source\AST\ASTNamespace
*/
public function testGroupUseStatement()
{
$namespaces = $this->parseCodeResourceForTest();
$this->assertNotNull($namespaces);

return $namespaces[0];
}

/**
* @param \PDepend\Source\AST\ASTNamespace $namespace
* @return void
* @depends testGroupUseStatement
*/
public function testGroupUseStatementClassNameResolution(ASTNamespace $namespace)
{
$classes = $namespace->getClasses();
$class = $classes[0];

$this->assertEquals(
'FooLibrary\Bar\Baz\ClassB',
$class->getParentClass()->getNamespacedName()
);
}

/**
* @param \PDepend\Source\AST\ASTNamespace $namespace
* @return void
* @depends testGroupUseStatement
*/
public function testGroupUseStatementAliasResolution(ASTNamespace $namespace)
{
$classes = $namespace->getClasses();
$class = $classes[1];

$this->assertEquals(
'FooLibrary\Bar\Baz\ClassD',
$class->getParentClass()->getNamespacedName()
);
}

/**
* @param \PDepend\Source\Tokenizer\Tokenizer $tokenizer
* @param \PDepend\Source\Builder\Builder $builder
Expand Down
@@ -0,0 +1,12 @@
<?php
use FooLibrary\Bar\Baz\{ ClassA, ClassB, ClassC, ClassD as Fizbo };

class ExtendingClass extends ClassB
{

}

class AliasExtendingClass extends Fizbo
{

}

0 comments on commit fd4aaca

Please sign in to comment.