Passed
Push — type-resolver ( 5b5dc4 )
by Luis
10:45
created

TypeResolver::resolveUnionTypes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * PHP version 8.0
4
 *
5
 * This source file is subject to the license that is bundled with this package in the file LICENSE.
6
 */
7
8
namespace PhUml\Parser\Code;
9
10
use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
0 ignored issues
show
Bug introduced by
The type phpDocumentor\Reflection\DocBlock\Tags\InvalidTag was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use phpDocumentor\Reflection\DocBlock\Tags\Param;
0 ignored issues
show
Bug introduced by
The type phpDocumentor\Reflection\DocBlock\Tags\Param was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use phpDocumentor\Reflection\DocBlock\Tags\TagWithType;
0 ignored issues
show
Bug introduced by
The type phpDocumentor\Reflection\DocBlock\Tags\TagWithType was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
13
use phpDocumentor\Reflection\DocBlockFactory;
0 ignored issues
show
Bug introduced by
The type phpDocumentor\Reflection\DocBlockFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use phpDocumentor\Reflection\Type;
0 ignored issues
show
Bug introduced by
The type phpDocumentor\Reflection\Type was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use phpDocumentor\Reflection\Types\Compound;
0 ignored issues
show
Bug introduced by
The type phpDocumentor\Reflection\Types\Compound was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use phpDocumentor\Reflection\Types\Nullable;
0 ignored issues
show
Bug introduced by
The type phpDocumentor\Reflection\Types\Nullable was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use PhUml\Code\Name;
18
use PhUml\Code\UseStatements;
19
use PhUml\Code\Variables\TypeDeclaration;
20
21
final class TypeResolver
22
{
23
    public function __construct(private DocBlockFactory $factory)
24
    {
25
    }
26
27
    public function resolveForParameter(?string $methodComment, string $name, UseStatements $useStatements): TypeDeclaration
28
    {
29
        if ($methodComment === null) {
30
            return TypeDeclaration::absent();
31
        }
32
33
        $docBlock = $this->factory->create($methodComment);
34
35
        /** @var TagWithType[]|InvalidTag[] $parameterTags */
36
        $parameterTags = $docBlock->getTagsByName('param');
37
38
        /** @var Param[] $params */
39
        $params = array_values(array_filter(
40
            $parameterTags,
41
            static fn (TagWithType|InvalidTag $parameter) =>
42
                $parameter instanceof Param && "\${$parameter->getVariableName()}" === $name
43
        ));
44
        if (count($params) < 1) {
45
            return TypeDeclaration::absent();
46
        }
47
48
        [$param] = $params;
49
50
        return $this->declarationFromTagType($param->getType(), $useStatements);
51
    }
52
53
    public function resolveForReturn(?string $methodComment, UseStatements $useStatements): TypeDeclaration
54
    {
55
        if ($methodComment === null) {
56
            return TypeDeclaration::absent();
57
        }
58
59
        $docBlock = $this->factory->create($methodComment);
60
61
        /** @var TagWithType[]|InvalidTag[] $returnTags */
62
        $returnTags = $docBlock->getTagsByName('return');
63
64
        if (count($returnTags) < 1) {
65
            return TypeDeclaration::absent();
66
        }
67
68
        [$return] = $returnTags;
69
        if ($return instanceof InvalidTag) {
70
            return TypeDeclaration::absent();
71
        }
72
73
        return $this->declarationFromTagType($return->getType(), $useStatements);
74
    }
75
76
    public function resolveForAttribute(?string $attributeComment, UseStatements $useStatements): TypeDeclaration
77
    {
78
        if ($attributeComment === null) {
79
            return TypeDeclaration::absent();
80
        }
81
82
        $docBlock = $this->factory->create($attributeComment);
83
84
        /** @var TagWithType[]|InvalidTag[] $varTags */
85
        $varTags = $docBlock->getTagsByName('var');
86
87
        if (count($varTags) < 1) {
88
            return TypeDeclaration::absent();
89
        }
90
91
        [$var] = $varTags;
92
        if ($var instanceof InvalidTag) {
93
            return TypeDeclaration::absent();
94
        }
95
96
        return $this->declarationFromTagType($var->getType(), $useStatements);
97
    }
98
99
    private function declarationFromTagType(?Type $tagType, UseStatements $useStatements): TypeDeclaration
100
    {
101
        return match (true) {
102
            $tagType === null => TypeDeclaration::absent(),
103
            $tagType instanceof Nullable => $this->resolveNullableType($tagType, $useStatements),
0 ignored issues
show
Bug introduced by
It seems like $tagType can also be of type null; however, parameter $nullable of PhUml\Parser\Code\TypeRe...::resolveNullableType() does only seem to accept phpDocumentor\Reflection\Types\Nullable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
            $tagType instanceof Nullable => $this->resolveNullableType(/** @scrutinizer ignore-type */ $tagType, $useStatements),
Loading history...
104
            $tagType instanceof Compound => $this->resolveUnionTypes($tagType, $useStatements),
0 ignored issues
show
Bug introduced by
It seems like $tagType can also be of type null; however, parameter $tagType of PhUml\Parser\Code\TypeRe...er::resolveUnionTypes() does only seem to accept phpDocumentor\Reflection\Types\Compound, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
            $tagType instanceof Compound => $this->resolveUnionTypes(/** @scrutinizer ignore-type */ $tagType, $useStatements),
Loading history...
105
            default => $this->resolveType($tagType, $useStatements)
0 ignored issues
show
Bug introduced by
It seems like $tagType can also be of type null; however, parameter $tagType of PhUml\Parser\Code\TypeResolver::resolveType() does only seem to accept phpDocumentor\Reflection\Type, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

105
            default => $this->resolveType(/** @scrutinizer ignore-type */ $tagType, $useStatements)
Loading history...
106
        };
107
    }
108
109
    private function resolveUnionTypes(Compound $tagType, UseStatements $useStatements): TypeDeclaration
110
    {
111
        $withFullyQualifiedNames = array_map(
112
            fn (string $type) => $useStatements->fullyQualifiedNameFor(new Name($this->unqualify($type))),
113
            $tagType->getIterator()->getArrayCopy()
114
        );
115
        return TypeDeclaration::fromUnionType($withFullyQualifiedNames);
116
    }
117
118
    private function resolveType(Type $tagType, UseStatements $useStatements): TypeDeclaration
119
    {
120
        $type = $this->unqualify((string) $tagType);
121
        $fullyQualifiedName = $useStatements->fullyQualifiedNameFor(new Name($type));
122
        return TypeDeclaration::from($fullyQualifiedName);
123
    }
124
125
    private function resolveNullableType(Nullable $nullable, UseStatements $useStatements): TypeDeclaration
126
    {
127
        $type = $this->unqualify((string) $nullable->getActualType());
128
        $fullyQualifiedName = $useStatements->fullyQualifiedNameFor(new Name($type));
129
        return TypeDeclaration::fromNullable($fullyQualifiedName);
130
    }
131
132
    private function unqualify(string $name): string
133
    {
134
        return ltrim($name, characters: '\\');
135
    }
136
}
137