Skip to content

Commit baa7e72

Browse files
Handle generics using AST instead of PHPStan
1 parent e800e8f commit baa7e72

File tree

3 files changed

+72
-6
lines changed

3 files changed

+72
-6
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Fixture;
4+
5+
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Source\AbstractGenericFactory;
6+
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Source\ConferenceTalk;
7+
8+
/**
9+
* @extends AbstractGenericFactory<ConferenceTalk>
10+
*/
11+
final class ConcreteGenericFactory extends AbstractGenericFactory
12+
{
13+
public function build(): object
14+
{
15+
return new ConferenceTalk();
16+
}
17+
}
18+
19+
?>
20+
-----
21+
<?php
22+
23+
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Fixture;
24+
25+
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Source\AbstractGenericFactory;
26+
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Source\ConferenceTalk;
27+
28+
/**
29+
* @extends AbstractGenericFactory<ConferenceTalk>
30+
*/
31+
final class ConcreteGenericFactory extends AbstractGenericFactory
32+
{
33+
public function build(): \Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Source\ConferenceTalk
34+
{
35+
return new ConferenceTalk();
36+
}
37+
}
38+
39+
?>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\NarrowObjectReturnTypeRector\Source;
6+
7+
/**
8+
* @template T
9+
*/
10+
abstract class AbstractGenericFactory
11+
{
12+
/**
13+
* @return T
14+
*/
15+
abstract public function build(): object;
16+
}

rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpParser\Node\Stmt\ClassMethod;
1111
use PHPStan\Reflection\ClassReflection;
1212
use PHPStan\Type\ObjectType;
13+
use Rector\PhpParser\AstResolver;
1314
use Rector\PhpParser\Node\BetterNodeFinder;
1415
use Rector\Rector\AbstractRector;
1516
use Rector\Reflection\ReflectionResolver;
@@ -26,6 +27,7 @@ final class NarrowObjectReturnTypeRector extends AbstractRector
2627
public function __construct(
2728
private readonly BetterNodeFinder $betterNodeFinder,
2829
private readonly ReflectionResolver $reflectionResolver,
30+
private readonly AstResolver $astResolver,
2931
) {
3032
}
3133

@@ -189,17 +191,18 @@ private function isNarrowingValid(string $declaredType, string $actualType): boo
189191
private function hasParentMethodWithNonObjectReturn(ClassMethod $classMethod): bool
190192
{
191193
$classReflection = $this->reflectionResolver->resolveClassReflection($classMethod);
194+
192195
if (! $classReflection instanceof ClassReflection) {
193196
return false;
194197
}
195198

196199
$ancestors = array_filter(
197200
$classReflection->getAncestors(),
198-
fn (ClassReflection $ancestorClassReflection): bool =>
199-
$classReflection->getName() !== $ancestorClassReflection->getName()
201+
fn (ClassReflection $ancestorClassReflection): bool => $classReflection->getName() !== $ancestorClassReflection->getName()
200202
);
201203

202204
$methodName = $this->getName($classMethod);
205+
203206
foreach ($ancestors as $ancestor) {
204207
if ($ancestor->getFileName() === null) {
205208
continue;
@@ -209,11 +212,19 @@ private function hasParentMethodWithNonObjectReturn(ClassMethod $classMethod): b
209212
continue;
210213
}
211214

212-
$parentMethod = $ancestor->getNativeMethod($methodName);
213-
$parentReturnType = $parentMethod->getVariants()[0]
214-
->getReturnType();
215+
$parentClassMethod = $this->astResolver->resolveClassMethod($ancestor->getName(), $methodName);
216+
217+
if ($parentClassMethod === null) {
218+
continue;
219+
}
220+
221+
$parentReturnType = $parentClassMethod->returnType;
222+
223+
if ($parentReturnType === null) {
224+
continue;
225+
}
215226

216-
if ($parentReturnType->isObject()->yes() && $parentReturnType->getObjectClassNames() === []) {
227+
if ($parentReturnType instanceof Identifier && $parentReturnType->name === 'object') {
217228
continue;
218229
}
219230

0 commit comments

Comments
 (0)