Skip to content

Commit

Permalink
Search for candidates in called class as well
Browse files Browse the repository at this point in the history
  • Loading branch information
vudaltsov committed Nov 27, 2023
1 parent a680c9d commit 66c2201
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 13 deletions.
12 changes: 8 additions & 4 deletions src/CandidatesFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ final class CandidatesFinder
private function __construct() {}

/**
* @param class-string $class
* @return list<\ReflectionMethod>
*/
public static function findCandidates(\ReflectionMethod $method): array
public static function findCandidates(\ReflectionMethod $method, string $class): array
{
$static = $method->isStatic();
$private = $method->isPrivate();
$protected = $method->isProtected();
$candidates = [];

foreach (self::findCandidatesByAttribute($method) as $candidate) {
foreach (self::findCandidatesByAttribute($method, $class) as $candidate) {
if ($candidate->isStatic() !== $static) {
throw new \LogicException(sprintf(
'%s %s::%s() is not a valid overloading method for %s %s::%s().',
Expand Down Expand Up @@ -58,18 +59,21 @@ public static function findCandidates(\ReflectionMethod $method): array
}

/**
* @param class-string $class
* @return \Generator<int, \ReflectionMethod>
*/
private static function findCandidatesByAttribute(\ReflectionMethod $method): \Generator
private static function findCandidatesByAttribute(\ReflectionMethod $method, string $class): \Generator
{
foreach ($method->getDeclaringClass()->getMethods() as $candidate) {
foreach ((new \ReflectionClass($class))->getMethods() as $candidate) {
if ($candidate->name === $method->name) {
continue;
}

foreach ($candidate->getAttributes(Overload::class) as $attribute) {
if ($attribute->newInstance()->name === $method->name) {
yield $candidate;

continue 2;

Check warning on line 76 in src/CandidatesFinder.php

View workflow job for this annotation

GitHub Actions / infection (8.1)

Escaped Mutant for Mutator "DecrementInteger": --- Original +++ New @@ @@ foreach ($candidate->getAttributes(Overload::class) as $attribute) { if ($attribute->newInstance()->name === $method->name) { (yield $candidate); - continue 2; + continue 1; } } } } }

Check warning on line 76 in src/CandidatesFinder.php

View workflow job for this annotation

GitHub Actions / infection (8.1)

Escaped Mutant for Mutator "Continue_": --- Original +++ New @@ @@ foreach ($candidate->getAttributes(Overload::class) as $attribute) { if ($attribute->newInstance()->name === $method->name) { (yield $candidate); - continue 2; + break; } } } } }
}
}
}
Expand Down
29 changes: 26 additions & 3 deletions src/Overload.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,24 @@ public static function call(): mixed
throw new \BadMethodCallException(__METHOD__ . '() must be called from a class method.');
}

$class = $trace['class'];
/** @var non-empty-string */
$method = $trace['function'];
$object = $trace['object'] ?? null;
$class = self::resolveClass($trace['class'], $method, $object);

/** @psalm-suppress PossiblyNullFunctionCall, PossiblyNullReference */
return self::$resolverCache
->get($class, $method, static function () use ($class, $method): string {
$reflectionMethod = new \ReflectionMethod($class, $method);
$candidates = CandidatesFinder::findCandidates($reflectionMethod);
$candidates = CandidatesFinder::findCandidates($reflectionMethod, $class);

if ($candidates === []) {
throw new \BadMethodCallException(sprintf('No overloading methods for %s::%s().', $class, $method));
}

return CodeGenerator::generateResolver($reflectionMethod, $candidates);
})
->bindTo($trace['object'] ?? null, $class)
->bindTo($object, $class)
->__invoke($trace['args'] ?? []);
}

Expand All @@ -63,4 +64,26 @@ public static function clearCache(): void
{
self::$resolverCache?->clear();
}

/**
* @param class-string $class
* @param non-empty-string $method
* @return class-string
*/
private static function resolveClass(string $class, string $method, ?object $object): string
{
if ($object === null) {

Check warning on line 75 in src/Overload.php

View workflow job for this annotation

GitHub Actions / infection (8.1)

Escaped Mutant for Mutator "Identical": --- Original +++ New @@ @@ */ private static function resolveClass(string $class, string $method, ?object $object) : string { - if ($object === null) { + if ($object !== null) { return $class; } if ($object::class === $class) {
return $class;
}

if ($object::class === $class) {

Check warning on line 79 in src/Overload.php

View workflow job for this annotation

GitHub Actions / infection (8.1)

Escaped Mutant for Mutator "Identical": --- Original +++ New @@ @@ if ($object === null) { return $class; } - if ($object::class === $class) { + if ($object::class !== $class) { return $class; } if ((new \ReflectionMethod($class, $method))->isPrivate()) {
return $class;
}

if ((new \ReflectionMethod($class, $method))->isPrivate()) {
return $class;
}

return $object::class;
}
}
12 changes: 6 additions & 6 deletions tests/CandidatesFinderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function b(): void {}
};
$method = new \ReflectionMethod($object, 'a');

$candidates = CandidatesFinder::findCandidates($method);
$candidates = CandidatesFinder::findCandidates($method, $object::class);

self::assertSame([], $candidates);
}
Expand All @@ -35,7 +35,7 @@ public function b(): void {}
};
$method = new \ReflectionMethod($object, 'a');

$candidates = CandidatesFinder::findCandidates($method);
$candidates = CandidatesFinder::findCandidates($method, $object::class);

self::assertSame([], $candidates);
}
Expand All @@ -53,7 +53,7 @@ public function c(): void {}
};
$method = new \ReflectionMethod($object, 'a');

$candidates = CandidatesFinder::findCandidates($method);
$candidates = CandidatesFinder::findCandidates($method, $object::class);

self::assertEquals(
[new \ReflectionMethod($object, 'b'), new \ReflectionMethod($object, 'c')],
Expand All @@ -76,7 +76,7 @@ public static function b(): void {}
$object::class,
)));

CandidatesFinder::findCandidates($method);
CandidatesFinder::findCandidates($method, $object::class);
}

public function testItThrowsIfNonStaticOverloadsStatic(): void
Expand All @@ -94,7 +94,7 @@ public function b(): void {}
$object::class,
)));

CandidatesFinder::findCandidates($method);
CandidatesFinder::findCandidates($method, $object::class);
}

/**
Expand Down Expand Up @@ -129,6 +129,6 @@ public function testItThrowsIfVisibilityIsDifferent(string $aVisibility, string
$aVisibility,
)));

CandidatesFinder::findCandidates($method);
CandidatesFinder::findCandidates($method, $object::class);
}
}

0 comments on commit 66c2201

Please sign in to comment.