diff --git a/rules/dead-code/src/Rector/Class_/RemoveEmptyAbstractClassRector.php b/rules/dead-code/src/Rector/Class_/RemoveEmptyAbstractClassRector.php new file mode 100644 index 00000000000..b2cbfe41d13 --- /dev/null +++ b/rules/dead-code/src/Rector/Class_/RemoveEmptyAbstractClassRector.php @@ -0,0 +1,134 @@ +betterNodeFinder->findInstanceOf($node, FullyQualified::class); + foreach ($fullyQualifieds as $fullyQualified) { + $parent = $fullyQualified->getAttribute(AttributeKey::PARENT_NODE); + if ($parent instanceof Class_) { + continue; + } + + $this->fullyQualifieds[] = $fullyQualified; + } + return $node; + } + + if ($this->shouldSkip($node)) { + return null; + } + + return $this->processRemove($node); + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Empty abstract class that does nothing', + [ + new CodeSample( +<<<'CODE_SAMPLE' +class SomeClass extends SomeAbstractClass +{ +} + +abstract class SomeAbstractClass extends AnotherAbstractClass +{ +} + +abstract class AnotherAbstractClass +{ + public function getName() + { + return 'name'; + } +} +CODE_SAMPLE +, +<<<'CODE_SAMPLE' +class SomeClass extends AnotherAbstractClass +{ +} + +abstracst clas AnotherAbstractClass +{ + public function getName() + { + return 'cowo'; + } +} +CODE_SAMPLE + ), + + ]); + } + + private function shouldSkip(Class_ $class): bool + { + if (! $class->isAbstract()) { + return true; + } + + if ($class->implements !== []) { + return true; + } + + $stmts = $class->stmts; + return $stmts !== []; + } + + private function processRemove(Class_ $class): ?Class_ + { + $className = $class->namespacedName->toString(); + foreach ($this->fullyQualifieds as $fullyQualified) { + if ($className === $fullyQualified->toString()) { + return null; + } + } + + $children = $this->nodeRepository->findChildrenOfClass($this->getName($class->namespacedName)); + $extends = $class->extends; + foreach ($children as $child) { + $child->extends = $extends; + } + + $this->removeNode($class); + return $class; + } +} diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/abstract_class_used_multi.php.inc b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/abstract_class_used_multi.php.inc new file mode 100644 index 00000000000..29f4372d02b --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/abstract_class_used_multi.php.inc @@ -0,0 +1,43 @@ + +----- + \ No newline at end of file diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/abstract_class_used_multi_upper.php.inc b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/abstract_class_used_multi_upper.php.inc new file mode 100644 index 00000000000..21a26ccb1d6 --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/abstract_class_used_multi_upper.php.inc @@ -0,0 +1,43 @@ + +----- + \ No newline at end of file diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/fixture.php.inc b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..edc555893e5 --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/fixture.php.inc @@ -0,0 +1,39 @@ + +----- + diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/multi_extends.php.inc b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/multi_extends.php.inc new file mode 100644 index 00000000000..64f7e215721 --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/multi_extends.php.inc @@ -0,0 +1,43 @@ + +----- + diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/single_empty_abstract.php.inc b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/single_empty_abstract.php.inc new file mode 100644 index 00000000000..78d5505acb8 --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/single_empty_abstract.php.inc @@ -0,0 +1,23 @@ + +----- + diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/skip_abstract_class_used.php.inc b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/skip_abstract_class_used.php.inc new file mode 100644 index 00000000000..1f3d9b7e708 --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Fixture/skip_abstract_class_used.php.inc @@ -0,0 +1,21 @@ + diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/RemoveEmptyAbstractClassRectorTest.php b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/RemoveEmptyAbstractClassRectorTest.php new file mode 100644 index 00000000000..955129fe34a --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/RemoveEmptyAbstractClassRectorTest.php @@ -0,0 +1,31 @@ +doTestFileInfo($fileInfo); + } + + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + protected function getRectorClass(): string + { + return RemoveEmptyAbstractClassRector::class; + } +} diff --git a/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Source/ATrait.php b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Source/ATrait.php new file mode 100644 index 00000000000..10eee3a1847 --- /dev/null +++ b/rules/dead-code/tests/Rector/Class_/RemoveEmptyAbstractClassRector/Source/ATrait.php @@ -0,0 +1,6 @@ +