Repository: Roave/BetterReflection (php)

Issue:
ReflectionNamedType adapter does not fulfil its purpose
Hi,
I just found out that the ReflectionNamedType adapter implemented in #528 does not work as it should.

1) `ReflectionNamedType::fromReturnTypeOrNull()` still returned `ReflectionType` because the method didn't use `new static`, nor was overriden in ReflectionNamedType.
2) BR's ReflectionNamedType adapter class must extend `\ReflectionNamedType` from PHP, otherwise it doesn't work as a fully-fledged adapter, it cannot be used where `\ReflectionNamedType` is typehinted.

PoC of a fix: https://github.com/ondrejmirtes/BetterReflection/commit/65ff59911be6a81f4420364f888d2f32ae93c6f4 (I just copied and adjusted Adapter\ReflectionType). Notice also the mistake in ReflectionProperty::getType() which looks like untested code.

/cc @kukulich 

Pull request description:
Fixed ReflectionNamedType adapter
Fixes #556 

Credit to @ondrejmirtes 

Patch:
diff --git a/src/Reflection/Adapter/ReflectionNamedType.php b/src/Reflection/Adapter/ReflectionNamedType.php
index 52152891..a33c55e6 100644
--- a/src/Reflection/Adapter/ReflectionNamedType.php
+++ b/src/Reflection/Adapter/ReflectionNamedType.php
@@ -4,22 +4,51 @@ declare(strict_types=1);
 
 namespace Roave\BetterReflection\Reflection\Adapter;
 
+use ReflectionNamedType as CoreReflectionNamedType;
 use Roave\BetterReflection\Reflection\ReflectionType as BetterReflectionType;
 
-class ReflectionNamedType extends ReflectionType
+class ReflectionNamedType extends CoreReflectionNamedType
 {
     /** @var BetterReflectionType */
     private $betterReflectionType;
 
     public function __construct(BetterReflectionType $betterReflectionType)
     {
-        parent::__construct($betterReflectionType);
-
         $this->betterReflectionType = $betterReflectionType;
     }
 
-    public function getName()
+    public static function fromReturnTypeOrNull(?BetterReflectionType $betterReflectionType) : ?self
+    {
+        if ($betterReflectionType === null) {
+            return null;
+        }
+
+        return new self($betterReflectionType);
+    }
+
+    public function getName() : string
     {
         return $this->betterReflectionType->getName();
     }
+
+    public function __toString() : string
+    {
+        return $this->betterReflectionType->__toString();
+    }
+
+    public function allowsNull() : bool
+    {
+        return $this->betterReflectionType->allowsNull();
+    }
+
+    public function isBuiltin() : bool
+    {
+        $type = (string) $this->betterReflectionType;
+
+        if ($type === 'self' || $type === 'parent') {
+            return false;
+        }
+
+        return $this->betterReflectionType->isBuiltin();
+    }
 }
diff --git a/src/Reflection/Adapter/ReflectionProperty.php b/src/Reflection/Adapter/ReflectionProperty.php
index e80a9e6f..36502d20 100644
--- a/src/Reflection/Adapter/ReflectionProperty.php
+++ b/src/Reflection/Adapter/ReflectionProperty.php
@@ -100,7 +100,7 @@ class ReflectionProperty extends CoreReflectionProperty
      */
     public function getType()
     {
-        return ReflectionType::fromReturnTypeOrNull($this->betterReflectionProperty->getType());
+        return ReflectionNamedType::fromReturnTypeOrNull($this->betterReflectionProperty->getType());
     }
 
     /**


Test patch:
diff --git a/test/unit/Reflection/Adapter/ReflectionMethodTest.php b/test/unit/Reflection/Adapter/ReflectionMethodTest.php
index 95e4200c..e92e9941 100644
--- a/test/unit/Reflection/Adapter/ReflectionMethodTest.php
+++ b/test/unit/Reflection/Adapter/ReflectionMethodTest.php
@@ -11,8 +11,8 @@ use ReflectionMethod as CoreReflectionMethod;
 use Roave\BetterReflection\Reflection\Adapter\Exception\NotImplemented;
 use Roave\BetterReflection\Reflection\Adapter\ReflectionClass as ReflectionClassAdapter;
 use Roave\BetterReflection\Reflection\Adapter\ReflectionMethod as ReflectionMethodAdapter;
+use Roave\BetterReflection\Reflection\Adapter\ReflectionNamedType as ReflectionNamedTypeAdapter;
 use Roave\BetterReflection\Reflection\Adapter\ReflectionParameter as ReflectionParameterAdapter;
-use Roave\BetterReflection\Reflection\Adapter\ReflectionType as ReflectionTypeAdapter;
 use Roave\BetterReflection\Reflection\Exception\NoObjectProvided;
 use Roave\BetterReflection\Reflection\Exception\NotAnObject;
 use Roave\BetterReflection\Reflection\Exception\ObjectNotInstanceOfClass;
@@ -133,7 +133,7 @@ class ReflectionMethodTest extends TestCase
                 break;
 
             case 'getReturnType':
-                self::assertInstanceOf(ReflectionTypeAdapter::class, $adapterReturnValue);
+                self::assertInstanceOf(ReflectionNamedTypeAdapter::class, $adapterReturnValue);
                 break;
 
             case 'getPrototype':
diff --git a/test/unit/Reflection/Adapter/ReflectionNamedTypeTest.php b/test/unit/Reflection/Adapter/ReflectionNamedTypeTest.php
index f096b550..5ce03e1d 100644
--- a/test/unit/Reflection/Adapter/ReflectionNamedTypeTest.php
+++ b/test/unit/Reflection/Adapter/ReflectionNamedTypeTest.php
@@ -70,4 +70,11 @@ class ReflectionNamedTypeTest extends TestCase
         $adapter = new ReflectionNamedTypeAdapter($reflectionStub);
         $adapter->{$methodName}(...$args);
     }
+
+    public function testIsInstanceOfCoreReflectionType() : void
+    {
+        $reflectionStub = $this->createMock(BetterReflectionType::class);
+        $adapter        = ReflectionNamedTypeAdapter::fromReturnTypeOrNull($reflectionStub);
+        $this->assertInstanceOf(CoreReflectionNamedType::class, $adapter);
+    }
 }