diff --git a/README.md b/README.md index bbf2a85..1b54c4d 100644 --- a/README.md +++ b/README.md @@ -161,8 +161,6 @@ Another approach for DIC-only usages is to scan the generated php file, but that ## Limitations: - Extension dependencies are not analysed (e.g. `ext-json`) -- Files without namespace has limited support - - Only symbols with use statements and FQNs are detected ## Contributing: - Check your code by `composer check` diff --git a/src/UsedSymbolExtractor.php b/src/UsedSymbolExtractor.php index 10537d1..8f386c8 100644 --- a/src/UsedSymbolExtractor.php +++ b/src/UsedSymbolExtractor.php @@ -7,6 +7,7 @@ use function is_array; use function ltrim; use function strlen; +use function strpos; use function substr; use function token_get_all; use const PHP_VERSION_ID; @@ -72,6 +73,7 @@ public function parseUsedSymbols(): array $level = 0; // {, }, {$, ${ $squareLevel = 0; // [, ], #[ + $inGlobalScope = true; $inClassLevel = null; $inAttributeSquareLevel = null; @@ -105,6 +107,7 @@ public function parseUsedSymbols(): array break; case PHP_VERSION_ID >= 80000 ? T_NAMESPACE : -1: + $inGlobalScope = false; $useStatements = []; // reset use statements on namespace change break; @@ -121,6 +124,11 @@ public function parseUsedSymbols(): array $symbolName = $useStatements[$neededAlias] . substr($token[1], strlen($neededAlias)); $kind = $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null); $usedSymbols[$kind][$symbolName][] = $token[2]; + + } elseif ($inGlobalScope) { + $symbolName = $token[1]; + $kind = $this->getFqnSymbolKind($this->pointer - 2, $this->pointer, $inAttributeSquareLevel !== null); + $usedSymbols[$kind][$symbolName][] = $token[2]; } break; @@ -142,6 +150,7 @@ public function parseUsedSymbols(): array if (substr($nextName, 0, 1) !== '\\') { // not a namespace-relative name, but a new namespace declaration $useStatements = []; // reset use statements on namespace change + $inGlobalScope = false; } break; @@ -173,6 +182,11 @@ public function parseUsedSymbols(): array $symbolName = $useStatements[$neededAlias] . substr($name, strlen($neededAlias)); $kind = $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false); $usedSymbols[$kind][$symbolName][] = $token[2]; + + } elseif ($inGlobalScope && strpos($name, '\\') !== false) { + $symbolName = $name; + $kind = $this->getFqnSymbolKind($pointerBeforeName, $this->pointer - 1, false); + $usedSymbols[$kind][$symbolName][] = $token[2]; } } diff --git a/tests/UsedSymbolExtractorTest.php b/tests/UsedSymbolExtractorTest.php index 5f85160..5a039cc 100644 --- a/tests/UsedSymbolExtractorTest.php +++ b/tests/UsedSymbolExtractorTest.php @@ -105,6 +105,10 @@ public function provideVariants(): iterable [ SymbolKind::CLASSLIKE => [ 'DateTimeImmutable' => [3], + 'PHPUnit\Framework\Error' => [5], + ], + SymbolKind::FUNCTION => [ + 'PHPUnit\Framework\assertSame' => [7], ], ], ]; diff --git a/tests/data/not-autoloaded/used-symbols/global-namespace.php b/tests/data/not-autoloaded/used-symbols/global-namespace.php index fb70774..a6e0929 100644 --- a/tests/data/not-autoloaded/used-symbols/global-namespace.php +++ b/tests/data/not-autoloaded/used-symbols/global-namespace.php @@ -2,7 +2,9 @@ new \DateTimeImmutable(); new DateTime; +new PHPUnit\Framework\Error(); +PHPUnit\Framework\assertSame(1, 1); class Foo { public function someFunction(string $foo): void diff --git a/tests/data/not-autoloaded/used-symbols/relative-namespace.php b/tests/data/not-autoloaded/used-symbols/relative-namespace.php index 9e3c447..ec6805c 100644 --- a/tests/data/not-autoloaded/used-symbols/relative-namespace.php +++ b/tests/data/not-autoloaded/used-symbols/relative-namespace.php @@ -8,3 +8,4 @@ class Foo {} new namespace\Foo(); new DateTimeImmutable(); +new Foo\Bar; // is Relative\Foo\Bar