diff --git a/src/Analysers/TokenScanner.php b/src/Analysers/TokenScanner.php index 4cf70cd9a..df7f317dd 100644 --- a/src/Analysers/TokenScanner.php +++ b/src/Analysers/TokenScanner.php @@ -33,6 +33,7 @@ protected function scanTokens(array $tokens): array $isInterface = false; $namespace = ''; $currentName = null; + $unitLevel = 0; $lastToken = null; $stack = []; @@ -44,6 +45,9 @@ protected function scanTokens(array $tokens): array break; case '}': array_pop($stack); + if (count($stack) == $unitLevel) { + $currentName = null; + } break; } continue; @@ -69,7 +73,7 @@ protected function scanTokens(array $tokens): array break; case T_CLASS: - if ($stack) { + if ($currentName) { break; } @@ -95,28 +99,31 @@ protected function scanTokens(array $tokens): array $isInterface = false; $currentName = $namespace . '\\' . $token[1]; + $unitLevel = count($stack); $units[$currentName] = ['uses' => $uses, 'interfaces' => [], 'traits' => [], 'methods' => [], 'properties' => []]; break; case T_INTERFACE: - if ($stack) { + if ($currentName) { break; } $isInterface = true; $token = $this->nextToken($tokens); $currentName = $namespace . '\\' . $token[1]; + $unitLevel = count($stack); $units[$currentName] = ['uses' => $uses, 'interfaces' => [], 'traits' => [], 'methods' => [], 'properties' => []]; break; case T_TRAIT: - if ($stack) { + if ($currentName) { break; } $isInterface = false; $token = $this->nextToken($tokens); $currentName = $namespace . '\\' . $token[1]; + $unitLevel = count($stack); $this->skipTo($tokens, '{', true); $units[$currentName] = ['uses' => $uses, 'interfaces' => [], 'traits' => [], 'methods' => [], 'properties' => []]; break; @@ -129,7 +136,7 @@ protected function scanTokens(array $tokens): array if (!is_array($token) || T_IMPLEMENTS !== $token[0]) { break; } - // no break + // no break case T_IMPLEMENTS: $fqns = $this->parseFQNStatement($tokens, $token); if ($currentName) { @@ -140,7 +147,7 @@ protected function scanTokens(array $tokens): array case T_FUNCTION: $token = $this->nextToken($tokens); - if (1 == count($stack) && $currentName) { + if (($unitLevel + 1) == count($stack) && $currentName) { if (!$isInterface) { // more nesting $this->skipTo($tokens, '{', true); @@ -153,7 +160,7 @@ protected function scanTokens(array $tokens): array break; case T_VARIABLE: - if (1 == count($stack) && $currentName) { + if (($unitLevel + 1) == count($stack) && $currentName) { $units[$currentName]['properties'][] = substr($token[1], 1); } break; diff --git a/tests/Analysers/TokenScannerTest.php b/tests/Analysers/TokenScannerTest.php index 993a1f466..f0aee0c05 100644 --- a/tests/Analysers/TokenScannerTest.php +++ b/tests/Analysers/TokenScannerTest.php @@ -191,6 +191,44 @@ public function scanCases() ], ], ], + 'namespaces1' => [ + 'PHP/namespaces1.php', + [ + 'Foo\\FooClass' => [ + 'uses' => [], + 'interfaces' => [], + 'traits' => [], + 'methods' => [], + 'properties' => [], + ], + 'Bar\\BarClass' => [ + 'uses' => [], + 'interfaces' => [], + 'traits' => [], + 'methods' => [], + 'properties' => [], + ], + ], + 'namespaces2' => [ + 'PHP/namespaces2.php', + [ + 'Foo\\FooClass' => [ + 'uses' => [], + 'interfaces' => [], + 'traits' => [], + 'methods' => [], + 'properties' => [], + ], + 'Bar\\BarClass' => [ + 'uses' => [], + 'interfaces' => [], + 'traits' => [], + 'methods' => [], + 'properties' => [], + ], + ], + ], + ], ]; } diff --git a/tests/Fixtures/PHP/namespaces1.php b/tests/Fixtures/PHP/namespaces1.php new file mode 100644 index 000000000..7902a83bc --- /dev/null +++ b/tests/Fixtures/PHP/namespaces1.php @@ -0,0 +1,14 @@ +