Skip to content

Commit

Permalink
Implemented ReflectionMethod/ReflectionFunction::hasTentativeReturnTy…
Browse files Browse the repository at this point in the history
…pe() and getTentativeReturnType()
  • Loading branch information
kukulich committed Sep 27, 2021
1 parent 943ad3a commit e258f6d
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 10 deletions.
4 changes: 2 additions & 2 deletions src/Reflection/Adapter/ReflectionFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,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 @@ -302,12 +302,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 @@ -379,6 +379,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: 7 additions & 2 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 @@ -115,7 +116,9 @@ public function generateFunctionStub(string $functionName): ?StubData
$this->addDocComment($functionNode, $functionReflection);
$this->addParameters($functionNode, $functionReflection);

$returnType = $functionReflection->getReturnType();
$returnType = method_exists($functionReflection, 'getTentativeReturnType')
? $functionReflection->getTentativeReturnType()
: $functionReflection->getReturnType();
assert($returnType instanceof CoreReflectionNamedType || $returnType instanceof CoreReflectionUnionType || $returnType === null);

if ($returnType !== null) {
Expand Down Expand Up @@ -368,7 +371,9 @@ private function addMethods(Class_|Interface_|Trait_ $classNode, CoreReflectionC
$this->addDocComment($methodNode, $methodReflection);
$this->addParameters($methodNode, $methodReflection);

$returnType = $methodReflection->getReturnType();
$returnType = method_exists($methodReflection, 'getTentativeReturnType')
? $methodReflection->getTentativeReturnType()
: $methodReflection->getReturnType();
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\Reflector;
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 Reflector(new PhpInternalSourceLocator($this->astLocator, new ReflectionSourceStubber())))->reflectClass(CoreReflectionClass::class);
$methodInfo = $classInfo->getMethod('getName');

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

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

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

/**
* @requires PHP >= 8.1
*/
public function testGetTentativeReturnType(): void
{
$classInfo = (new Reflector(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 Reflector(
new SingleFileSourceLocator(__DIR__ . '/../Fixture/Php7ReturnTypeDeclarations.php', $this->astLocator),
))->reflectFunction('returnsString');

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

public function testCannotClone(): void
{
$php = '<?php function foo() {}';
Expand Down

0 comments on commit e258f6d

Please sign in to comment.