Skip to content

Commit

Permalink
minor #5407 TokensAnalyzer::getClassyElements - return trait imports …
Browse files Browse the repository at this point in the history
…(SpacePossum)

This PR was merged into the 2.17 branch.

Discussion
----------

TokensAnalyzer::getClassyElements - return trait imports

Commits
-------

ab2e7cd TokensAnalyzer::getClassyElements - return trait imports
  • Loading branch information
SpacePossum committed Dec 31, 2020
2 parents fb0b660 + ab2e7cd commit 15a42b6
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 51 deletions.
25 changes: 17 additions & 8 deletions src/Tokenizer/TokensAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ public function __construct(Tokens $tokens)
/**
* Get indexes of methods and properties in classy code (classes, interfaces and traits).
*
* @param bool $returnTraitsImports TODO on v3 remove flag and return the imports
*
* @return array[]
*/
public function getClassyElements()
public function getClassyElements($returnTraitsImports = false)
{
$elements = [];

for ($index = 1, $count = \count($this->tokens) - 2; $index < $count; ++$index) {
if ($this->tokens[$index]->isClassy()) {
list($index, $newElements) = $this->findClassyElements($index, $index);
list($index, $newElements) = $this->findClassyElements($index, $index, $returnTraitsImports);
$elements += $newElements;
}
}
Expand Down Expand Up @@ -638,12 +640,13 @@ public function isSuperGlobal($index)
* Searches in tokens from the classy (start) index till the end (index) of the classy.
* Returns an array; first value is the index until the method has analysed (int), second the found classy elements (array).
*
* @param int $classIndex classy index
* @param int $index
* @param int $classIndex classy index
* @param int $index
* @param bool $returnTraitsImports
*
* @return array
*/
private function findClassyElements($classIndex, $index)
private function findClassyElements($classIndex, $index, $returnTraitsImports = false)
{
$elements = [];
$curlyBracesLevel = 0;
Expand Down Expand Up @@ -681,7 +684,7 @@ private function findClassyElements($classIndex, $index)
--$nestedBracesLevel;

if (0 === $nestedBracesLevel) {
list($index, $newElements) = $this->findClassyElements($nestedClassIndex, $index);
list($index, $newElements) = $this->findClassyElements($nestedClassIndex, $index, $returnTraitsImports);
$elements += $newElements;

break;
Expand All @@ -691,12 +694,12 @@ private function findClassyElements($classIndex, $index)
}

if ($token->isClassy()) { // anonymous class in class
list($index, $newElements) = $this->findClassyElements($index, $index);
list($index, $newElements) = $this->findClassyElements($index, $index, $returnTraitsImports);
$elements += $newElements;
}
}
} else {
list($index, $newElements) = $this->findClassyElements($nestedClassIndex, $nestedClassIndex);
list($index, $newElements) = $this->findClassyElements($nestedClassIndex, $nestedClassIndex, $returnTraitsImports);
$elements += $newElements;
}

Expand Down Expand Up @@ -757,6 +760,12 @@ private function findClassyElements($classIndex, $index)
'type' => 'const',
'classIndex' => $classIndex,
];
} elseif ($returnTraitsImports && $token->isGivenKind(CT::T_USE_TRAIT)) {
$elements[$index] = [
'token' => $token,
'type' => 'trait_import',
'classIndex' => $classIndex,
];
}
}

Expand Down
156 changes: 113 additions & 43 deletions tests/Tokenizer/TokensAnalyzerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,97 +28,167 @@
*/
final class TokensAnalyzerTest extends TestCase
{
public function testGetClassyElements()
/**
* @dataProvider provideGetClassyElementsCases
*
* @param bool $returnTraitsImports
* @param string $source
*/
public function testGetClassyElements(array $expectedElements, $returnTraitsImports, $source)
{
$source = <<<'PHP'
<?php
class Foo
{
public $prop0;
protected $prop1;
private $prop2 = 1;
var $prop3 = array(1,2,3);
const CONSTANT = 'constant value';
$tokens = Tokens::fromCode($source);

public function bar4()
{
$a = 5;
foreach ($expectedElements as $index => $element) {
$expectedElements[$index] = [
'token' => $tokens[$index],
'type' => $element['type'],
'classIndex' => $element['classIndex'],
];
}

return " ({$a})";
$tokensAnalyzer = new TokensAnalyzer($tokens);

static::assertSame(
$expectedElements,
$tokensAnalyzer->getClassyElements($returnTraitsImports)
);
}
public function bar5($data)

public function provideGetClassyElementsCases()
{
$message = $data;
$example = function ($arg) use ($message) {
echo $arg . ' ' . $message;
};
$example('hello');
}function A(){}
}
yield 'trait import' => [
[
10 => [
'type' => 'trait_import',
'classIndex' => 4,
],
19 => [
'type' => 'trait_import',
'classIndex' => 4,
],
24 => [
'type' => 'const',
'classIndex' => 4,
],
35 => [
'type' => 'method',
'classIndex' => 4,
],
55 => [
'type' => 'trait_import',
'classIndex' => 49,
],
64 => [
'type' => 'method',
'classIndex' => 49,
],
],
true,
'<?php
/** */
class Foo
{
use A\B;
//
use Foo;
function test(){}
const A = 1;
class Foo2
{
const CONSTANT = 'constant value';
}
public function foo()
{
$a = new class()
{
use Z; // nested trait import
PHP;
public function bar()
{
echo 123;
}
};
$tokens = Tokens::fromCode($source);
$tokensAnalyzer = new TokensAnalyzer($tokens);
$elements = $tokensAnalyzer->getClassyElements();
$a->bar();
}
}',
];

static::assertSame(
yield [
[
9 => [
'token' => $tokens[9],
'type' => 'property',
'classIndex' => 1,
],
14 => [
'token' => $tokens[14],
'type' => 'property',
'classIndex' => 1,
],
19 => [
'token' => $tokens[19],
'type' => 'property',
'classIndex' => 1,
],
28 => [
'token' => $tokens[28],
'type' => 'property',
'classIndex' => 1,
],
42 => [
'token' => $tokens[42],
'type' => 'const',
'classIndex' => 1,
],
53 => [
'token' => $tokens[53],
'type' => 'method',
'classIndex' => 1,
],
83 => [
'token' => $tokens[83],
'type' => 'method',
'classIndex' => 1,
],
140 => [
'token' => $tokens[140],
'type' => 'method',
'classIndex' => 1,
],
164 => [
'token' => $tokens[164],
'type' => 'const',
'classIndex' => 158,
],
],
$elements
);
false,
<<<'PHP'
<?php
class Foo
{
public $prop0;
protected $prop1;
private $prop2 = 1;
var $prop3 = array(1,2,3);
const CONSTANT = 'constant value';
public function bar4()
{
$a = 5;
return " ({$a})";
}
public function bar5($data)
{
$message = $data;
$example = function ($arg) use ($message) {
echo $arg . ' ' . $message;
};
$example('hello');
}function A(){}
}
function test(){}
class Foo2
{
const CONSTANT = 'constant value';
use Foo\Bar; // not expected in the return value by default (BC)
}

PHP
,
];
}

/**
Expand Down

0 comments on commit 15a42b6

Please sign in to comment.