Failed Conditions
Push — new-parser-ast-metadata ( cfd696...cc9a79 )
by Michael
02:12
created

AstBuilder::visitUnnamedParameter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Annotations\Parser\Visitor;
6
7
use Doctrine\Annotations\Parser\Ast\Annotation;
8
use Doctrine\Annotations\Parser\Ast\Annotations;
9
use Doctrine\Annotations\Parser\Ast\ClassConstantFetch;
10
use Doctrine\Annotations\Parser\Ast\Collection\ListCollection;
11
use Doctrine\Annotations\Parser\Ast\Collection\MapCollection;
12
use Doctrine\Annotations\Parser\Ast\ConstantFetch;
13
use Doctrine\Annotations\Parser\Ast\Node;
14
use Doctrine\Annotations\Parser\Ast\Pair;
15
use Doctrine\Annotations\Parser\Ast\Parameter\NamedParameter;
16
use Doctrine\Annotations\Parser\Ast\Parameter\UnnamedParameter;
17
use Doctrine\Annotations\Parser\Ast\Parameters;
18
use Doctrine\Annotations\Parser\Ast\Reference;
19
use Doctrine\Annotations\Parser\Ast\Scalar;
20
use Doctrine\Annotations\Parser\Ast\Scalar\BooleanScalar;
21
use Doctrine\Annotations\Parser\Ast\Scalar\FloatScalar;
22
use Doctrine\Annotations\Parser\Ast\Scalar\Identifier;
23
use Doctrine\Annotations\Parser\Ast\Scalar\IntegerScalar;
24
use Doctrine\Annotations\Parser\Ast\Scalar\NullScalar;
25
use Doctrine\Annotations\Parser\Ast\Scalar\StringScalar;
26
use Doctrine\Annotations\Parser\Nodes;
27
use Doctrine\Annotations\Parser\Tokens;
28
use Hoa\Compiler\Llk\TreeNode;
29
use Hoa\Visitor\Element;
30
use Hoa\Visitor\Visit;
31
use function assert;
32
use function ltrim;
33
use function sprintf;
34
use function str_replace;
35
use function strcasecmp;
36
37
final class AstBuilder implements Visit
38
{
39
    /**
40
     * @param mixed $handle
41
     * @param mixed $eldnah
42
     */
43 29
    public function visit(Element $node, &$handle = null, $eldnah = null) : Node
44
    {
45 29
        assert($node instanceof TreeNode);
46
47 29
        if ($node->isToken()) {
48 16
            return $this->visitToken($node);
49
        }
50
51 29
        return $this->visitNode($node);
52
    }
53
54 29
    private function visitNode(TreeNode $node) : Node
55
    {
56 29
        switch ($node->getId()) {
57
            case Nodes::ANNOTATIONS:
58 29
                return $this->visitAnnotations($node);
59
            case Nodes::ANNOTATION:
60 28
                return $this->visitAnnotation($node);
61
            case Nodes::PAIR:
62 3
                return $this->visitPair($node);
63
            case Nodes::PARAMETERS:
64 22
                return $this->visitParameters($node);
65
            case Nodes::NAMED_PARAMETERS:
66 13
                return $this->visitNamedParameter($node);
67
            case Nodes::UNNAMED_PARAMETERS:
68 15
                return $this->visitUnnamedParameter($node);
69
            case Nodes::VALUE:
70 22
                return $this->visitValue($node);
71
            case Nodes::MAP:
72 3
                return $this->visitMap($node);
73
            case Nodes::LIST:
74 6
                return $this->visitList($node);
75
            case Nodes::STANDALONE_CONSTANT:
76
                return $this->visitStandaloneConstant($node);
77
            case Nodes::CLASS_CONSTANT:
78 3
                return $this->visitClassConstant($node);
79
            case Nodes::REFERENCE:
80 3
                return $this->visitReference($node);
81
            case Nodes::STRING:
82 15
                return $this->visitString($node);
83
        }
84
85
        assert(false, sprintf('Unsupported node %s.', $node->getId()));
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Doctrine\Annotations\Parser\Ast\Node. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
86
    }
87
88 16
    private function visitToken(TreeNode $node) : Scalar
89
    {
90 16
        $value = $node->getValueValue();
91
92 16
        switch ($node->getValueToken()) {
93 16
            case Tokens::IDENTIFIER:
94 14
                return new Identifier($value);
95 10
            case Tokens::NULL:
96 1
                return new NullScalar();
97 10
            case Tokens::BOOLEAN:
98 4
                return new BooleanScalar(strcasecmp($value, 'true') === 0);
99 8
            case Tokens::INTEGER:
100 8
                $intValue = (int) $value;
101 8
                assert((string) $intValue === $value, 'Integer overflow');
102
103 8
                return new IntegerScalar($intValue);
104 3
            case Tokens::FLOAT:
105 3
                return new FloatScalar((float) $value);
106
        }
107
108
        assert(false, sprintf('Unsupported token %s.', $node->getValueToken()));
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Doctrine\Annotations\Parser\Ast\Scalar. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
109
    }
110
111 29
    private function visitAnnotations(TreeNode $node) : Annotations
112
    {
113 29
        return new Annotations(
114
            ...(function (TreeNode ...$nodes) : iterable {
115 29
                foreach ($nodes as $node) {
116 28
                    yield $node->accept($this);
117
                }
118 29
            })(...$node->getChildren())
119
        );
120
    }
121
122 28
    private function visitAnnotation(TreeNode $node) : Annotation
123
    {
124 28
        $identifier = $node->getChild(0)->getValueValue();
125
126 28
        return new Annotation(
127 28
            new Reference(ltrim($identifier, '\\'), $identifier[0] === '\\'),
128 28
            $node->childExists(1) ? $node->getChild(1)->accept($this) : new Parameters()
0 ignored issues
show
Bug introduced by
It seems like $node->childExists(1) ? ...Parser\Ast\Parameters() can also be of type Doctrine\Annotations\Par...st\Scalar\BooleanScalar and Doctrine\Annotations\Parser\Ast\Scalar\FloatScalar and Doctrine\Annotations\Parser\Ast\Scalar\Identifier and Doctrine\Annotations\Par...st\Scalar\IntegerScalar and Doctrine\Annotations\Parser\Ast\Scalar\NullScalar; however, parameter $parameters of Doctrine\Annotations\Par...notation::__construct() does only seem to accept Doctrine\Annotations\Parser\Ast\Parameters, 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

128
            /** @scrutinizer ignore-type */ $node->childExists(1) ? $node->getChild(1)->accept($this) : new Parameters()
Loading history...
129
        );
130
    }
131
132 3
    private function visitPair(TreeNode $node) : Pair
133
    {
134 3
        return new Pair(
135 3
            $node->getChild(0)->accept($this),
136 3
            $node->getChild(1)->accept($this)
137
        );
138
    }
139
140 22
    private function visitParameters(TreeNode $node) : Parameters
141
    {
142 22
        return new Parameters(
143
            ...(function (TreeNode ...$nodes) : iterable {
144 22
                foreach ($nodes as $node) {
145 22
                    yield $node->accept($this);
146
                }
147 22
            })(...$node->getChildren())
148
        );
149
    }
150
151 13
    private function visitNamedParameter(TreeNode $node) : NamedParameter
152
    {
153 13
        return new NamedParameter(
154 13
            $node->getChild(0)->accept($this),
0 ignored issues
show
Bug introduced by
It seems like $node->getChild(0)->accept($this) can also be of type Doctrine\Annotations\Par...st\Scalar\BooleanScalar and Doctrine\Annotations\Parser\Ast\Scalar\FloatScalar and Doctrine\Annotations\Par...st\Scalar\IntegerScalar and Doctrine\Annotations\Parser\Ast\Scalar\NullScalar; however, parameter $name of Doctrine\Annotations\Par...arameter::__construct() does only seem to accept Doctrine\Annotations\Parser\Ast\Scalar\Identifier, 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

154
            /** @scrutinizer ignore-type */ $node->getChild(0)->accept($this),
Loading history...
155 13
            $node->getChild(1)->accept($this)
156
        );
157
    }
158
159 15
    private function visitUnnamedParameter(TreeNode $node) : UnnamedParameter
160
    {
161 15
        return new UnnamedParameter($node->getChild(0)->accept($this));
162
    }
163
164 22
    private function visitValue(TreeNode $node) : Node
165
    {
166 22
        return $node->getChild(0)->accept($this);
167
    }
168
169 3
    private function visitMap(TreeNode $node) : MapCollection
170
    {
171 3
        return new MapCollection(
172
            ...(function (TreeNode ...$nodes) : iterable {
173 3
                foreach ($nodes as $node) {
174 3
                    yield $node->accept($this);
175
                }
176 3
            })(...$node->getChildren())
177
        );
178
    }
179
180 6
    private function visitList(TreeNode $node) : ListCollection
181
    {
182 6
        return new ListCollection(
183
            ...(function (TreeNode ...$nodes) : iterable {
184 6
                foreach ($nodes as $node) {
185 6
                    yield $node->accept($this);
186
                }
187 6
            })(...$node->getChildren())
188
        );
189
    }
190
191
    private function visitStandaloneConstant(TreeNode $node) : ConstantFetch
192
    {
193
        return new ConstantFetch($node->getChild(0)->accept($this));
0 ignored issues
show
Bug introduced by
It seems like $node->getChild(0)->accept($this) can also be of type Doctrine\Annotations\Par...st\Scalar\BooleanScalar and Doctrine\Annotations\Parser\Ast\Scalar\FloatScalar and Doctrine\Annotations\Par...st\Scalar\IntegerScalar and Doctrine\Annotations\Parser\Ast\Scalar\NullScalar; however, parameter $name of Doctrine\Annotations\Par...antFetch::__construct() does only seem to accept Doctrine\Annotations\Parser\Ast\Scalar\Identifier, 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

193
        return new ConstantFetch(/** @scrutinizer ignore-type */ $node->getChild(0)->accept($this));
Loading history...
194
    }
195
196 3
    private function visitClassConstant(TreeNode $node) : ClassConstantFetch
197
    {
198 3
        return new ClassConstantFetch(
199 3
            $node->getChild(0)->accept($this),
200 3
            $node->getChild(1)->accept($this)
0 ignored issues
show
Bug introduced by
It seems like $node->getChild(1)->accept($this) can also be of type Doctrine\Annotations\Par...st\Scalar\BooleanScalar and Doctrine\Annotations\Parser\Ast\Scalar\FloatScalar and Doctrine\Annotations\Par...st\Scalar\IntegerScalar and Doctrine\Annotations\Parser\Ast\Scalar\NullScalar; however, parameter $name of Doctrine\Annotations\Par...antFetch::__construct() does only seem to accept Doctrine\Annotations\Parser\Ast\Scalar\Identifier, 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

200
            /** @scrutinizer ignore-type */ $node->getChild(1)->accept($this)
Loading history...
201
        );
202
    }
203
204 3
    private function visitReference(TreeNode $node) : Reference
205
    {
206 3
        $child = $node->getChild(0);
207 3
        $value = $child->getValueValue();
208
209 3
        if ($child->getValueToken() === Tokens::NAMESPACED_IDENTIFIER && $value[0] === '\\') {
210 1
            return new Reference(ltrim($value, '\\'), true);
211
        }
212
213 3
        return new Reference($value, false);
214
    }
215
216 15
    private function visitString(TreeNode $node) : StringScalar
217
    {
218 15
        return new StringScalar(str_replace('\\\\', '\\', $node->getChild(0) ? $node->getChild(0)->getValueValue() : ''));
219
    }
220
}
221