Repository: Roave/BetterReflection (php)

Issue:
ReflectionClass::getImmediateInterfaces() returns parent interfaces
Version: 4.3.0

`ReflectionClass::getImmediateInterfaces()` intends to `Get only the interfaces that this class implements (i.e. do not search up parent classes etc.)` but actually returns parent implemented interfaces.

Given I have following code I want to be analysed:
```php
<?php

require_once 'vendor/autoload.php';

use Roave\BetterReflection\BetterReflection;
use Roave\BetterReflection\Reflector\ClassReflector;
use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator;

$code = <<<PHP
<?php
    namespace Tests\SensioLabs\Deptrac\AstRunner\Fixtures\BasicInheritance;

    interface FixtureBasicInheritanceInterfaceA { }
    interface FixtureBasicInheritanceInterfaceB extends FixtureBasicInheritanceInterfaceA { }
    interface FixtureBasicInheritanceInterfaceC extends FixtureBasicInheritanceInterfaceB { }
    interface FixtureBasicInheritanceInterfaceD extends FixtureBasicInheritanceInterfaceC { }
    interface FixtureBasicInheritanceInterfaceE extends FixtureBasicInheritanceInterfaceD { }
PHP;

$reflector = new ClassReflector(new StringSourceLocator($code, (new BetterReflection())->astLocator()));
print_r(
    array_keys(
        $reflector->reflect(
            'Tests\SensioLabs\Deptrac\AstRunner\Fixtures\BasicInheritance\FixtureBasicInheritanceInterfaceE'
        )->getImmediateInterfaces()
    )
);

```

I would expect only `FixtureBasicInheritanceInterfaceD` to be returned but currently following is returned:
```
Array
(
    [0] => Tests\SensioLabs\Deptrac\AstRunner\Fixtures\BasicInheritance\FixtureBasicInheritanceInterfaceD
    [1] => Tests\SensioLabs\Deptrac\AstRunner\Fixtures\BasicInheritance\FixtureBasicInheritanceInterfaceC
    [2] => Tests\SensioLabs\Deptrac\AstRunner\Fixtures\BasicInheritance\FixtureBasicInheritanceInterfaceB
    [3] => Tests\SensioLabs\Deptrac\AstRunner\Fixtures\BasicInheritance\FixtureBasicInheritanceInterfaceA
)
```

Pull request description:
Fixed `ReflectionClass::getImmediateInterfaces()` to only return immediately implemented interfaces
Fixes #643 

Patch:
diff --git a/docs/usage.md b/docs/usage.md
index 54a968e9..b8b238a0 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -266,7 +266,7 @@ $functions = $reflector->getAllFunctions();
 
 ### Reflecting a Closure
 
