Skip to content

Commit 286ca84

Browse files
committed
skip type override
1 parent d4e87d0 commit 286ca84

File tree

2 files changed

+93
-24
lines changed

2 files changed

+93
-24
lines changed

phpstan.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ parameters:
326326
- '#expects array<PhpParser\\Node\\Stmt>, array<PhpParser\\Node> given#'
327327
- '#should return non\-empty\-string but returns string#'
328328

329+
# known non-empty class method
330+
-
331+
message: '#Offset 0 might not exist on array<PhpParser\\Node\\Stmt>\|null#'
332+
path: rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php
333+
329334
# false positive, can accept non-class string
330335
- '#Parameter \#1 \$name of method PHPStan\\BetterReflection\\Reflection\\Adapter\\ReflectionClass\:\:getAttributes\(\) expects class\-string\|null, string given#'
331336

rules/DeadCode/Rector/ClassMethod/RemoveParentDelegatingConstructorRector.php

Lines changed: 88 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
use PhpParser\Node\Stmt\Expression;
1414
use PhpParser\NodeVisitor;
1515
use PHPStan\Reflection\ClassReflection;
16+
use PHPStan\Reflection\ExtendedMethodReflection;
1617
use Rector\Enum\ObjectReference;
1718
use Rector\PHPStan\ScopeFetcher;
19+
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
1820
use Rector\Rector\AbstractRector;
21+
use Rector\StaticTypeMapper\StaticTypeMapper;
1922
use Rector\ValueObject\MethodName;
2023
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
2124
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -25,6 +28,11 @@
2528
*/
2629
final class RemoveParentDelegatingConstructorRector extends AbstractRector
2730
{
31+
public function __construct(
32+
private readonly StaticTypeMapper $staticTypeMapper,
33+
) {
34+
}
35+
2836
public function getRuleDefinition(): RuleDefinition
2937
{
3038
return new RuleDefinition(
@@ -86,7 +94,8 @@ public function refactor(Node $node): ?int
8694
return null;
8795
}
8896

89-
if (! $this->hasParentClassWithConstructor($node)) {
97+
$parentMethodReflection = $this->matchParentConstructorReflection($node);
98+
if (! $parentMethodReflection instanceof ExtendedMethodReflection) {
9099
return null;
91100
}
92101

@@ -96,49 +105,38 @@ public function refactor(Node $node): ?int
96105
return null;
97106
}
98107

99-
$constructorParams = $node->getParams();
100-
if (count($constructorParams) !== count($parentCallArgs)) {
108+
// match count and order
109+
if (! $this->isParameterAndArgCountAndOrderIdentical($node)) {
101110
return null;
102111
}
103112

104-
// match passed names in the same order
105-
$paramNames = [];
106-
foreach ($constructorParams as $constructorParam) {
107-
$paramNames[] = $this->getName($constructorParam->var);
108-
}
109-
110-
$argNames = [];
111-
foreach ($parentCallArgs as $parentCallArg) {
112-
$argValue = $parentCallArg->value;
113-
if (! $argValue instanceof Variable) {
114-
return null;
115-
}
116-
117-
$argNames[] = $this->getName($argValue);
118-
}
119-
120-
if ($paramNames !== $argNames) {
113+
// match parameter types and parent constructor types
114+
if (! $this->areConstructorAndParentParameterTypesMatching($node, $parentMethodReflection)) {
121115
return null;
122116
}
123117

124118
return NodeVisitor::REMOVE_NODE;
125119
}
126120

127-
private function hasParentClassWithConstructor(ClassMethod $classMethod): bool
121+
private function matchParentConstructorReflection(ClassMethod $classMethod): ?ExtendedMethodReflection
128122
{
129123
$scope = ScopeFetcher::fetch($classMethod);
130124

131125
$classReflection = $scope->getClassReflection();
132126
if (! $classReflection instanceof ClassReflection) {
133-
return false;
127+
return null;
134128
}
135129

136130
$parentClassReflection = $classReflection->getParentClass();
137131
if (! $parentClassReflection instanceof ClassReflection) {
138-
return false;
132+
return null;
133+
}
134+
135+
if (! $parentClassReflection->hasConstructor()) {
136+
return null;
139137
}
140138

141-
return $parentClassReflection->hasConstructor();
139+
return $parentClassReflection->getConstructor();
142140
}
143141

144142
/**
@@ -167,4 +165,70 @@ private function matchParentConstructorCallArgs(Stmt $stmt): ?array
167165

168166
return $staticCall->getArgs();
169167
}
168+
169+
private function isParameterAndArgCountAndOrderIdentical(ClassMethod $classMethod): bool
170+
{
171+
$soleStmt = $classMethod->stmts[0];
172+
173+
$parentCallArgs = $this->matchParentConstructorCallArgs($soleStmt);
174+
if ($parentCallArgs === null) {
175+
return false;
176+
}
177+
178+
$constructorParams = $classMethod->getParams();
179+
if (count($constructorParams) !== count($parentCallArgs)) {
180+
return false;
181+
}
182+
183+
// match passed names in the same order
184+
$paramNames = [];
185+
foreach ($constructorParams as $constructorParam) {
186+
$paramNames[] = $this->getName($constructorParam->var);
187+
}
188+
189+
$argNames = [];
190+
foreach ($parentCallArgs as $parentCallArg) {
191+
$argValue = $parentCallArg->value;
192+
if (! $argValue instanceof Variable) {
193+
return false;
194+
}
195+
196+
$argNames[] = $this->getName($argValue);
197+
}
198+
199+
return $paramNames === $argNames;
200+
}
201+
202+
private function areConstructorAndParentParameterTypesMatching(
203+
ClassMethod $classMethod,
204+
ExtendedMethodReflection $parentMethodReflection
205+
): bool {
206+
foreach ($classMethod->getParams() as $position => $param) {
207+
$parameterType = $param->type;
208+
209+
// no type override
210+
if ($parameterType === null) {
211+
continue;
212+
}
213+
214+
$parametersSelector = $parentMethodReflection->getOnlyVariant();
215+
216+
foreach ($parametersSelector->getParameters() as $index => $parameterReflection) {
217+
if ($index !== $position) {
218+
continue;
219+
}
220+
221+
$parentParameterType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
222+
$parameterReflection->getType(),
223+
TypeKind::PARAM
224+
);
225+
226+
if (! $this->nodeComparator->areNodesEqual($parameterType, $parentParameterType)) {
227+
return false;
228+
}
229+
}
230+
}
231+
232+
return true;
233+
}
170234
}

0 commit comments

Comments
 (0)