Skip to content

Commit

Permalink
fix: handle inferring methods with same names properly
Browse files Browse the repository at this point in the history
  • Loading branch information
romm committed Jul 4, 2022
1 parent 3020db2 commit dc45dd8
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 2 deletions.
3 changes: 1 addition & 2 deletions src/Utility/Reflection/ClassAliasParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

use function array_shift;
use function explode;
use function get_class;
use function implode;
use function strtolower;

Expand Down Expand Up @@ -63,6 +62,6 @@ public function resolveAlias(string $symbol, Reflector $reflection): string
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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces;

interface InterfaceA
{
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces;

interface InterfaceB
{
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
40 changes: 40 additions & 0 deletions tests/Integration/Mapping/InterfaceInferringMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
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;
Expand Down Expand Up @@ -146,6 +153,39 @@ function (string $type, int $key): string {
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);
Expand Down

0 comments on commit dc45dd8

Please sign in to comment.