-The `ReflectionFunction` class has a static constructor which you can reflect directly on a closure:
+The `ReflectionFunction` class has a static constructor which you can reflectdirectly on a closure:
 
 ```php
 <?php
diff --git a/src/Reflection/ReflectionClass.php b/src/Reflection/ReflectionClass.php
index c619efaf..5a2563f3 100644
--- a/src/Reflection/ReflectionClass.php
+++ b/src/Reflection/ReflectionClass.php
@@ -1089,7 +1089,28 @@ class ReflectionClass implements Reflection
      */
     public function getImmediateInterfaces() : array
     {
-        return $this->getCurrentClassImplementedInterfacesIndexedByName();
+        if ($this->isTrait()) {
+            return [];
+        }
+
+        assert($this->node instanceof ClassNode || $this->node instanceof InterfaceNode);
+
+        $nodes = $this->node instanceof InterfaceNode ? $this->node->extends : $this->node->implements;
+
+        return array_combine(
+            array_map(
+                static function (Node\Name $interfaceName) : string {
+                    return $interfaceName->toString();
+                },
+                $nodes,
+            ),
+            array_map(
+                function (Node\Name $interfaceName) : ReflectionClass {
+                    return $this->reflectClassForNamedNode($interfaceName);
+                },
+                $nodes,
+            ),
+        );
     }
 
     /**
diff --git a/src/SourceLocator/Type/AutoloadSourceLocator.php b/src/SourceLocator/Type/AutoloadSourceLocator.php
index 0afd76dd..64a6c284 100644
--- a/src/SourceLocator/Type/AutoloadSourceLocator.php
+++ b/src/SourceLocator/Type/AutoloadSourceLocator.php
@@ -203,7 +203,7 @@ class AutoloadSourceLocator extends AbstractSourceLocator
     /**
      * We can only load constants if they already exist, because PHP does not
      * have constant autoloading. Therefore if it exists, we simply use brute force
-     * to search throughout all included files to find the right filename.
+     * to search throught all included files to find the right filename.
      */
     private function locateConstantByName(string $constantName) : ?string
     {


Test patch:
diff --git a/test/unit/Fixture/ClassesWithPublicOrNonPublicConstructor.php b/test/unit/Fixture/ClassesWithPublicOrNonPublicContructor.php
similarity index 96%
rename from test/unit/Fixture/ClassesWithPublicOrNonPublicConstructor.php
rename to test/unit/Fixture/ClassesWithPublicOrNonPublicContructor.php
index 1de3ccc1..2960f5ac 100644
--- a/test/unit/Fixture/ClassesWithPublicOrNonPublicConstructor.php
+++ b/test/unit/Fixture/ClassesWithPublicOrNonPublicContructor.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicConstructor;
+namespace Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicContructor;
 
 
 class ClassWithPublicConstructor
diff --git a/test/unit/Fixture/PrototypeTree.php b/test/unit/Fixture/PrototypeTree.php
index 4d5b1248..a938c494 100644
--- a/test/unit/Fixture/PrototypeTree.php
+++ b/test/unit/Fixture/PrototypeTree.php
@@ -138,7 +138,8 @@ namespace Foom {
 namespace Boom {
     interface Foo {}
     interface Bar {}
+    interface Boo extends Bar {}
 
     class A implements Foo {}
-    class B extends A implements Bar {}
+    class B extends A implements Boo {}
 }
diff --git a/test/unit/Reflection/Adapter/ReflectionPropertyTest.php b/test/unit/Reflection/Adapter/ReflectionPropertyTest.php
index 16d0d454..dfc30a07 100644
--- a/test/unit/Reflection/Adapter/ReflectionPropertyTest.php
+++ b/test/unit/Reflection/Adapter/ReflectionPropertyTest.php
@@ -39,7 +39,7 @@ class ReflectionPropertyTest extends TestCase
     /**
      * @dataProvider coreReflectionPropertyNamesProvider
      */
-    public function testCoreReflectionProperties(string $methodName) : void
+    public function testCoreReflectionPropertys(string $methodName) : void
     {
         $reflectionPropertyAdapterReflection = new CoreReflectionClass(ReflectionPropertyAdapter::class);
         self::assertTrue($reflectionPropertyAdapterReflection->hasMethod($methodName));
diff --git a/test/unit/Reflection/ReflectionClassConstantTest.php b/test/unit/Reflection/ReflectionClassConstantTest.php
index 9334758f..0e71fb65 100644
--- a/test/unit/Reflection/ReflectionClassConstantTest.php
+++ b/test/unit/Reflection/ReflectionClassConstantTest.php
@@ -121,7 +121,7 @@ class ReflectionClassConstantTest extends TestCase
         ];
     }
 
-    public function columnsProvider() : array
+    public function columsProvider() : array
     {
         return [
             ["<?php\n\nclass T {\nconst TEST = 1;}", 1, 15],
@@ -131,7 +131,7 @@ class ReflectionClassConstantTest extends TestCase
     }
 
     /**
-     * @dataProvider columnsProvider
+     * @dataProvider columsProvider
      */
     public function testGetStartColumnAndEndColumn(string $php, int $startColumn, int $endColumn) : void
     {
diff --git a/test/unit/Reflection/ReflectionClassTest.php b/test/unit/Reflection/ReflectionClassTest.php
index 0cb888e0..ed080e3b 100644
--- a/test/unit/Reflection/ReflectionClassTest.php
+++ b/test/unit/Reflection/ReflectionClassTest.php
@@ -35,11 +35,11 @@ use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator;
 use Roave\BetterReflectionTest\BetterReflectionSingleton;
 use Roave\BetterReflectionTest\ClassesImplementingIterators;
 use Roave\BetterReflectionTest\ClassesWithCloneMethod;
-use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicConstructor\ClassWithExtendedConstructor;
-use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicConstructor\ClassWithoutConstructor;
-use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicConstructor\ClassWithPrivateConstructor;
-use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicConstructor\ClassWithProtectedConstructor;
-use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicConstructor\ClassWithPublicConstructor;
+use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicContructor\ClassWithExtendedConstructor;
+use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicContructor\ClassWithoutConstructor;
+use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicContructor\ClassWithPrivateConstructor;
+use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicContructor\ClassWithProtectedConstructor;
+use Roave\BetterReflectionTest\ClassesWithPublicOrNonPublicContructor\ClassWithPublicConstructor;
 use Roave\BetterReflectionTest\ClassWithInterfaces;
 use Roave\BetterReflectionTest\ClassWithInterfacesExtendingInterfaces;
 use Roave\BetterReflectionTest\ClassWithInterfacesOther;
@@ -626,7 +626,7 @@ PHP;
         self::assertStringContainsString('Some comments here', $classInfo->getDocComment());
     }
 
-    public function testGetDocCommentBetweenComments() : void
+    public function testGetDocCommentBetweeenComments() : void
     {
         $php       = '<?php
             /* A comment */
@@ -1335,7 +1335,7 @@ PHP;
         self::assertFalse($reflector->reflect(ExampleInterface::class)->isInstantiable());
 
         $reflector = new ClassReflector(new SingleFileSourceLocator(
-            __DIR__ . '/../Fixture/ClassesWithPublicOrNonPublicConstructor.php',
+            __DIR__ . '/../Fixture/ClassesWithPublicOrNonPublicContructor.php',
             $this->astLocator,
         ));
 
@@ -1465,8 +1465,8 @@ PHP;
         $interfaces = $reflector->reflect('Boom\B')->getImmediateInterfaces();
 
         self::assertCount(1, $interfaces);
-        self::assertInstanceOf(ReflectionClass::class, $interfaces['Boom\Bar']);
-        self::assertSame('Boom\Bar', $interfaces['Boom\Bar']->getName());
+        self::assertInstanceOf(ReflectionClass::class, $interfaces['Boom\Boo']);
+        self::assertSame('Boom\Boo', $interfaces['Boom\Boo']->getName());
     }
 
     public function testGetImmediateInterfacesDoesNotIncludeCurrentInterface() : void
@@ -1493,7 +1493,7 @@ PHP;
         sort($dInterfaces);
 
         self::assertSame(['B'], $cInterfaces);
-        self::assertSame(['A', 'B', 'C'], $dInterfaces);
+        self::assertSame(['A', 'C'], $dInterfaces);
     }
 
     public function testReflectedTraitHasNoInterfaces() : void
diff --git a/test/unit/Reflection/ReflectionPropertyTest.php b/test/unit/Reflection/ReflectionPropertyTest.php
index a0ed227d..f603389e 100644
--- a/test/unit/Reflection/ReflectionPropertyTest.php
+++ b/test/unit/Reflection/ReflectionPropertyTest.php
@@ -161,7 +161,7 @@ class ReflectionPropertyTest extends TestCase
         self::assertSame($expectedDoc, $property->getDocComment());
     }
 
-    public function testGetDocCommentBetweenComments() : void
+    public function testGetDocCommentBetweeenComments() : void
     {
         $php       = '<?php
             class Bar implements Foo {
@@ -325,7 +325,7 @@ class ReflectionPropertyTest extends TestCase
         ];
     }
 
-    public function columnsProvider() : array
+    public function columsProvider() : array
     {
         return [
             ["<?php\n\nclass T {\npublic \$test = 1;\n}", 1, 17],
@@ -335,7 +335,7 @@ class ReflectionPropertyTest extends TestCase
     }
 
     /**
-     * @dataProvider columnsProvider
+     * @dataProvider columsProvider
      */
     public function testGetStartColumnAndEndColumn(string $php, int $startColumn, int $endColumn) : void
     {
diff --git a/test/unit/SourceLocator/Ast/LocatorTest.php b/test/unit/SourceLocator/Ast/LocatorTest.php
index 7f48ac4b..b4324e95 100644
--- a/test/unit/SourceLocator/Ast/LocatorTest.php
+++ b/test/unit/SourceLocator/Ast/LocatorTest.php
@@ -135,7 +135,7 @@ class LocatorTest extends TestCase
         self::assertInstanceOf(ReflectionConstant::class, $constantInfo);
     }
 
-    public function testReflectThrowsExceptionWhenClassNotFoundAndNoNodesExist() : void
+    public function testReflectThrowsExeptionWhenClassNotFoundAndNoNodesExist() : void
     {
         $php = '<?php';
 
@@ -147,7 +147,7 @@ class LocatorTest extends TestCase
         );
     }
 
-    public function testReflectThrowsExceptionWhenClassNotFoundButNodesExist() : void
+    public function testReflectThrowsExeptionWhenClassNotFoundButNodesExist() : void
     {
         $php = "<?php
         namespace Foo;
diff --git a/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php b/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php
index 534c98c5..10bb560e 100644
--- a/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php
+++ b/test/unit/SourceLocator/SourceStubber/ReflectionSourceStubberTest.php
@@ -303,7 +303,7 @@ class ReflectionSourceStubberTest extends TestCase
         if (! in_array($parameterName, ['mysqli_stmt#bind_param.vars', 'mysqli_stmt#bind_result.vars'], true)
             && ! preg_match('~^RedisCluster#\w+.arg$~', $parameterName)
         ) {
-            // Parameters are variadic but not optional
+            // Parameters are variadic but not optinal
             self::assertSame($original->isOptional(), $stubbed->isOptional(), $parameterName);
         }
 
diff --git a/test/unit/SourceLocator/Type/MemoizingSourceLocatorTest.php b/test/unit/SourceLocator/Type/MemoizingSourceLocatorTest.php
index 1ae5d31a..fe74985e 100644
--- a/test/unit/SourceLocator/Type/MemoizingSourceLocatorTest.php
+++ b/test/unit/SourceLocator/Type/MemoizingSourceLocatorTest.php
@@ -54,7 +54,7 @@ class MemoizingSourceLocatorTest extends TestCase
         $this->memoizingLocator = new MemoizingSourceLocator($this->wrappedLocator);
         $this->identifierNames  = array_unique(array_map(
             static function () : string {
-                return uniqid('identifier', true);
+                return uniqid('identifer', true);
             },
             range(1, 20),
         ));