diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php index e452c8289d5..7520d64c6a6 100644 --- a/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php +++ b/rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php @@ -10,9 +10,9 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt; +use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; -use PhpParser\NodeVisitor; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; @@ -84,38 +84,39 @@ class SomeParent extends Node */ public function getNodeTypes(): array { - return [ClassMethod::class]; + return [Class_::class]; } /** - * @param ClassMethod $node + * @param Class_ $node */ - public function refactor(Node $node): ?int + public function refactor(Node $node): ?Class_ { - if (! $this->isName($node, MethodName::CONSTRUCT)) { + $constructClassMethod = $node->getMethod(MethodName::CONSTRUCT); + if (! $constructClassMethod instanceof ClassMethod) { return null; } - if ($node->stmts === null || count($node->stmts) !== 1) { + if ($constructClassMethod->stmts === null || count($constructClassMethod->stmts) !== 1) { return null; } - if ($node->isFinal()) { + if ($constructClassMethod->isFinal()) { return null; } - if (! $node->isPublic()) { + if (! $constructClassMethod->isPublic()) { return null; } - $soleStmt = $node->stmts[0]; + $soleStmt = $constructClassMethod->stmts[0]; $parentCallArgs = $this->matchParentConstructorCallArgs($soleStmt); if ($parentCallArgs === null) { return null; } // match count and order - if (! $this->isParameterAndArgCountAndOrderIdentical($node)) { + if (! $this->isParameterAndArgCountAndOrderIdentical($constructClassMethod)) { return null; } @@ -130,22 +131,31 @@ public function refactor(Node $node): ?int } // match parameter types and parent constructor types - if (! $this->areConstructorAndParentParameterTypesMatching($node, $parentMethodReflection)) { + if (! $this->areConstructorAndParentParameterTypesMatching($constructClassMethod, $parentMethodReflection)) { return null; } - if ($this->doAttributeDecoratedParametersExist($node)) { + if ($this->doAttributeDecoratedParametersExist($constructClassMethod)) { return null; } // keep when the docblock refines parameter types beyond the native signature, // e.g. @param array or @phpstan-param SomeShape $config — removing // the constructor would drop that type information - if ($this->hasParamRefiningDocblock($node)) { + if ($this->hasParamRefiningDocblock($constructClassMethod)) { return null; } - return NodeVisitor::REMOVE_NODE; + foreach ($node->stmts as $key => $stmt) { + if ($stmt === $constructClassMethod) { + unset($node->stmts[$key]); + $node->stmts = array_values($node->stmts); + + return $node; + } + } + + return null; } private function hasParamRefiningDocblock(ClassMethod $classMethod): bool @@ -155,9 +165,9 @@ private function hasParamRefiningDocblock(ClassMethod $classMethod): bool return $phpDocInfo->hasByNames(['@param', '@phpstan-param', '@psalm-param']); } - private function matchParentConstructorReflection(ClassMethod $classMethod): ?ExtendedMethodReflection + private function matchParentConstructorReflection(Class_ $class): ?ExtendedMethodReflection { - $scope = ScopeFetcher::fetch($classMethod); + $scope = ScopeFetcher::fetch($class); $classReflection = $scope->getClassReflection(); if (! $classReflection instanceof ClassReflection) { diff --git a/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php b/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php index 21f75b182b1..7d605c7b574 100644 --- a/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php +++ b/src/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php @@ -139,12 +139,6 @@ public function processNodes( string $filePath, ?MutatingScope $formerMutatingScope = null ): array { - /** - * The stmts must be array of Stmt, or it will be silently skipped by PHPStan - * @see vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:282 - */ - Assert::allIsInstanceOf($stmts, Stmt::class); - $scope = $formerMutatingScope ?? $this->scopeFactory->createFromFile($filePath); $this->fillScope($stmts, $filePath, $scope);