Skip to content

Commit 6918438

Browse files
committed
Implement TypeSpecifierContext->getReturnType()
1 parent 2fe4e0f commit 6918438

File tree

5 files changed

+123
-0
lines changed

5 files changed

+123
-0
lines changed

src/Analyser/TypeSpecifierContext.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Analyser;
44

55
use PHPStan\ShouldNotHappenException;
6+
use PHPStan\Type\MixedType;
67

78
/**
89
* @api
@@ -89,4 +90,8 @@ public function null(): bool
8990
return $this->value === null;
9091
}
9192

93+
public function getReturnType(): Type {
94+
return new MixedType();
95+
}
96+
9297
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
services:
2+
-
3+
class: PHPStan\Analyser\TypeSpecifierContextReturnTypeExtension
4+
tags:
5+
- phpstan.typeSpecifier.methodTypeSpecifyingExtension
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PhpParser\Node\Expr\MethodCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Analyser\SpecifiedTypes;
8+
use PHPStan\Analyser\TypeSpecifier;
9+
use PHPStan\Analyser\TypeSpecifierAwareExtension;
10+
use PHPStan\Analyser\TypeSpecifierContext;
11+
use PHPStan\Reflection\MethodReflection;
12+
use PHPStan\Rules\Properties\PropertyReflectionFinder;
13+
use PHPStan\Type\Accessory\HasPropertyType;
14+
use PHPStan\Type\IntersectionType;
15+
use PHPStan\Type\MethodTypeSpecifyingExtension;
16+
use PHPStan\Type\ObjectWithoutClassType;
17+
use PHPStan\Type\StringType;
18+
19+
class TypeSpecifierContextReturnTypeExtension implements MethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
20+
{
21+
22+
private TypeSpecifier $typeSpecifier;
23+
24+
public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
25+
{
26+
$this->typeSpecifier = $typeSpecifier;
27+
}
28+
29+
public function getClass(): string
30+
{
31+
return \TypeSpecifierContextReturnTypeTest\ContextReturnType::class;
32+
}
33+
34+
public function isMethodSupported(
35+
MethodReflection $methodReflection,
36+
MethodCall $node,
37+
TypeSpecifierContext $context,
38+
): bool
39+
{
40+
return str_starts_with($methodReflection->getName(), 'returns');
41+
}
42+
43+
public function specifyTypes(
44+
MethodReflection $methodReflection,
45+
MethodCall $node,
46+
Scope $scope,
47+
TypeSpecifierContext $context,
48+
): SpecifiedTypes
49+
{
50+
return $this->typeSpecifier->create(
51+
$node->getArgs()[0]->value,
52+
$context->getReturnType(),
53+
$context,
54+
$scope,
55+
);
56+
}
57+
58+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PHPStan\ShouldNotHappenException;
6+
use PHPStan\Testing\PHPStanTestCase;
7+
use PHPStan\Testing\TypeInferenceTestCase;
8+
9+
class TypeSpecifierContextReturnTypeTest extends TypeInferenceTestCase
10+
{
11+
public function dataContextReturnType(): iterable
12+
{
13+
yield from $this->gatherAssertTypes(__DIR__ . '/data/type-specifier-context-return-type.php');
14+
}
15+
16+
/**
17+
* @dataProvider dataContextReturnType
18+
* @param mixed ...$args
19+
*/
20+
public function testContextReturnType(
21+
string $assertType,
22+
string $file,
23+
...$args,
24+
): void
25+
{
26+
$this->assertFileAsserts($assertType, $file, ...$args);
27+
}
28+
29+
public static function getAdditionalConfigFiles(): array
30+
{
31+
return [
32+
__DIR__.'/TypeSpecifierContextReturnTypeExtension.neon'
33+
];
34+
}
35+
36+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace TypeSpecifierContextReturnTypeTest;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class ContextReturnType {
8+
public function returnsInt(int $specifiedContextReturnType): int {}
9+
10+
public function doFoo(int $i) {
11+
assertType('int', $i);
12+
if ($this->returnsInt($i) > 0) {
13+
assertType('int<1, max>', $i);
14+
} else {
15+
assertType('int<min, 0>', $i);
16+
}
17+
assertType('int', $i);
18+
}
19+
}

0 commit comments

Comments
 (0)