ac447d9db4dcc46e75014c9710be149d3a4e5720
[GitHub/WoltLab/WCF.git] /
1 <?php
2
3 declare(strict_types=1);
4
5 namespace CuyZ\Valinor\QA\PHPStan\Extension;
6
7 use CuyZ\Valinor\Mapper\TreeMapper;
8 use PhpParser\Node\Expr\MethodCall;
9 use PHPStan\Analyser\Scope;
10 use PHPStan\PhpDoc\TypeStringResolver;
11 use PHPStan\Reflection\MethodReflection;
12 use PHPStan\Type\ClassStringType;
13 use PHPStan\Type\Constant\ConstantStringType;
14 use PHPStan\Type\DynamicMethodReturnTypeExtension;
15 use PHPStan\Type\Generic\GenericClassStringType;
16 use PHPStan\Type\MixedType;
17 use PHPStan\Type\ObjectWithoutClassType;
18 use PHPStan\Type\Type;
19 use PHPStan\Type\UnionType;
20
21 final class TreeMapperPHPStanExtension implements DynamicMethodReturnTypeExtension
22 {
23 public function __construct(private TypeStringResolver $resolver) {}
24
25 public function getClass(): string
26 {
27 return TreeMapper::class;
28 }
29
30 public function isMethodSupported(MethodReflection $methodReflection): bool
31 {
32 return $methodReflection->getName() === 'map';
33 }
34
35 public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
36 {
37 $arguments = $methodCall->getArgs();
38
39 if (count($arguments) === 0) {
40 return new MixedType();
41 }
42
43 $type = $scope->getType($arguments[0]->value);
44
45 if ($type instanceof UnionType) {
46 return $type->traverse(fn (Type $type) => $this->type($type));
47 }
48
49 return $this->type($type);
50 }
51
52 private function type(Type $type): Type
53 {
54 if ($type instanceof GenericClassStringType) {
55 return $type->getGenericType();
56 }
57
58 if ($type instanceof ConstantStringType) {
59 return $this->resolver->resolve($type->getValue());
60 }
61
62 if ($type instanceof ClassStringType) {
63 return new ObjectWithoutClassType();
64 }
65
66 return new MixedType();
67 }
68 }