fix: handle inferring methods with same names properly

This commit is contained in:
Romain Canon 2022-07-01 21:53:39 +02:00
parent 3020db20bf
commit dc45dd8ac5
11 changed files with 161 additions and 2 deletions

View File

@ -12,7 +12,6 @@ use Reflector;
use function array_shift;
use function explode;
use function get_class;
use function implode;
use function strtolower;
@ -63,6 +62,6 @@ final class ClassAliasParser
private function aliases(Reflector $reflection): array
{
/** @infection-ignore-all */
return $this->aliases[get_class($reflection) . $reflection->name] ??= Singleton::phpParser()->parseUseStatements($reflection);
return $this->aliases[Reflection::signature($reflection)] ??= Singleton::phpParser()->parseUseStatements($reflection);
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\A;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceA;
final class ClassThatInheritsInterfaceA implements InterfaceA
{
public string $value;
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\A;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceA;
final class OtherClassThatInheritsInterfaceA implements InterfaceA
{
public string $value;
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\B;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceB;
final class ClassThatInheritsInterfaceB implements InterfaceB
{
public string $value;
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\B;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceB;
final class OtherClassThatInheritsInterfaceB implements InterfaceB
{
public string $value;
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces;
final class ClassWithBothInterfaces
{
public InterfaceA $a;
public InterfaceB $b;
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces;
interface InterfaceA
{
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\A\ClassThatInheritsInterfaceA;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\A\OtherClassThatInheritsInterfaceA;
final class InterfaceAInferer
{
/**
* @return class-string<ClassThatInheritsInterfaceA|OtherClassThatInheritsInterfaceA>
*/
public static function infer(bool $classic): string
{
return $classic
? ClassThatInheritsInterfaceA::class
: OtherClassThatInheritsInterfaceA::class;
}
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces;
interface InterfaceB
{
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\B\ClassThatInheritsInterfaceB;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\B\OtherClassThatInheritsInterfaceB;
final class InterfaceBInferer
{
/**
* @return class-string<ClassThatInheritsInterfaceB|OtherClassThatInheritsInterfaceB>
*/
public static function infer(bool $classic): string
{
return $classic
? ClassThatInheritsInterfaceB::class
: OtherClassThatInheritsInterfaceB::class;
}
}

View File

@ -12,6 +12,13 @@ use CuyZ\Valinor\Mapper\Tree\Exception\ObjectImplementationCallbackError;
use CuyZ\Valinor\Mapper\Tree\Exception\ObjectImplementationNotRegistered;
use CuyZ\Valinor\Mapper\Tree\Exception\ResolvedImplementationIsNotAccepted;
use CuyZ\Valinor\MapperBuilder;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\A\ClassThatInheritsInterfaceA;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\B\ClassThatInheritsInterfaceB;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\ClassWithBothInterfaces;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceA;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceAInferer;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceB;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\InterfaceBInferer;
use CuyZ\Valinor\Tests\Integration\IntegrationTest;
use CuyZ\Valinor\Type\Resolver\Exception\CannotResolveObjectType;
use DateTime;
@ -146,6 +153,39 @@ final class InterfaceInferringMappingTest extends IntegrationTest
self::assertSame('bar', $resultB->valueB);
}
public function test_infer_with_two_functions_with_same_name_works_properly(): void
{
try {
$result = (new MapperBuilder())
->infer(
InterfaceA::class,
// @PHP8.1 first-class callable syntax
[InterfaceAInferer::class, 'infer']
)
->infer(
InterfaceB::class,
// @PHP8.1 first-class callable syntax
[InterfaceBInferer::class, 'infer']
)
->mapper()
->map(ClassWithBothInterfaces::class, [
'a' => [
'classic' => true,
'value' => 'foo',
],
'b' => [
'classic' => true,
'value' => 'bar',
],
]);
} catch (MappingError $error) {
$this->mappingFail($error);
}
self::assertInstanceOf(ClassThatInheritsInterfaceA::class, $result->a);
self::assertInstanceOf(ClassThatInheritsInterfaceB::class, $result->b);
}
public function test_unresolvable_implementation_throws_exception(): void
{
$this->expectException(CannotResolveObjectType::class);