1
0
mirror of https://github.com/rectorphp/rector.git synced 2025-04-14 04:22:17 +02:00

[NodeTypeResolver] Fix missing parent traits in class reflection types

This commit is contained in:
Tomas Votruba 2018-08-09 11:23:57 +02:00
parent 24c6cc3d9f
commit f3348c84d8
13 changed files with 164 additions and 48 deletions
packages

@ -2,10 +2,21 @@
namespace Rector\NodeTypeResolver\Reflection;
use PHPStan\Broker\Broker;
use PHPStan\Reflection\ClassReflection;
final class ClassReflectionTypesResolver
{
/**
* @var Broker
*/
private $broker;
public function __construct(Broker $broker)
{
$this->broker = $broker;
}
/**
* @return string[]
*/
@ -30,6 +41,15 @@ final class ClassReflectionTypesResolver
$types[] = $classReflection->getName();
}
// to cover traits of parent classes
foreach ($classReflection->getParentClassesNames() as $parentClassName) {
$parentClassReflection = $this->broker->getClass($parentClassName);
foreach ($parentClassReflection->getTraits() as $parentClassTrait) {
$types[] = $parentClassTrait->getName();
}
}
return $types;
}
}

@ -0,0 +1,50 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver;
use Iterator;
use PhpParser\Node\Stmt\Class_;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\AbstractNodeTypeResolverTest;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source\AnotherTrait;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source\ClassWithParentClass;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source\ClassWithParentInterface;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source\ClassWithParentTrait;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source\ClassWithTrait;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source\ParentClass;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source\SomeInterface;
/**
* @covers \Rector\NodeTypeResolver\PerNodeTypeResolver\ClassAndInterfaceTypeResolver
*/
final class ClassAndInterfaceTypeResolverTest extends AbstractNodeTypeResolverTest
{
/**
* @dataProvider dataProvider()
* @param string[] $expectedTypes
*/
public function test(string $file, int $nodePosition, array $expectedTypes): void
{
$variableNodes = $this->getNodesForFileOfType($file, Class_::class);
$this->assertSame($expectedTypes, $this->nodeTypeResolver->resolve($variableNodes[$nodePosition]));
}
public function dataProvider(): Iterator
{
// yield [__DIR__ . '/Source/ClassWithParentInterface.php', 0, [
// ClassWithParentInterface::class,
// SomeInterface::class,
// ]];
//
// yield [__DIR__ . '/Source/ClassWithParentClass.php', 0, [
// ClassWithParentClass::class,
// ParentClass::class,
// ]];
// yield [__DIR__ . '/Source/ClassWithTrait.php', 0, [ClassWithTrait::class, AnotherTrait::class]];
yield [__DIR__ . '/Source/ClassWithParentTrait.php', 0, [ClassWithParentTrait::class, ClassWithTrait::class, AnotherTrait::class]];
// yield [__DIR__ . '/Source/AnonymousClass.php', 0, [ParentClass::class, SomeInterface::class]];
}
}

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
new class extends ParentClass implements SomeInterface
{
use AnotherTrait;
};

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
trait AnotherTrait
{
}

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
final class ClassWithParentClass extends ParentClass
{
}

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
final class ClassWithParentInterface implements SomeInterface
{
}

@ -0,0 +1,7 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
class ClassWithParentTrait extends ClassWithTrait
{
}

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
class ClassWithTrait
{
use AnotherTrait;
}

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
class ParentClass
{
}

@ -0,0 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassAndInterfaceTypeResolver\Source;
interface SomeInterface
{
}

@ -1,48 +0,0 @@
<?php declare(strict_types=1);
namespace Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassTypeResolver;
use Iterator;
use PhpParser\Node\Stmt\Class_;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\AbstractNodeTypeResolverTest;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassTypeResolver\Source\AnotherTrait;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassTypeResolver\Source\ClassWithParentClass;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassTypeResolver\Source\ClassWithParentInterface;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassTypeResolver\Source\ClassWithTrait;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassTypeResolver\Source\ParentClass;
use Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ClassTypeResolver\Source\SomeInterface;
/**
* @covers \Rector\NodeTypeResolver\PerNodeTypeResolver\ClassTypeResolver
*/
final class ClassTypeResolverTest extends AbstractNodeTypeResolverTest
{
/**
* @dataProvider dataProvider()
* @param string[] $expectedTypes
*/
public function test(string $file, int $nodePosition, array $expectedTypes): void
{
$variableNodes = $this->getNodesForFileOfType($file, Class_::class);
$this->assertSame($expectedTypes, $this->nodeTypeResolver->resolve($variableNodes[$nodePosition]));
}
public function dataProvider(): Iterator
{
yield [__DIR__ . '/Source/ClassWithParentInterface.php', 0, [
ClassWithParentInterface::class,
SomeInterface::class,
]];
yield [__DIR__ . '/Source/ClassWithParentClass.php', 0, [
ClassWithParentClass::class,
ParentClass::class,
]];
yield [__DIR__ . '/Source/ClassWithTrait.php', 0, [ClassWithTrait::class, AnotherTrait::class]];
// traits in anonymous classes are ignored in PHPStan
yield [__DIR__ . '/Source/AnonymousClass.php', 0, [ParentClass::class, SomeInterface::class]];
}
}

@ -0,0 +1,20 @@
<?php declare (strict_types=1);
use Rector\Symfony\Tests\Rector\FrameworkBundle\GetToConstructorInjectionRector\Source\ParentClassWithGetTrait;
class ClassWithNamedServiceAndParentTrait extends ParentClassWithGetTrait
{
/**
* @var \Rector\Symfony\Tests\Rector\FrameworkBundle\AbstractToConstructorInjectionRectorSource\SomeTranslator
*/
private $someTranslator;
public function __construct(\Rector\Symfony\Tests\Rector\FrameworkBundle\AbstractToConstructorInjectionRectorSource\SomeTranslator $someTranslator)
{
$this->someTranslator = $someTranslator;
}
public function render()
{
$this->someTranslator;
}
}

@ -0,0 +1,11 @@
<?php declare (strict_types=1);
use Rector\Symfony\Tests\Rector\FrameworkBundle\GetToConstructorInjectionRector\Source\ParentClassWithGetTrait;
class ClassWithNamedServiceAndParentTrait extends ParentClassWithGetTrait
{
public function render()
{
$this->get('translator');
}
}