Skip to content

Commit a719629

Browse files
authored
[DowngradePhp80] Handle union implements method from interface on DowngradeUnionTypeDeclarationRector (#271)
* [DowngradePhp80] Handle union implements method from interface on DowngradeUnionTypeDeclarationRector * Fix
1 parent 15fd706 commit a719629

File tree

6 files changed

+95
-1
lines changed

6 files changed

+95
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Fixture;
4+
5+
use Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\Foo1;
6+
use Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\Foo2;
7+
use Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\SomeInterface;
8+
9+
class OverrideFromInterface implements SomeInterface
10+
{
11+
public function run(): Foo1|Foo2
12+
{
13+
return new Foo1();
14+
}
15+
}
16+
17+
?>
18+
-----
19+
<?php
20+
21+
namespace Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Fixture;
22+
23+
use Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\Foo1;
24+
use Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\Foo2;
25+
use Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\SomeInterface;
26+
27+
class OverrideFromInterface implements SomeInterface
28+
{
29+
/**
30+
* @return \Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\Foo1|\Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\Foo2
31+
*/
32+
public function run(): \Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source\FooInterface
33+
{
34+
return new Foo1();
35+
}
36+
}
37+
38+
?>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source;
4+
5+
class Foo1 implements FooInterface
6+
{
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source;
4+
5+
class Foo2 implements FooInterface
6+
{
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source;
4+
5+
interface FooInterface
6+
{
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp80\Rector\FunctionLike\DowngradeUnionTypeDeclarationRector\Source;
4+
5+
interface SomeInterface
6+
{
7+
public function run(): FooInterface;
8+
}

src/PhpDocDecorator/PhpDocFromTypeDeclarationDecorator.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
use PhpParser\Node\Expr\Closure;
1111
use PhpParser\Node\Identifier;
1212
use PhpParser\Node\Name;
13+
use PhpParser\Node\Name\FullyQualified;
1314
use PhpParser\Node\Param;
15+
use PhpParser\Node\Stmt\ClassLike;
1416
use PhpParser\Node\Stmt\ClassMethod;
1517
use PhpParser\Node\Stmt\Function_;
1618
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
@@ -27,6 +29,7 @@
2729
use Rector\Php\PhpVersionProvider;
2830
use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer;
2931
use Rector\PhpAttribute\NodeFactory\PhpAttributeGroupFactory;
32+
use Rector\PhpParser\AstResolver;
3033
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
3134
use Rector\Reflection\ReflectionResolver;
3235
use Rector\StaticTypeMapper\StaticTypeMapper;
@@ -52,7 +55,8 @@ public function __construct(
5255
private readonly PhpAttributeGroupFactory $phpAttributeGroupFactory,
5356
private readonly ReflectionResolver $reflectionResolver,
5457
private readonly PhpAttributeAnalyzer $phpAttributeAnalyzer,
55-
private readonly PhpVersionProvider $phpVersionProvider
58+
private readonly PhpVersionProvider $phpVersionProvider,
59+
private readonly AstResolver $astResolver,
5660
) {
5761
$this->classMethodWillChangeReturnTypes = [
5862
// @todo how to make list complete? is the method list needed or can we use just class names?
@@ -96,6 +100,29 @@ public function decorateReturn(ClassMethod|Function_|Closure|ArrowFunction $func
96100
return;
97101
}
98102

103+
$ancestors = array_filter(
104+
$classReflection->getAncestors(),
105+
static fn (ClassReflection $ancestor): bool => $classReflection->getName() !== $ancestor->getName()
106+
);
107+
108+
foreach ($ancestors as $ancestor) {
109+
$classLike = $this->astResolver->resolveClassFromClassReflection($ancestor);
110+
if (! $classLike instanceof ClassLike) {
111+
continue;
112+
}
113+
114+
$classMethod = $classLike->getMethod($functionLike->name->toString());
115+
if (! $classMethod instanceof ClassMethod) {
116+
continue;
117+
}
118+
119+
$returnType = $classMethod->returnType;
120+
if ($returnType instanceof Node && $returnType instanceof FullyQualified) {
121+
$functionLike->returnType = new FullyQualified($returnType->toString());
122+
break;
123+
}
124+
}
125+
99126
if (! $this->isRequireReturnTypeWillChange($classReflection, $functionLike)) {
100127
return;
101128
}

0 commit comments

Comments
 (0)