Skip to content

Commit baa371e

Browse files
committed
Fix native static return typehint when entering class method
1 parent ae50bb4 commit baa371e

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

src/Analyser/MutatingScope.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2595,7 +2595,7 @@ public function enterClassMethod(
25952595
return TemplateTypeHelper::toArgument($type);
25962596
}, $phpDocParameterTypes),
25972597
$this->getRealParameterDefaultValues($classMethod),
2598-
$this->getFunctionType($classMethod->returnType, $classMethod->returnType === null, false),
2598+
$this->transformStaticType($this->getFunctionType($classMethod->returnType, $classMethod->returnType === null, false)),
25992599
$phpDocReturnType !== null ? TemplateTypeHelper::toArgument($phpDocReturnType) : null,
26002600
$throwType,
26012601
$deprecatedDescription,
@@ -2608,6 +2608,25 @@ public function enterClassMethod(
26082608
);
26092609
}
26102610

2611+
private function transformStaticType(Type $type): Type
2612+
{
2613+
return TypeTraverser::map($type, function (Type $type, callable $traverse): Type {
2614+
if (!$this->isInClass()) {
2615+
return $type;
2616+
}
2617+
if ($type instanceof StaticType) {
2618+
$classReflection = $this->getClassReflection();
2619+
$changedType = $type->changeBaseClass($classReflection);
2620+
if ($classReflection->isFinal()) {
2621+
$changedType = $changedType->getStaticObjectType();
2622+
}
2623+
return $traverse($changedType);
2624+
}
2625+
2626+
return $traverse($type);
2627+
});
2628+
}
2629+
26112630
/**
26122631
* @param Node\FunctionLike $functionLike
26132632
* @return Type[]

tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,4 +477,12 @@ public function testBug3118(): void
477477
]);
478478
}
479479

480+
public function testBug4795(): void
481+
{
482+
if (PHP_VERSION_ID < 80000 && !self::$useStaticReflectionProvider) {
483+
$this->markTestSkipped('Test requires PHP 8.0');
484+
}
485+
$this->analyse([__DIR__ . '/data/bug-4795.php'], []);
486+
}
487+
480488
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php // lint >= 8.0
2+
3+
namespace Bug4795;
4+
5+
abstract class BaseDTO
6+
{
7+
8+
final protected static function create(): static
9+
{
10+
$class = static::class;
11+
12+
return new $class();
13+
}
14+
15+
abstract public static function parse(): static;
16+
17+
}
18+
19+
final class ConcreteDTO extends BaseDTO
20+
{
21+
22+
public string $foo;
23+
24+
public static function parse(): static
25+
{
26+
$instance = self::create();
27+
28+
$instance->foo = 'bar';
29+
30+
return $instance;
31+
}
32+
}
33+
34+
class NonFinalConcreteDTO extends BaseDTO
35+
{
36+
37+
public string $foo;
38+
39+
public static function parse(): static
40+
{
41+
$instance = self::create();
42+
43+
$instance->foo = 'bar';
44+
45+
return $instance;
46+
}
47+
}

0 commit comments

Comments
 (0)