From ae0f5bd340d25bf741b4cedf0872f4baa9719b32 Mon Sep 17 00:00:00 2001 From: Romain Canon Date: Wed, 18 Sep 2024 06:08:22 +0200 Subject: [PATCH] misc: simplify alias handling --- .../Specifications/AliasSpecification.php | 21 +- src/Utility/Reflection/PhpParser.php | 6 +- src/Utility/Reflection/TokenParser.php | 15 +- .../Unit/Utility/Reflection/PhpParserTest.php | 272 ++++-------------- 4 files changed, 70 insertions(+), 244 deletions(-) diff --git a/src/Type/Parser/Factory/Specifications/AliasSpecification.php b/src/Type/Parser/Factory/Specifications/AliasSpecification.php index 3d927787..236a1586 100644 --- a/src/Type/Parser/Factory/Specifications/AliasSpecification.php +++ b/src/Type/Parser/Factory/Specifications/AliasSpecification.php @@ -53,32 +53,27 @@ public function manipulateToken(TraversingToken $token): TraversingToken private function resolveAlias(string $symbol): string { - $alias = $symbol; + $aliases = PhpParser::parseUseStatements($this->reflection); $namespaceParts = explode('\\', $symbol); - $firstPart = array_shift($namespaceParts); - if ($firstPart) { - $alias = strtolower($firstPart); + $lastPart = strtolower(end($namespaceParts)); + + if (isset($aliases[$lastPart])) { + return $aliases[$lastPart]; } - $aliases = PhpParser::parseUseStatements($this->reflection); + $alias = strtolower(array_shift($namespaceParts)); if (! isset($aliases[$alias])) { return $symbol; } - $fqcn = $aliases[$alias]['fqcn']; - if ($namespaceParts === []) { - return $fqcn; - } - - if (! $aliases[$alias]['isExplicitAlias']) { - return $symbol; + return $aliases[$alias]; } - return $fqcn . '\\' . implode('\\', $namespaceParts); + return $aliases[$alias] . '\\' . implode('\\', $namespaceParts); } private function resolveNamespaced(string $symbol): string diff --git a/src/Utility/Reflection/PhpParser.php b/src/Utility/Reflection/PhpParser.php index 3024c331..9f08755d 100644 --- a/src/Utility/Reflection/PhpParser.php +++ b/src/Utility/Reflection/PhpParser.php @@ -17,12 +17,12 @@ */ final class PhpParser { - /** @var array> */ + /** @var array> */ private static array $statements = []; /** * @param ReflectionClass|ReflectionFunction|ReflectionMethod $reflection - * @return array + * @return array */ public static function parseUseStatements(\ReflectionClass|\ReflectionFunction|\ReflectionMethod $reflection): array { @@ -34,7 +34,7 @@ public static function parseUseStatements(\ReflectionClass|\ReflectionFunction|\ /** * @param ReflectionClass|ReflectionFunction|ReflectionMethod $reflection - * @return array + * @return array */ private static function fetchUseStatements(\ReflectionClass|\ReflectionFunction|\ReflectionMethod $reflection): array { diff --git a/src/Utility/Reflection/TokenParser.php b/src/Utility/Reflection/TokenParser.php index 68dc04ee..e97bd34c 100644 --- a/src/Utility/Reflection/TokenParser.php +++ b/src/Utility/Reflection/TokenParser.php @@ -29,7 +29,7 @@ public function __construct(string $content) } /** - * @return array + * @return array */ public function parseUseStatements(string $namespaceName): array { @@ -58,7 +58,7 @@ public function parseUseStatements(string $namespaceName): array } /** - * @return array + * @return array */ private function parseUseStatement(): array { @@ -86,18 +86,12 @@ private function parseUseStatement(): array $explicitAlias = true; $alias = ''; } elseif ($name === ',') { - $statements[strtolower($alias)] = [ - 'fqcn' => $groupRoot . $class, - 'isExplicitAlias' => $explicitAlias, - ]; + $statements[strtolower($alias)] = $groupRoot . $class; $class = $alias = ''; $explicitAlias = false; } elseif ($name === ';') { if ($alias !== '') { - $statements[strtolower($alias)] = [ - 'fqcn' => $groupRoot . $class, - 'isExplicitAlias' => $explicitAlias, - ]; + $statements[strtolower($alias)] = $groupRoot . $class; } break; } elseif ($name === '{') { @@ -106,7 +100,6 @@ private function parseUseStatement(): array } } - /** @var array */ return $statements; } diff --git a/tests/Unit/Utility/Reflection/PhpParserTest.php b/tests/Unit/Utility/Reflection/PhpParserTest.php index 8f444af2..23eed74e 100644 --- a/tests/Unit/Utility/Reflection/PhpParserTest.php +++ b/tests/Unit/Utility/Reflection/PhpParserTest.php @@ -26,7 +26,7 @@ final class PhpParserTest extends TestCase { /** * @param ReflectionClass|ReflectionFunction|ReflectionMethod $reflection - * @param array $expectedMap + * @param array $expectedMap */ #[DataProvider('use_statements_data_provider')] public function test_parse_use_statements(\ReflectionClass|\ReflectionFunction|\ReflectionMethod $reflection, array $expectedMap): void @@ -46,282 +46,120 @@ public static function use_statements_data_provider(): Generator yield 'one namespace' => [ new ReflectionClass(ClassInSingleNamespace::class), [ - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'multiple namespaces, class A' => [ new ReflectionClass(ClassA::class), [ - 'classb' => [ - 'fqcn' => ClassB::class, - 'isExplicitAlias' => false, - ], - 'classbalias' => [ - 'fqcn' => ClassB::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'classb' => ClassB::class, + 'classbalias' => ClassB::class, + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'multiple namespaces, class B' => [ new ReflectionClass(ClassB::class), [ - 'classa' => [ - 'fqcn' => ClassA::class, - 'isExplicitAlias' => false, - ], - 'classaalias' => [ - 'fqcn' => ClassA::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'classa' => ClassA::class, + 'classaalias' => ClassA::class, + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'multiple namespaces, function A' => [ new ReflectionFunction('\CuyZ\Valinor\Tests\Fixtures\WithAliasA\functionA'), [ - 'classb' => [ - 'fqcn' => ClassB::class, - 'isExplicitAlias' => false, - ], - 'classbalias' => [ - 'fqcn' => ClassB::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'classb' => ClassB::class, + 'classbalias' => ClassB::class, + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'multiple namespaces, function B' => [ new ReflectionFunction('\CuyZ\Valinor\Tests\Fixtures\WithAliasB\functionB'), [ - 'classa' => [ - 'fqcn' => ClassA::class, - 'isExplicitAlias' => false, - ], - 'classaalias' => [ - 'fqcn' => ClassA::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'classa' => ClassA::class, + 'classaalias' => ClassA::class, + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'one namespace, method' => [ new ReflectionMethod(ClassInSingleNamespace::class, '__construct'), [ - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'multiple namespaces, class A method' => [ new ReflectionMethod(ClassA::class, '__construct'), [ - 'classb' => [ - 'fqcn' => ClassB::class, - 'isExplicitAlias' => false, - ], - 'classbalias' => [ - 'fqcn' => ClassB::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'classb' => ClassB::class, + 'classbalias' => ClassB::class, + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'multiple namespaces, class B method' => [ new ReflectionMethod(ClassB::class, '__construct'), [ - 'classa' => [ - 'fqcn' => ClassA::class, - 'isExplicitAlias' => false, - ], - 'classaalias' => [ - 'fqcn' => ClassA::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'foo' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => false, - ], - 'datetimeimmutable' => [ - 'fqcn' => \DateTimeImmutable::class, - 'isExplicitAlias' => false, - ], - 'stdclassalias' => [ - 'fqcn' => \stdClass::class, - 'isExplicitAlias' => true, - ], + 'classa' => ClassA::class, + 'classaalias' => ClassA::class, + 'baralias' => Bar::class, + 'foo' => Foo::class, + 'datetimeimmutable' => \DateTimeImmutable::class, + 'stdclassalias' => \stdClass::class, ] ]; yield 'function in root namespace' => [ new ReflectionFunction('function_in_root_namespace'), [ - 'fooalias' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], + 'fooalias' => Foo::class, + 'baralias' => Bar::class, ] ]; yield 'one namespace, one use statement, two import statements' => [ new ReflectionFunction('CuyZ\Valinor\Tests\Unit\Utility\Reflection\Fixtures\function_with_several_import_statements_in_same_use_statement'), [ - 'fooalias' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'anotherfooalias' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => true, - ], - 'anotherbaralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], + 'fooalias' => Foo::class, + 'baralias' => Bar::class, + 'anotherfooalias' => Foo::class, + 'anotherbaralias' => Bar::class, ] ]; yield 'one namespace, one use statement, two grouped import statements' => [ new ReflectionFunction('\CuyZ\Valinor\Tests\Unit\Utility\Reflection\Fixtures\function_with_grouped_import_statements'), [ - 'fooalias' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => true, - ], - 'baralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], - 'anotherfooalias' => [ - 'fqcn' => Foo::class, - 'isExplicitAlias' => true, - ], - 'anotherbaralias' => [ - 'fqcn' => Bar::class, - 'isExplicitAlias' => true, - ], + 'fooalias' => Foo::class, + 'baralias' => Bar::class, + 'anotherfooalias' => Foo::class, + 'anotherbaralias' => Bar::class, ], ]; }