Remove unused ClassLikeParentResolver (#385)

This commit is contained in:
Tomas Votruba 2021-07-05 12:46:26 +02:00 committed by GitHub
parent 5f43d6b712
commit 0a616c462d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 3 additions and 882 deletions

View File

@ -48,10 +48,11 @@
"symplify/smart-file-system": "^9.4.4",
"symplify/symfony-php-config": "^9.4.4",
"tracy/tracy": "^2.8",
"webmozart/assert": "^1.10"
"webmozart/assert": "^1.10",
"cweagans/composer-patches": "^1.7",
"symplify/vendor-patches": "^9.4"
},
"require-dev": {
"cweagans/composer-patches": "^1.7",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-nette": "^0.12.19",
"phpunit/phpunit": "^9.5",
@ -64,7 +65,6 @@
"symplify/phpstan-extensions": "^9.4.4",
"symplify/phpstan-rules": "^9.4.4",
"symplify/rule-doc-generator": "^9.4.4",
"symplify/vendor-patches": "^9.4",
"timeweb/phpstan-enum": "^2.3"
},
"replace": {

View File

@ -107,16 +107,6 @@ final class NodeRepository
return $this->parsedNodeCollector->findClass($name);
}
/**
* @deprecated Use static reflection instead
*
* @param class-string $name
*/
public function findTrait(string $name): ?Trait_
{
return $this->parsedNodeCollector->findTrait($name);
}
private function isChildOrEqualClassLike(string $desiredClass, ?string $currentClassName): bool
{
if ($currentClassName === null) {

View File

@ -1,65 +0,0 @@
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\ClassWithParent;
abstract class AbstractParentClassWithParents
{
/**
* @var ClassWithParent
*/
private $implement;
public function __construct(ClassWithParent $implement)
{
$this->implement = $implement;
}
}
class FirstChildClassWithParent extends AbstractParentClassWithParents
{
public function __construct(ClassWithParent $firstImplementer)
{
parent::__construct($firstImplementer);
}
}
class SecondChildClassWithParent extends AbstractParentClassWithParents
{
public function __construct(ClassWithParent $secondImplementer)
{
parent::__construct($secondImplementer);
}
}
?>
-----
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\ClassWithParent;
abstract class AbstractParentClassWithParents
{
/**
* @var ClassWithParent
*/
private $implement;
public function injectAbstractParentClassWithParents(\Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\ClassWithParent $classWithParent)
{
$this->classWithParent = $classWithParent;
}
}
class FirstChildClassWithParent extends AbstractParentClassWithParents
{
}
class SecondChildClassWithParent extends AbstractParentClassWithParents
{
}
?>

View File

@ -1,82 +0,0 @@
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\AnotherDependency;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClassWithExtraDependency
{
/**
* @var SomeDependency
*/
private $someDependency;
public function __construct(SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChildWithExtraDependency extends AbstractParentClassWithExtraDependency
{
/**
* @var AnotherDependency
*/
private $anotherDependency;
public function __construct(SomeDependency $someDependency, AnotherDependency $anotherDependency)
{
parent::__construct($someDependency);
$this->anotherDependency = $anotherDependency;
}
}
class SecondChildWithExtraDependency extends AbstractParentClassWithExtraDependency
{
public function __construct(SomeDependency $someDependency)
{
parent::__construct($someDependency);
}
}
?>
-----
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\AnotherDependency;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClassWithExtraDependency
{
/**
* @var SomeDependency
*/
private $someDependency;
public function injectAbstractParentClassWithExtraDependency(\Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChildWithExtraDependency extends AbstractParentClassWithExtraDependency
{
/**
* @var AnotherDependency
*/
private $anotherDependency;
public function __construct(AnotherDependency $anotherDependency)
{
$this->anotherDependency = $anotherDependency;
}
}
class SecondChildWithExtraDependency extends AbstractParentClassWithExtraDependency
{
}
?>

View File

@ -1,65 +0,0 @@
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClass
{
/**
* @var SomeDependency
*/
private $someDependency;
public function __construct(SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChild extends AbstractParentClass
{
public function __construct(SomeDependency $someDependency)
{
parent::__construct($someDependency);
}
}
class SecondChild extends AbstractParentClass
{
public function __construct(SomeDependency $someDependency)
{
parent::__construct($someDependency);
}
}
?>
-----
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClass
{
/**
* @var SomeDependency
*/
private $someDependency;
public function injectAbstractParentClass(\Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChild extends AbstractParentClass
{
}
class SecondChild extends AbstractParentClass
{
}
?>

View File

@ -1,36 +0,0 @@
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\FirstImplementer;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\ImplementInterface;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SecondImplementer;
abstract class AbstractParentClassSkipDifferentImplementations
{
/**
* @var ImplementInterface
*/
private $implement;
public function __construct(ImplementInterface $implement)
{
$this->implement = $implement;
}
}
class FirstChildDifferentImplementations extends AbstractParentClassSkipDifferentImplementations
{
public function __construct(FirstImplementer $firstImplementer)
{
parent::__construct($firstImplementer);
}
}
class SecondChildDifferentImplementations extends AbstractParentClassSkipDifferentImplementations
{
public function __construct(SecondImplementer $secondImplementer)
{
parent::__construct($secondImplementer);
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\AnotherDependency;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClassSkipDifferent
{
/**
* @var SomeDependency
*/
private $someDependency;
public function __construct(SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChildDifferentTypes extends AbstractParentClassSkipDifferent
{
private $anotherDependency;
public function __construct(AnotherDependency $anotherDependency)
{
$this->anotherDependency = $anotherDependency;
}
}
class SecondChildDifferentTypes extends AbstractParentClassSkipDifferent
{
private $anotherDependency;
public function __construct(AnotherDependency $anotherDependency)
{
$this->anotherDependency = $anotherDependency;
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Fixture;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClassSkipEmptyConstructor
{
/**
* @var SomeDependency
*/
private $someDependency;
public function __construct(SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChildSkipEmptyConstructor extends AbstractParentClassSkipEmptyConstructor
{
public function __construct()
{
$value = 5;
}
}
class SecondChildSkipEmptyConstructor extends AbstractParentClassSkipEmptyConstructor
{
public function __construct()
{
$value = 15;
}
}

View File

@ -1,68 +0,0 @@
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\FixtureSymfony;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClass
{
/**
* @var SomeDependency
*/
private $someDependency;
public function __construct(SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChild extends AbstractParentClass
{
public function __construct(SomeDependency $someDependency)
{
parent::__construct($someDependency);
}
}
class SecondChild extends AbstractParentClass
{
public function __construct(SomeDependency $someDependency)
{
parent::__construct($someDependency);
}
}
?>
-----
<?php
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\FixtureSymfony;
use Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency;
abstract class AbstractParentClass
{
/**
* @var SomeDependency
*/
private $someDependency;
/**
* @required
*/
public function injectAbstractParentClass(\Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source\SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChild extends AbstractParentClass
{
}
class SecondChild extends AbstractParentClass
{
}
?>

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MultiParentingToAbstractDependencyRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/nette_config.php';
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source;
abstract class AbstractSomeParent
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source;
final class AnotherDependency
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source;
final class ClassWithParent extends AbstractSomeParent
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source;
class FirstImplementer implements ImplementInterface
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source;
interface ImplementInterface
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source;
class SecondImplementer implements ImplementInterface
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\Source;
final class SomeDependency
{
}

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class SymfonyMultiParentingToAbstractDependencyRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/FixtureSymfony');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/symfony_config.php';
}
}

View File

@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Core\ValueObject\FrameworkName;
use Rector\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(MultiParentingToAbstractDependencyRector::class)
->call('configure', [[
MultiParentingToAbstractDependencyRector::FRAMEWORK => FrameworkName::NETTE,
]]);
};

View File

@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Core\ValueObject\FrameworkName;
use Rector\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(MultiParentingToAbstractDependencyRector::class)
->call('configure', [[
MultiParentingToAbstractDependencyRector::FRAMEWORK => FrameworkName::SYMFONY,
]]);
};

View File

@ -1,276 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\DependencyInjection\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\NodeManipulator\ClassInsertManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\FrameworkName;
use Rector\Core\ValueObject\MethodName;
use Rector\DependencyInjection\NodeFactory\InjectMethodFactory;
use Rector\DependencyInjection\NodeRemover\ClassMethodNodeRemover;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\DependencyInjection\Rector\Class_\MultiParentingToAbstractDependencyRector\MultiParentingToAbstractDependencyRectorTest
*/
final class MultiParentingToAbstractDependencyRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @api
* @var string
*/
public const FRAMEWORK = 'framework';
private string $framework = FrameworkName::SYMFONY;
/**
* @var ObjectType[]
*/
private array $injectObjectTypes = [];
public function __construct(
private ClassMethodNodeRemover $classMethodNodeRemover,
private InjectMethodFactory $injectMethodFactory,
PhpDocInfoFactory $phpDocInfoFactory,
private ClassInsertManipulator $classInsertManipulator
) {
$this->phpDocInfoFactory = $phpDocInfoFactory;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Move dependency passed to all children to parent as @inject/@required dependency',
[
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
abstract class AbstractParentClass
{
private $someDependency;
public function __construct(SomeDependency $someDependency)
{
$this->someDependency = $someDependency;
}
}
class FirstChild extends AbstractParentClass
{
public function __construct(SomeDependency $someDependency)
{
parent::__construct($someDependency);
}
}
class SecondChild extends AbstractParentClass
{
public function __construct(SomeDependency $someDependency)
{
parent::__construct($someDependency);
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
abstract class AbstractParentClass
{
/**
* @inject
* @var SomeDependency
*/
public $someDependency;
}
class FirstChild extends AbstractParentClass
{
}
class SecondChild extends AbstractParentClass
{
}
CODE_SAMPLE
,
[
self::FRAMEWORK => FrameworkName::NETTE,
]
),
]
);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $node->isAbstract()) {
return null;
}
/** @var string|null $className */
$className = $node->getAttribute(AttributeKey::CLASS_NAME);
if ($className === null) {
return null;
}
$childrenClasses = $this->nodeRepository->findChildrenOfClass($className);
if (count($childrenClasses) < 2) {
return null;
}
$classMethod = $node->getMethod(MethodName::CONSTRUCT);
if (! $classMethod instanceof ClassMethod) {
return null;
}
$abstractClassConstructorParamTypes = $this->resolveConstructorParamClassTypes($node);
// process
$this->injectObjectTypes = [];
foreach ($childrenClasses as $childClass) {
$constructorClassMethod = $childClass->getMethod(MethodName::CONSTRUCT);
if (! $constructorClassMethod instanceof ClassMethod) {
continue;
}
$this->refactorChildConstructorClassMethod($constructorClassMethod, $abstractClassConstructorParamTypes);
$this->classMethodNodeRemover->removeClassMethodIfUseless($constructorClassMethod);
}
// 2. remove from abstract class
$this->clearAbstractClassConstructor($classMethod);
// 3. add inject*/@required to abstract property
$this->addInjectOrRequiredClassMethod($node);
return $node;
}
/**
* @param array<string, string> $configuration
*/
public function configure(array $configuration): void
{
$this->framework = $configuration[self::FRAMEWORK] ?? FrameworkName::SYMFONY;
}
/**
* @return ObjectType[]
*/
private function resolveConstructorParamClassTypes(Class_ $class): array
{
$constructorClassMethod = $class->getMethod(MethodName::CONSTRUCT);
if (! $constructorClassMethod instanceof ClassMethod) {
return [];
}
$objectTypes = [];
foreach ($constructorClassMethod->getParams() as $param) {
$paramType = $this->getObjectType($param);
$paramType = $this->popFirstObjectTypeFromUnionType($paramType);
if (! $paramType instanceof ObjectType) {
continue;
}
$objectTypes[] = $paramType;
}
return $objectTypes;
}
/**
* @param ObjectType[] $abstractClassConstructorParamTypes
*/
private function refactorChildConstructorClassMethod(
ClassMethod $classMethod,
array $abstractClassConstructorParamTypes
): void {
foreach ($classMethod->getParams() as $key => $param) {
$paramType = $this->getStaticType($param);
$paramType = $this->popFirstObjectTypeFromUnionType($paramType);
if (! $paramType instanceof ObjectType) {
continue;
}
if (! $this->nodeTypeResolver->isSameObjectTypes($paramType, $abstractClassConstructorParamTypes)) {
continue;
}
$this->nodeRemover->removeParam($classMethod, $key);
$this->classMethodNodeRemover->removeParamFromMethodBody($classMethod, $param);
$this->injectObjectTypes[] = $paramType;
}
}
private function clearAbstractClassConstructor(ClassMethod $classMethod): void
{
foreach ($classMethod->getParams() as $key => $param) {
if (! $this->nodeTypeResolver->isObjectTypes($param, $this->injectObjectTypes)) {
continue;
}
unset($classMethod->params[$key]);
$this->classMethodNodeRemover->removeParamFromMethodBody($classMethod, $param);
}
$this->classMethodNodeRemover->removeClassMethodIfUseless($classMethod);
}
private function addInjectOrRequiredClassMethod(Class_ $class): void
{
/** @var string $className */
$className = $class->getAttribute(AttributeKey::CLASS_NAME);
if ($this->injectObjectTypes === []) {
return;
}
$injectClassMethod = $this->injectMethodFactory->createFromTypes(
$this->injectObjectTypes,
$className,
$this->framework
);
$this->classInsertManipulator->addAsFirstMethod($class, $injectClassMethod);
}
private function popFirstObjectTypeFromUnionType(Type $paramType): Type
{
if (! $paramType instanceof UnionType) {
return $paramType;
}
foreach ($paramType->getTypes() as $unionedType) {
if ($unionedType instanceof ObjectType) {
return $unionedType;
}
}
return $paramType;
}
}

View File

@ -1,40 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\DowngradePhp72\NodeAnalyzer;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Interface_;
use PHPStan\Reflection\ClassReflection;
use Rector\NodeCollector\NodeCollector\NodeRepository;
final class ClassLikeParentResolver
{
public function __construct(
private NodeRepository $nodeRepository
) {
}
/**
* @return array<Class_|Interface_>
*/
public function resolveFromClassReflection(ClassReflection $classReflection): array
{
$parentClassLikes = [];
foreach ($classReflection->getAncestors() as $ancestorClassReflectoin) {
$parentClass = $this->nodeRepository->findClass($ancestorClassReflectoin->getName());
if ($parentClass instanceof Class_) {
$parentClassLikes[] = $parentClass;
}
$parentInterface = $this->nodeRepository->findInterface($ancestorClassReflectoin->getName());
if ($parentInterface instanceof Interface_) {
$parentClassLikes[] = $parentInterface;
}
}
return $parentClassLikes;
}
}