From ce32d575bcd0afcc404d86841caa7e2519b3f3f1 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 22 Dec 2025 14:44:56 +0100 Subject: [PATCH 1/4] [dead-code] Add RemoveParentDelegatingConstructorRector --- .../Fixture/some_class.php.inc | 27 ++++ ...eParentDelegatingConstructorRectorTest.php | 28 ++++ .../config/configured_rule.php | 9 ++ ...emoveParentDelegatingConstructorRector.php | 136 ++++++++++++++++++ src/Reporting/DeprecatedRulesReporter.php | 2 +- 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/some_class.php.inc create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/RemoveParentDelegatingConstructorRectorTest.php create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/config/configured_rule.php create mode 100644 rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/some_class.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/some_class.php.inc new file mode 100644 index 00000000000..e12790aaadc --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/some_class.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/RemoveParentDelegatingConstructorRectorTest.php b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/RemoveParentDelegatingConstructorRectorTest.php new file mode 100644 index 00000000000..e65a7af8078 --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/RemoveParentDelegatingConstructorRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/config/configured_rule.php b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/config/configured_rule.php new file mode 100644 index 00000000000..8f49ec2f813 --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/config/configured_rule.php @@ -0,0 +1,9 @@ +withRules([RemoveParentDelegatingConstructorRector::class]); diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php new file mode 100644 index 00000000000..f6462a1299d --- /dev/null +++ b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php @@ -0,0 +1,136 @@ +> + */ + public function getNodeTypes(): array + { + return [ClassMethod::class]; + } + + /** + * @param ClassMethod $node + */ + public function refactor(Node $node): ?int + { + if (! $this->isName($node, MethodName::CONSTRUCT)) { + return null; + } + + if (count($node->stmts) !== 1) { + return null; + } + + $scope = ScopeFetcher::fetch($node); + $classReflection = $scope->getClassReflection(); + if (! $classReflection->getParentClass() instanceof ClassReflection) { + return null; + } + + $parentClassReflection = $classReflection->getParentClass(); + if (! $parentClassReflection->hasConstructor()) { + return null; + } + + // $parentClassReflectionConstructor = $parentClassReflection->getConstructor(); + + $soleStmt = $node->stmts[0]; + if (! $soleStmt instanceof Node\Stmt\Expression) { + return null; + } + + if (! $soleStmt->expr instanceof Node\Expr\StaticCall) { + return null; + } + + $staticCall = $soleStmt->expr; + if (! $this->isName($staticCall->class, ObjectReference::PARENT)) { + return null; + } + + if (! $this->isName($staticCall->name, MethodName::CONSTRUCT)) { + return null; + } + + $constructorParams = $node->getParams(); + $parentCallArgs = $staticCall->getArgs(); + + if (count($constructorParams) !== count($parentCallArgs)) { + return null; + } + + return NodeVisitor::REMOVE_NODE; + } +} diff --git a/src/Reporting/DeprecatedRulesReporter.php b/src/Reporting/DeprecatedRulesReporter.php index 5f941be6faa..aa5ef694428 100644 --- a/src/Reporting/DeprecatedRulesReporter.php +++ b/src/Reporting/DeprecatedRulesReporter.php @@ -4,13 +4,13 @@ namespace Rector\Reporting; -use Rector\PhpParserNode\FileNode; use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; use Rector\Configuration\Option; use Rector\Configuration\Parameter\SimpleParameterProvider; use Rector\Contract\PhpParser\Node\StmtsAwareInterface; use Rector\Contract\Rector\RectorInterface; use Rector\PhpParser\Enum\NodeGroup; +use Rector\PhpParserNode\FileNode; use ReflectionMethod; use Symfony\Component\Console\Style\SymfonyStyle; From d4e87d0e70e3fabfb76b020d458c22eaea62069b Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 22 Dec 2025 14:55:18 +0100 Subject: [PATCH 2/4] enable rule --- .../Fixture/skip_different_type.php.inc | 16 ++++ .../Fixture/skip_differnt_args.php.inc | 13 +++ .../Fixture/skip_differnt_count.php.inc | 13 +++ ...emoveParentDelegatingConstructorRector.php | 94 +++++++++++++------ .../CommentRemovingNodeTraverser.php | 5 - src/Config/Level/DeadCodeLevel.php | 4 + 6 files changed, 110 insertions(+), 35 deletions(-) create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_differnt_args.php.inc create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_differnt_count.php.inc diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc new file mode 100644 index 00000000000..70017d50c2e --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc @@ -0,0 +1,16 @@ +stmts) !== 1) { + if ($node->stmts === null || count($node->stmts) !== 1) { return null; } - $scope = ScopeFetcher::fetch($node); - $classReflection = $scope->getClassReflection(); - if (! $classReflection->getParentClass() instanceof ClassReflection) { + if (! $this->hasParentClassWithConstructor($node)) { return null; } - $parentClassReflection = $classReflection->getParentClass(); - if (! $parentClassReflection->hasConstructor()) { + $soleStmt = $node->stmts[0]; + $parentCallArgs = $this->matchParentConstructorCallArgs($soleStmt); + if ($parentCallArgs === null) { return null; } - // $parentClassReflectionConstructor = $parentClassReflection->getConstructor(); - - $soleStmt = $node->stmts[0]; - if (! $soleStmt instanceof Node\Stmt\Expression) { + $constructorParams = $node->getParams(); + if (count($constructorParams) !== count($parentCallArgs)) { return null; } - if (! $soleStmt->expr instanceof Node\Expr\StaticCall) { + // match passed names in the same order + $paramNames = []; + foreach ($constructorParams as $constructorParam) { + $paramNames[] = $this->getName($constructorParam->var); + } + + $argNames = []; + foreach ($parentCallArgs as $parentCallArg) { + $argValue = $parentCallArg->value; + if (! $argValue instanceof Variable) { + return null; + } + + $argNames[] = $this->getName($argValue); + } + + if ($paramNames !== $argNames) { return null; } - $staticCall = $soleStmt->expr; - if (! $this->isName($staticCall->class, ObjectReference::PARENT)) { + return NodeVisitor::REMOVE_NODE; + } + + private function hasParentClassWithConstructor(ClassMethod $classMethod): bool + { + $scope = ScopeFetcher::fetch($classMethod); + + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { + return false; + } + + $parentClassReflection = $classReflection->getParentClass(); + if (! $parentClassReflection instanceof ClassReflection) { + return false; + } + + return $parentClassReflection->hasConstructor(); + } + + /** + * Looking for parent::__construct() + * + * @return Arg[]|null + */ + private function matchParentConstructorCallArgs(Stmt $stmt): ?array + { + if (! $stmt instanceof Expression) { return null; } - if (! $this->isName($staticCall->name, MethodName::CONSTRUCT)) { + if (! $stmt->expr instanceof StaticCall) { return null; } - $constructorParams = $node->getParams(); - $parentCallArgs = $staticCall->getArgs(); + $staticCall = $stmt->expr; + if (! $this->isName($staticCall->class, ObjectReference::PARENT)) { + return null; + } - if (count($constructorParams) !== count($parentCallArgs)) { + if (! $this->isName($staticCall->name, MethodName::CONSTRUCT)) { return null; } - return NodeVisitor::REMOVE_NODE; + return $staticCall->getArgs(); } } diff --git a/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php b/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php index 5689b9affce..f17ab972b9c 100644 --- a/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php +++ b/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php @@ -5,12 +5,7 @@ namespace Rector\Comments\NodeTraverser; use PhpParser\NodeTraverser; -use Rector\Comments\NodeVisitor\CommentRemovingNodeVisitor; final class CommentRemovingNodeTraverser extends NodeTraverser { - public function __construct(CommentRemovingNodeVisitor $commentRemovingNodeVisitor) - { - parent::__construct($commentRemovingNodeVisitor); - } } diff --git a/src/Config/Level/DeadCodeLevel.php b/src/Config/Level/DeadCodeLevel.php index 9c0c8715b8c..70a2ab4d44e 100644 --- a/src/Config/Level/DeadCodeLevel.php +++ b/src/Config/Level/DeadCodeLevel.php @@ -17,6 +17,7 @@ use Rector\DeadCode\Rector\ClassMethod\RemoveArgumentFromDefaultParentCallRector; use Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector; use Rector\DeadCode\Rector\ClassMethod\RemoveNullTagValueNodeRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstructorRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodParameterRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; @@ -132,7 +133,10 @@ final class DeadCodeLevel RemoveConditionExactReturnRector::class, RemoveDeadStmtRector::class, UnwrapFutureCompatibleIfPhpVersionRector::class, + RemoveParentCallWithoutParentRector::class, + RemoveParentDelegatingConstructorRector::class, + RemoveDeadConditionAboveReturnRector::class, RemoveDeadLoopRector::class, From 286ca840bf9f3e738dea32ac3cc8954850474f70 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 22 Dec 2025 15:14:33 +0100 Subject: [PATCH 3/4] skip type override --- phpstan.neon | 5 + ...emoveParentDelegatingConstructorRector.php | 112 ++++++++++++++---- 2 files changed, 93 insertions(+), 24 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 616fe4cdfa7..9720808bdc2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -326,6 +326,11 @@ parameters: - '#expects array, array given#' - '#should return non\-empty\-string but returns string#' + # known non-empty class method + - + message: '#Offset 0 might not exist on array\|null#' + path: rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php + # false positive, can accept non-class string - '#Parameter \#1 \$name of method PHPStan\\BetterReflection\\Reflection\\Adapter\\ReflectionClass\:\:getAttributes\(\) expects class\-string\|null, string given#' diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php index 0f3a39d5805..5397d2c90d0 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php @@ -13,9 +13,12 @@ use PhpParser\Node\Stmt\Expression; use PhpParser\NodeVisitor; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedMethodReflection; use Rector\Enum\ObjectReference; use Rector\PHPStan\ScopeFetcher; +use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\Rector\AbstractRector; +use Rector\StaticTypeMapper\StaticTypeMapper; use Rector\ValueObject\MethodName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -25,6 +28,11 @@ */ final class RemoveParentDelegatingConstructorRector extends AbstractRector { + public function __construct( + private readonly StaticTypeMapper $staticTypeMapper, + ) { + } + public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -86,7 +94,8 @@ public function refactor(Node $node): ?int return null; } - if (! $this->hasParentClassWithConstructor($node)) { + $parentMethodReflection = $this->matchParentConstructorReflection($node); + if (! $parentMethodReflection instanceof ExtendedMethodReflection) { return null; } @@ -96,49 +105,38 @@ public function refactor(Node $node): ?int return null; } - $constructorParams = $node->getParams(); - if (count($constructorParams) !== count($parentCallArgs)) { + // match count and order + if (! $this->isParameterAndArgCountAndOrderIdentical($node)) { return null; } - // match passed names in the same order - $paramNames = []; - foreach ($constructorParams as $constructorParam) { - $paramNames[] = $this->getName($constructorParam->var); - } - - $argNames = []; - foreach ($parentCallArgs as $parentCallArg) { - $argValue = $parentCallArg->value; - if (! $argValue instanceof Variable) { - return null; - } - - $argNames[] = $this->getName($argValue); - } - - if ($paramNames !== $argNames) { + // match parameter types and parent constructor types + if (! $this->areConstructorAndParentParameterTypesMatching($node, $parentMethodReflection)) { return null; } return NodeVisitor::REMOVE_NODE; } - private function hasParentClassWithConstructor(ClassMethod $classMethod): bool + private function matchParentConstructorReflection(ClassMethod $classMethod): ?ExtendedMethodReflection { $scope = ScopeFetcher::fetch($classMethod); $classReflection = $scope->getClassReflection(); if (! $classReflection instanceof ClassReflection) { - return false; + return null; } $parentClassReflection = $classReflection->getParentClass(); if (! $parentClassReflection instanceof ClassReflection) { - return false; + return null; + } + + if (! $parentClassReflection->hasConstructor()) { + return null; } - return $parentClassReflection->hasConstructor(); + return $parentClassReflection->getConstructor(); } /** @@ -167,4 +165,70 @@ private function matchParentConstructorCallArgs(Stmt $stmt): ?array return $staticCall->getArgs(); } + + private function isParameterAndArgCountAndOrderIdentical(ClassMethod $classMethod): bool + { + $soleStmt = $classMethod->stmts[0]; + + $parentCallArgs = $this->matchParentConstructorCallArgs($soleStmt); + if ($parentCallArgs === null) { + return false; + } + + $constructorParams = $classMethod->getParams(); + if (count($constructorParams) !== count($parentCallArgs)) { + return false; + } + + // match passed names in the same order + $paramNames = []; + foreach ($constructorParams as $constructorParam) { + $paramNames[] = $this->getName($constructorParam->var); + } + + $argNames = []; + foreach ($parentCallArgs as $parentCallArg) { + $argValue = $parentCallArg->value; + if (! $argValue instanceof Variable) { + return false; + } + + $argNames[] = $this->getName($argValue); + } + + return $paramNames === $argNames; + } + + private function areConstructorAndParentParameterTypesMatching( + ClassMethod $classMethod, + ExtendedMethodReflection $parentMethodReflection + ): bool { + foreach ($classMethod->getParams() as $position => $param) { + $parameterType = $param->type; + + // no type override + if ($parameterType === null) { + continue; + } + + $parametersSelector = $parentMethodReflection->getOnlyVariant(); + + foreach ($parametersSelector->getParameters() as $index => $parameterReflection) { + if ($index !== $position) { + continue; + } + + $parentParameterType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode( + $parameterReflection->getType(), + TypeKind::PARAM + ); + + if (! $this->nodeComparator->areNodesEqual($parameterType, $parentParameterType)) { + return false; + } + } + } + + return true; + } } From fc381ce0190150a39532dec6eb80690deafe4cc6 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 22 Dec 2025 15:17:43 +0100 Subject: [PATCH 4/4] skip fcc --- ...rnt_args.php.inc => skip_different_args.php.inc} | 0 ...t_count.php.inc => skip_different_count.php.inc} | 2 +- .../Fixture/skip_different_type.php.inc | 2 +- .../Fixture/skip_first_class_callable.php.inc | 13 +++++++++++++ .../RemoveParentDelegatingConstructorRector.php | 8 ++++++-- .../NodeTraverser/CommentRemovingNodeTraverser.php | 5 +++++ 6 files changed, 26 insertions(+), 4 deletions(-) rename rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/{skip_differnt_args.php.inc => skip_different_args.php.inc} (100%) rename rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/{skip_differnt_count.php.inc => skip_different_count.php.inc} (83%) create mode 100644 rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_first_class_callable.php.inc diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_differnt_args.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_args.php.inc similarity index 100% rename from rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_differnt_args.php.inc rename to rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_args.php.inc diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_differnt_count.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_count.php.inc similarity index 83% rename from rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_differnt_count.php.inc rename to rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_count.php.inc index 0f2fe25546a..3ed672b9e60 100644 --- a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_differnt_count.php.inc +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_count.php.inc @@ -4,7 +4,7 @@ namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstru use PhpParser\Node\Scalar\String_; -final class SkipDifferntCount extends String_ +final class SkipDifferentCount extends String_ { public function __construct($value) { diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc index 70017d50c2e..9f6c01f6c3d 100644 --- a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_different_type.php.inc @@ -7,7 +7,7 @@ namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveParentDelegatingConstru use PhpParser\NodeTraverser; use Rector\Comments\NodeVisitor\CommentRemovingNodeVisitor; -final class SkipDifferntType extends NodeTraverser +final class SkipDifferentType extends NodeTraverser { public function __construct(CommentRemovingNodeVisitor $commentRemovingNodeVisitor) { diff --git a/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_first_class_callable.php.inc b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_first_class_callable.php.inc new file mode 100644 index 00000000000..65e9a30f633 --- /dev/null +++ b/rules-tests/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector/Fixture/skip_first_class_callable.php.inc @@ -0,0 +1,13 @@ +expr; + if ($staticCall->isFirstClassCallable()) { + return null; + } + if (! $this->isName($staticCall->class, ObjectReference::PARENT)) { return null; } @@ -201,7 +205,7 @@ private function isParameterAndArgCountAndOrderIdentical(ClassMethod $classMetho private function areConstructorAndParentParameterTypesMatching( ClassMethod $classMethod, - ExtendedMethodReflection $parentMethodReflection + ExtendedMethodReflection $extendedMethodReflection ): bool { foreach ($classMethod->getParams() as $position => $param) { $parameterType = $param->type; @@ -211,7 +215,7 @@ private function areConstructorAndParentParameterTypesMatching( continue; } - $parametersSelector = $parentMethodReflection->getOnlyVariant(); + $parametersSelector = $extendedMethodReflection->getOnlyVariant(); foreach ($parametersSelector->getParameters() as $index => $parameterReflection) { if ($index !== $position) { diff --git a/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php b/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php index f17ab972b9c..5689b9affce 100644 --- a/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php +++ b/src/Comments/NodeTraverser/CommentRemovingNodeTraverser.php @@ -5,7 +5,12 @@ namespace Rector\Comments\NodeTraverser; use PhpParser\NodeTraverser; +use Rector\Comments\NodeVisitor\CommentRemovingNodeVisitor; final class CommentRemovingNodeTraverser extends NodeTraverser { + public function __construct(CommentRemovingNodeVisitor $commentRemovingNodeVisitor) + { + parent::__construct($commentRemovingNodeVisitor); + } }