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

PHP 8.1: Implemented ReflectionMethod/ReflectionFunction::hasTentativeReturnType() and getTentativeReturnType() #817

Merged
merged 1 commit into from
Oct 14, 2021
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
4 changes: 2 additions & 2 deletions src/Reflection/Adapter/ReflectionFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,12 @@ public function getAttributes(?string $name = null, int $flags = 0): array

public function hasTentativeReturnType(): bool
{
throw new Exception\NotImplemented('Not implemented');
return $this->betterReflectionFunction->hasTentativeReturnType();
}

public function getTentativeReturnType(): ?CoreReflectionType
{
throw new Exception\NotImplemented('Not implemented');
return ReflectionType::fromTypeOrNull($this->betterReflectionFunction->getTentativeReturnType());
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Reflection/Adapter/ReflectionMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,12 @@ public function getAttributes(?string $name = null, int $flags = 0): array

public function hasTentativeReturnType(): bool
{
throw new Exception\NotImplemented('Not implemented');
return $this->betterReflectionMethod->hasTentativeReturnType();
}

public function getTentativeReturnType(): ?CoreReflectionType
{
throw new Exception\NotImplemented('Not implemented');
return ReflectionType::fromTypeOrNull($this->betterReflectionMethod->getTentativeReturnType());
}

/**
Expand Down
18 changes: 18 additions & 0 deletions src/Reflection/ReflectionFunctionAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,24 @@ public function hasReturnType(): bool
return $this->node->getReturnType() !== null;
}

public function hasTentativeReturnType(): bool
{
if ($this->isUserDefined()) {
return false;
}

return $this->hasReturnType();
}

public function getTentativeReturnType(): ReflectionNamedType|ReflectionUnionType|null
{
if ($this->isUserDefined()) {
return null;
}

return $this->getReturnType();
}

/**
* Set the return type declaration.
*/
Expand Down
9 changes: 9 additions & 0 deletions src/SourceLocator/SourceStubber/ReflectionSourceStubber.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
use function get_defined_constants;
use function in_array;
use function interface_exists;
use function method_exists;
use function trait_exists;

/**
Expand Down Expand Up @@ -116,6 +117,10 @@ public function generateFunctionStub(string $functionName): ?StubData
$this->addParameters($functionNode, $functionReflection);

$returnType = $functionReflection->getReturnType();
if ($returnType === null && method_exists($functionReflection, 'getTentativeReturnType')) {
$returnType = $functionReflection->getTentativeReturnType();
}

assert($returnType instanceof CoreReflectionNamedType || $returnType instanceof CoreReflectionUnionType || $returnType === null);

if ($returnType !== null) {
Expand Down Expand Up @@ -379,6 +384,10 @@ private function addMethods(Class_|Interface_|Trait_ $classNode, CoreReflectionC
$this->addParameters($methodNode, $methodReflection);

$returnType = $methodReflection->getReturnType();
if ($returnType === null && method_exists($methodReflection, 'getTentativeReturnType')) {
$returnType = $methodReflection->getTentativeReturnType();
}

assert($returnType instanceof CoreReflectionNamedType || $returnType instanceof CoreReflectionUnionType || $returnType === null);

if ($returnType !== null) {
Expand Down
4 changes: 2 additions & 2 deletions test/unit/Reflection/Adapter/ReflectionFunctionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ public function methodExpectationProvider(): array
['isGenerator', null, true, []],
['isVariadic', null, true, []],
['getAttributes', NotImplemented::class, null, []],
['hasTentativeReturnType', NotImplemented::class, null, []],
['getTentativeReturnType', NotImplemented::class, null, []],
['hasTentativeReturnType', null, false, []],
['getTentativeReturnType', null, null, []],
['getClosureUsedVariables', NotImplemented::class, null, []],

// ReflectionFunction
Expand Down
4 changes: 2 additions & 2 deletions test/unit/Reflection/Adapter/ReflectionMethodTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ public function methodExpectationProvider(): array
['isGenerator', null, true, []],
['isVariadic', null, true, []],
['getAttributes', NotImplemented::class, null, []],
['hasTentativeReturnType', NotImplemented::class, null, []],
['getTentativeReturnType', NotImplemented::class, null, []],
['hasTentativeReturnType', null, false, []],
['getTentativeReturnType', null, null, []],
['getClosureUsedVariables', NotImplemented::class, null, []],

// ReflectionMethod
Expand Down
46 changes: 46 additions & 0 deletions test/unit/Reflection/ReflectionFunctionAbstractTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PhpParser\Parser;
use PhpParser\PrettyPrinter\Standard as StandardPrettyPrinter;
use PHPUnit\Framework\TestCase;
use ReflectionClass as CoreReflectionClass;
use Roave\BetterReflection\Reflection\Exception\InvalidArrowFunctionBodyNode;
use Roave\BetterReflection\Reflection\Exception\Uncloneable;
use Roave\BetterReflection\Reflection\ReflectionFunction;
Expand All @@ -24,7 +25,9 @@
use Roave\BetterReflection\Reflector\DefaultReflector;
use Roave\BetterReflection\SourceLocator\Ast\Locator;
use Roave\BetterReflection\SourceLocator\Located\LocatedSource;
use Roave\BetterReflection\SourceLocator\SourceStubber\ReflectionSourceStubber;
use Roave\BetterReflection\SourceLocator\Type\ClosureSourceLocator;
use Roave\BetterReflection\SourceLocator\Type\PhpInternalSourceLocator;
use Roave\BetterReflection\SourceLocator\Type\SingleFileSourceLocator;
use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator;
use Roave\BetterReflectionTest\BetterReflectionSingleton;
Expand Down Expand Up @@ -501,6 +504,49 @@ public function testRemoveReturnType(): void
self::assertStringNotContainsString(': string', (new StandardPrettyPrinter())->prettyPrint([$functionInfo->getAst()]));
}

/**
* @requires PHP >= 8.1
*/
public function testHasTentativeReturnType(): void
{
$classInfo = (new DefaultReflector(new PhpInternalSourceLocator($this->astLocator, new ReflectionSourceStubber())))->reflectClass(CoreReflectionClass::class);
$methodInfo = $classInfo->getMethod('getName');

self::assertTrue($methodInfo->hasTentativeReturnType());
}

public function testHasNotTentativeReturnType(): void
{
$functionInfo = (new DefaultReflector(
new SingleFileSourceLocator(__DIR__ . '/../Fixture/Php7ReturnTypeDeclarations.php', $this->astLocator),
))->reflectFunction('returnsString');

self::assertFalse($functionInfo->hasTentativeReturnType());
}

/**
* @requires PHP >= 8.1
*/
public function testGetTentativeReturnType(): void
{
$classInfo = (new DefaultReflector(new PhpInternalSourceLocator($this->astLocator, new ReflectionSourceStubber())))->reflectClass(CoreReflectionClass::class);
$methodInfo = $classInfo->getMethod('getName');

$returnType = $methodInfo->getTentativeReturnType();

self::assertNotNull($returnType);
self::assertSame('string', $returnType->__toString());
}

public function testNoTentativeReturnType(): void
{
$functionInfo = (new DefaultReflector(
new SingleFileSourceLocator(__DIR__ . '/../Fixture/Php7ReturnTypeDeclarations.php', $this->astLocator),
))->reflectFunction('returnsString');

self::assertNull($functionInfo->getTentativeReturnType());
}

public function testCannotClone(): void
{
$php = '<?php function foo() {}';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use function get_declared_traits;
use function get_defined_functions;
use function in_array;
use function method_exists;
use function sort;

/**
Expand Down Expand Up @@ -307,7 +308,13 @@ private function assertSameMethodAttributes(CoreReflectionMethod $original, Refl
self::assertSame($original->isAbstract(), $stubbed->isAbstract());
self::assertSame($original->isDeprecated(), $stubbed->isDeprecated());

self::assertSame((string) $original->getReturnType(), (string) $stubbed->getReturnType());
if (method_exists($original, 'hasTentativeReturnType') && $original->hasTentativeReturnType()) {
self::assertSame($original->hasTentativeReturnType(), $stubbed->hasTentativeReturnType());
self::assertSame((string) $original->getTentativeReturnType(), (string) $stubbed->getTentativeReturnType());
} else {
self::assertSame($original->hasReturnType(), $stubbed->hasReturnType());
self::assertSame((string) $original->getReturnType(), (string) $stubbed->getReturnType());
}
}

private function assertSameParameterAttributes(
Expand Down Expand Up @@ -377,7 +384,13 @@ public function testInternalFunctionsReturnType(string $functionName): void
$stubbedReflection = $this->reflector->reflectFunction($functionName);
$originalReflection = new CoreReflectionFunction($functionName);

self::assertSame((string) $originalReflection->getReturnType(), (string) $stubbedReflection->getReturnType());
if (method_exists($originalReflection, 'hasTentativeReturnType') && $originalReflection->hasTentativeReturnType()) {
self::assertSame($originalReflection->hasTentativeReturnType(), $stubbedReflection->hasTentativeReturnType());
self::assertSame((string) $originalReflection->getTentativeReturnType(), (string) $stubbedReflection->getTentativeReturnType());
} else {
self::assertSame($originalReflection->hasReturnType(), $stubbedReflection->hasReturnType());
self::assertSame((string) $originalReflection->getReturnType(), (string) $stubbedReflection->getReturnType());
}
}

public function testFunctionWithParameterPassedByReference(): void
Expand Down