forked from phpactor/phpactor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
MethodTypeResolver.php
87 lines (67 loc) · 2.66 KB
/
MethodTypeResolver.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
79
80
81
82
83
84
85
86
87
<?php
namespace Phpactor\WorseReflection\Core\Reflection\TypeResolver;
use Phpactor\WorseReflection\Core\Reflection\ReflectionMethod;
use Phpactor\WorseReflection\Core\TypeFactory;
use Phpactor\WorseReflection\Core\Type;
use Phpactor\WorseReflection\Core\Reflection\ReflectionClass;
use Phpactor\WorseReflection\Core\Reflection\ReflectionClassLike;
class MethodTypeResolver
{
public function __construct(private ReflectionMethod $method)
{
}
public function resolve(ReflectionClassLike $contextClass): Type
{
$resolvedType = $this->getDocblockTypesFromClassOrMethod($this->method);
if (($resolvedType->isDefined())) {
return $resolvedType;
}
$resolvedType = $this->getTypesFromParentClass($contextClass);
if (($resolvedType->isDefined())) {
return $resolvedType;
}
return $this->getTypesFromInterfaces($contextClass);
}
private function getDocblockTypesFromClassOrMethod(ReflectionMethod $method): Type
{
$classLike = $method->class();
$classMethodOverride = $classLike->docblock()->methodType($method->name());
if (($classMethodOverride->isDefined())) {
return $classMethodOverride;
}
$returnType = $method->docblock()->returnType();
$aliased = $classLike->docblock()->typeAliases()->forType($returnType);
if ($aliased) {
return $aliased;
}
// no static support here
return $returnType;
}
private function getTypesFromParentClass(ReflectionClassLike $reflectionClassLike): Type
{
$methodClass = $this->method->declaringClass();
if (!$methodClass instanceof ReflectionClass) {
return TypeFactory::undefined();
}
if (null === $methodClass->parent()) {
return TypeFactory::undefined();
}
$parentClass = $methodClass->parent();
if (false === $parentClass->methods($reflectionClassLike)->has($this->method->name())) {
return TypeFactory::undefined();
}
return $parentClass->methods($reflectionClassLike)->get($this->method->name())->inferredType();
}
private function getTypesFromInterfaces(ReflectionClassLike $reflectionClassLike): Type
{
if (!$reflectionClassLike instanceof ReflectionClass) {
return TypeFactory::undefined();
}
foreach ($reflectionClassLike->interfaces() as $interface) {
if ($interface->methods()->has($this->method->name())) {
return $interface->methods()->get($this->method->name())->inferredType();
}
}
return TypeFactory::undefined();
}
}