Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate code for never return type #21

Merged
merged 1 commit into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public static function generate(string $returnedValueExpression, ?ReflectionMeth
return $returnedValueExpression . ";\nreturn;";
}

if ($originalReturnType instanceof ReflectionNamedType && $originalReturnType->getName() === 'never') {
return $returnedValueExpression . ';';
}

return 'return ' . $returnedValueExpression . ';';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
use ProxyManagerTestAsset\ClassWithReadOnlyProperties;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\EmptyClass;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\OtherObjectAccessClass;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionClass;
use ReflectionProperty;
use RuntimeException;
use stdClass;

use function array_key_exists;
Expand Down Expand Up @@ -1586,6 +1588,45 @@ static function (
self::assertSame($initialCounter + $increment, $proxy->counter);
}

/**
* @requires PHP 8.1
*
* @psalm-suppress UnusedVariable this method uses by-ref assignment of properties, and isn't recognized by static analysis
* @psalm-suppress UndefinedClass Class, interface or enum named never does not exist
*/
public function testWillExecuteLogicInANeverMethod(): void
{
$initialCounter = random_int(10, 1000);

$proxy = (new LazyLoadingGhostFactory())->createProxy(
NeverCounter::class,
static function (
LazyLoadingInterface $proxy,
string $method,
array $params,
?Closure & $initializer,
array $properties
) use ($initialCounter): bool {
$initializer = null;

$properties['counter'] = $initialCounter;

return true;
}
);

$increment = random_int(1001, 10000);

try {
$proxy->increment($increment);
$this->fail('RuntimeException expected');
} catch (RuntimeException $e) {
// Nothing to do
}

self::assertSame($initialCounter + $increment, $proxy->counter);
}

private static function isPropertyInitialized($object, ReflectionProperty $property): bool
{
return array_key_exists(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
use ProxyManagerTestAsset\ClassWithPublicStringTypedProperty;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\EmptyClass;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\OtherObjectAccessClass;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionClass;
use ReflectionProperty;
use RuntimeException;
use stdClass;

use function array_values;
Expand Down Expand Up @@ -695,6 +697,30 @@ public function testWillExecuteLogicInAVoidMethod(): void
self::assertSame($increment, $proxy->counter);
}

/**
* @requires PHP 8.1
*
* @psalm-suppress UndefinedClass Class, interface or enum named never does not exist
*/
public function testWillExecuteLogicInANeverMethod(): void
{
$proxy = (new LazyLoadingValueHolderFactory())->createProxy(
NeverCounter::class,
$this->createInitializer(NeverCounter::class, new NeverCounter())
);

$increment = random_int(100, 1000);

try {
$proxy->increment($increment);
$this->fail('RuntimeException expected');
} catch (RuntimeException $e) {
// Do nothing
}

self::assertSame($increment, $proxy->counter);
}

public function getMethodsThatAccessPropertiesOnOtherObjectsInTheSameScope(): Generator
{
foreach ((new ReflectionClass(OtherObjectAccessClass::class))->getProperties() as $property) {
Expand Down
16 changes: 16 additions & 0 deletions tests/ProxyManagerTest/Functional/NullObjectFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
use ProxyManagerTestAsset\ClassWithPublicStringTypedProperty;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\EmptyClass;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionProperty;
use stdClass;
use TypeError;

use function array_values;
use function assert;
Expand Down Expand Up @@ -126,6 +128,20 @@ public function testPropertyUnset(NullObjectInterface $proxy, string $publicProp
self::assertFalse(isset($proxy->$publicProperty));
}

/**
* @requires PHP 8.1
*/
public function testNeverReturningMethodCalls(): void
{
$proxy = (new NullObjectFactory())->createProxy(NeverCounter::class);
$method = [$proxy, 'increment'];

self::assertIsCallable($method);

$this->expectException(TypeError::class);
$method(random_int(10, 1000));
}

/**
* Generates a list of object | invoked method | parameters | expected result
*
Expand Down
26 changes: 26 additions & 0 deletions tests/ProxyManagerTest/Functional/RemoteObjectFunctionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use ProxyManagerTestAsset\ClassWithPublicStringNullableTypedProperty;
use ProxyManagerTestAsset\ClassWithPublicStringTypedProperty;
use ProxyManagerTestAsset\ClassWithSelfHint;
use ProxyManagerTestAsset\NeverCounter;
use ProxyManagerTestAsset\OtherObjectAccessClass;
use ProxyManagerTestAsset\RemoteProxy\BazServiceInterface;
use ProxyManagerTestAsset\RemoteProxy\Foo;
Expand All @@ -26,6 +27,7 @@
use ProxyManagerTestAsset\RemoteProxy\VariadicArgumentsServiceInterface;
use ProxyManagerTestAsset\VoidCounter;
use ReflectionClass;
use RuntimeException;
use stdClass;

use function assert;
Expand Down Expand Up @@ -403,6 +405,30 @@ public function testWillExecuteLogicInAVoidMethod(): void
$proxy->increment($increment);
}

/**
* @requires PHP 8.1
*/
public function testWillExecuteLogicInANeverMethod(): void
{
$adapter = $this->createMock(AdapterInterface::class);

$increment = random_int(10, 1000);

$adapter
->expects(self::once())
->method('call')
->with(NeverCounter::class, 'increment', [$increment])
->willThrowException(new RuntimeException());

$proxy = clone (new RemoteObjectFactory($adapter))
->createProxy(NeverCounter::class);

$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('');

$proxy->increment($increment);
}

public function getMethodsThatAccessPropertiesOnOtherObjectsInTheSameScope(): Generator
{
foreach ((new ReflectionClass(OtherObjectAccessClass::class))->getProperties() as $property) {
Expand Down
21 changes: 21 additions & 0 deletions tests/ProxyManagerTestAsset/NeverCounter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace ProxyManagerTestAsset;

use RuntimeException;

class NeverCounter
{
/**
* @var int
*/
public $counter = 0;

public function increment(int $amount) : never
{
$this->counter += $amount;
throw new RuntimeException();
}
}