-
Notifications
You must be signed in to change notification settings - Fork 435
/
ThrowableReturnTypeExtension.php
78 lines (65 loc) · 1.97 KB
/
ThrowableReturnTypeExtension.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php declare(strict_types = 1);
namespace PHPStan\Type\Php;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\ErrorType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeUtils;
use Throwable;
use function count;
use function in_array;
use function strtolower;
final class ThrowableReturnTypeExtension implements DynamicMethodReturnTypeExtension
{
public function getClass(): string
{
return Throwable::class;
}
public function isMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === 'getCode';
}
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
{
$type = $scope->getType($methodCall->var);
$types = [];
$pdoException = new ObjectType('PDOException');
foreach (TypeUtils::getDirectClassNames($type) as $class) {
$classType = new ObjectType($class);
if ($classType->getClassReflection() !== null) {
$classReflection = $classType->getClassReflection();
foreach ($classReflection->getMethodTags() as $methodName => $methodTag) {
if (strtolower($methodName) !== 'getcode') {
continue;
}
$types[] = $methodTag->getReturnType();
continue 2;
}
}
if ($pdoException->isSuperTypeOf($classType)->yes()) {
$types[] = new BenevolentUnionType([new IntegerType(), new StringType()]);
continue;
}
if (in_array(strtolower($class), [
'throwable',
'exception',
'runtimeexception',
], true)) {
$types[] = new BenevolentUnionType([new IntegerType(), new StringType()]);
continue;
}
$types[] = new IntegerType();
}
if (count($types) === 0) {
return new ErrorType();
}
return TypeCombinator::union(...$types);
}
}