Skip to content

Commit

Permalink
Merge 51761af into f989f45
Browse files Browse the repository at this point in the history
  • Loading branch information
ragboyjr committed Aug 22, 2018
2 parents f989f45 + 51761af commit 513e162
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 25 deletions.
118 changes: 96 additions & 22 deletions src/Types/ContextFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,7 @@ private function parseUseStatement(\ArrayIterator $tokens)
while ($continue) {
$this->skipToNextStringOrNamespaceSeparator($tokens);

list($alias, $fqnn) = $this->extractUseStatement($tokens);
$uses[$alias] = $fqnn;
$uses = array_merge($uses, $this->extractUseStatements($tokens));
if ($tokens->current()[0] === self::T_LITERAL_END_OF_USE) {
$continue = false;
}
Expand All @@ -215,38 +214,113 @@ private function skipToNextStringOrNamespaceSeparator(\ArrayIterator $tokens)

/**
* Deduce the namespace name and alias of an import when we are at the T_USE token or have not reached the end of
* a USE statement yet.
* a USE statement yet. This will return a key/value array of the alias => namespace.
*
* @return array
*/
private function extractUseStatement(\ArrayIterator $tokens)
private function extractUseStatements(\ArrayIterator $tokens)
{
$result = [''];
while ($tokens->valid()
&& ($tokens->current()[0] !== self::T_LITERAL_USE_SEPARATOR)
&& ($tokens->current()[0] !== self::T_LITERAL_END_OF_USE)
) {
if ($tokens->current()[0] === T_AS) {
$result[] = '';
$extractedUseStatements = [];
$groupedNs = '';
$currentNs = '';
$currentAlias = null;
$state = "start";

$i = 0;
while ($tokens->valid()) {
$i += 1;
$currentToken = $tokens->current();
$tokenId = is_string($currentToken) ? $currentToken : $currentToken[0];
$tokenValue = is_string($currentToken) ? null : $currentToken[1];
switch ($state) {
case "start":
switch ($tokenId) {
case T_STRING:
case T_NS_SEPARATOR:
$currentNs .= $tokenValue;
break;
case T_CURLY_OPEN:
case '{':
$state = 'grouped';
$groupedNs = $currentNs;
break;
case T_AS:
$state = 'start-alias';
break;
case self::T_LITERAL_USE_SEPARATOR:
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}
break;
case "start-alias":
switch ($tokenId) {
case T_STRING:
$currentAlias .= $tokenValue;
break;
case self::T_LITERAL_USE_SEPARATOR:
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}
break;
case "grouped":
switch ($tokenId) {
case T_STRING:
case T_NS_SEPARATOR:
$currentNs .= $tokenValue;
break;
case T_AS:
$state = 'grouped-alias';
break;
case self::T_LITERAL_USE_SEPARATOR:
$state = 'grouped';
$extractedUseStatements[$currentAlias ?: $currentNs] = $currentNs;
$currentNs = $groupedNs;
$currentAlias = null;
break;
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}
break;
case "grouped-alias":
switch ($tokenId) {
case T_STRING:
$currentAlias .= $tokenValue;
break;
case self::T_LITERAL_USE_SEPARATOR:
$state = 'grouped';
$extractedUseStatements[$currentAlias ?: $currentNs] = $currentNs;
$currentNs = $groupedNs;
$currentAlias = null;
break;
case self::T_LITERAL_END_OF_USE:
$state = 'end';
break;
default:
break;
}
}

if ($tokens->current()[0] === T_STRING || $tokens->current()[0] === T_NS_SEPARATOR) {
$result[count($result) - 1] .= $tokens->current()[1];
if ($state == "end") {
break;
}

$tokens->next();
}

if (count($result) === 1) {
$backslashPos = strrpos($result[0], '\\');

if (false !== $backslashPos) {
$result[] = substr($result[0], $backslashPos + 1);
} else {
$result[] = $result[0];
}
if ($groupedNs != $currentNs) {
$extractedUseStatements[$currentAlias ?: $currentNs] = $currentNs;
}

return array_reverse($result);

return $extractedUseStatements;
}
}
13 changes: 10 additions & 3 deletions tests/unit/Types/ContextFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@

// Added imports on purpose as mock for the unit tests, please do not remove.
use \ReflectionClass;
use Mockery as m;
use phpDocumentor;
use Mockery as m, phpDocumentor;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlock\Tag;
use PHPUnit\Framework\TestCase; // yes, the slash is part of the test
use PHPUnit\Framework\{
Assert,
Exception as e
};

/**
* @coversDefaultClass \phpDocumentor\Reflection\Types\ContextFactory
Expand Down Expand Up @@ -53,14 +56,18 @@ public function testReadsAliasesFromClassReflection()
'Tag' => Tag::class,
'phpDocumentor' => 'phpDocumentor',
'TestCase' => TestCase::class,
'Assert' => Assert::class,
'e' => e::class,
ReflectionClass::class => ReflectionClass::class,
];
$context = $fixture->createFromReflector(new ReflectionClass($this));

$actual = $context->getNamespaceAliases();

// sort so that order differences don't break it
$this->assertSame(sort($expected), sort($actual));
sort($expected);
sort($actual);
$this->assertSame($expected, $actual);
}

/**
Expand Down

0 comments on commit 513e162

Please sign in to comment.