TypeNodeParser::invoke()   B
last analyzed

Complexity

Conditions 8
Paths 8

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 17
c 1
b 0
f 0
nc 8
nop 2
dl 0
loc 32
rs 8.4444
1
<?php
2
3
/**
4
 * This file is part of PhpUnitGen.
5
 *
6
 * (c) 2017-2018 Paul Thébaud <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace PhpUnitGen\Parser\NodeParser;
13
14
use PhpParser\Node;
15
use PhpUnitGen\Exception\Exception;
16
use PhpUnitGen\Model\ModelInterface\PhpFileModelInterface;
17
use PhpUnitGen\Model\PropertyInterface\NodeInterface;
18
use PhpUnitGen\Model\PropertyInterface\TypeInterface;
19
use PhpUnitGen\Parser\NodeParserUtil\RootRetrieverHelper;
20
use Respect\Validation\Validator;
21
22
/**
23
 * Class TypeNodeParser.
24
 *
25
 * @author     Paul Thébaud <[email protected]>.
26
 * @copyright  2017-2018 Paul Thébaud <[email protected]>.
27
 * @license    https://opensource.org/licenses/MIT The MIT license.
28
 * @link       https://github.com/paul-thebaud/phpunit-generator
29
 * @since      Class available since Release 2.0.0.
30
 */
31
class TypeNodeParser extends AbstractNodeParser
32
{
33
    /**
34
     * Parse a node to update the parent node model.
35
     *
36
     * @param mixed         $node   The node to parse.
37
     * @param NodeInterface $parent The parent node.
38
     */
39
    public function invoke($node, NodeInterface $parent): void
40
    {
41
        if (! $parent instanceof TypeInterface) {
42
            throw new Exception('TypeNodeParser is made to parse a type node');
43
        }
44
45
        // If it is a nullable type
46
        if ($node instanceof Node\NullableType) {
47
            $parent->setNullable(true);
48
49
            $this->invoke($node->type, $parent);
50
            return;
51
        }
52
        // Handle scalar type in identifier
53
        if ($node instanceof Node\Identifier
54
            && Validator::contains($node->name)->validate(TypeInterface::RESERVED_TYPE_IDENTIFIERS)
55
        ) {
56
            $node = $node->name;
57
        }
58
        // If it is a class like type
59
        if ($node instanceof Node\Name || $node instanceof Node\Identifier) {
60
            $parent->setType(TypeInterface::CUSTOM);
61
            $parent->setCustomType($this->getClassType($node, $parent));
62
            return;
63
        }
64
        // If it is a scalar type
65
        if (Validator::stringType()->validate($node)) {
66
            $parent->setType(constant(TypeInterface::class . '::' . strtoupper($node)));
67
            return;
68
        }
69
70
        throw new Exception('TypeNodeParser is made to parse a type node');
71
    }
72
73
    /**
74
     * Get the class type hint as a string.
75
     *
76
     * @param Node\Name|Node\Identifier $node   The name node to parse.
77
     * @param TypeInterface             $parent The parent to update.
78
     *
79
     * @return string The class type hint.
80
     */
81
    private function getClassType($node, TypeInterface $parent): string
82
    {
83
        $phpFile = RootRetrieverHelper::getRoot($parent);
84
85
        switch (true) {
86
            case $node instanceof Node\Identifier:
87
            case $node->isRelative():
88
            case $node->isUnqualified():
89
                $name = $this->getUnqualifiedClassType($node, $phpFile);
0 ignored issues
show
Bug introduced by
It seems like $phpFile can also be of type null; however, parameter $phpFile of PhpUnitGen\Parser\NodePa...tUnqualifiedClassType() does only seem to accept PhpUnitGen\Model\ModelIn...e\PhpFileModelInterface, 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

89
                $name = $this->getUnqualifiedClassType($node, /** @scrutinizer ignore-type */ $phpFile);
Loading history...
90
                break;
91
            case $node->isFullyQualified():
92
                $name = $node->toString();
93
                break;
94
            case $node->isQualified():
95
                $name = $this->getQualifiedClassType($node, $phpFile);
0 ignored issues
show
Bug introduced by
It seems like $phpFile can also be of type null; however, parameter $phpFile of PhpUnitGen\Parser\NodePa...getQualifiedClassType() does only seem to accept PhpUnitGen\Model\ModelIn...e\PhpFileModelInterface, 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

95
                $name = $this->getQualifiedClassType($node, /** @scrutinizer ignore-type */ $phpFile);
Loading history...
96
                break;
97
            default:
98
                return TypeInterface::UNKNOWN_CUSTOM;
99
        }
100
101
        // Get the last name part
102
        $nameArray = explode('\\', $name);
103
        $lastPart  = end($nameArray);
104
105
        $phpFile->addConcreteUse($name, $lastPart);
106
107
        return $lastPart;
108
    }
109
110
    /**
111
     * Retrieve the class type hint when it is unqualified.
112
     *
113
     * @param Node\Name|Node\Identifier $node    The name node to parse.
114
     * @param PhpFileModelInterface     $phpFile The php file.
115
     *
116
     * @return string The class type hint.
117
     */
118
    private function getUnqualifiedClassType($node, PhpFileModelInterface $phpFile): string
119
    {
120
        $name = $node->toString();
121
        if ($phpFile->hasUse($name)) {
122
            return $phpFile->getUse($name);
123
        }
124
        $namespace = $phpFile->getNamespaceString();
125
        if ($namespace !== null) {
126
            $namespace = $namespace . '\\';
127
        }
128
        return $namespace . $name;
129
    }
130
131
    /**
132
     * Retrieve the class type hint when it is qualified.
133
     *
134
     * @param Node\Name             $node    The name node to parse.
135
     * @param PhpFileModelInterface $phpFile The php file.
136
     *
137
     * @return string The class type hint.
138
     */
139
    private function getQualifiedClassType(Node\Name $node, PhpFileModelInterface $phpFile): string
140
    {
141
        $path      = $node->toString();
142
        $firstPart = $node->getFirst();
143
144
        if ($phpFile->hasUse($firstPart)) {
145
            return str_replace($firstPart, $phpFile->getUse($firstPart), $path);
146
        }
147
        if ($phpFile->getNamespace() !== null
148
            && $firstPart === $phpFile->getNamespace()[count($phpFile->getNamespace()) - 1]
149
        ) {
150
            return str_replace($firstPart, $phpFile->getNamespaceString(), $path);
151
        }
152
        return $phpFile->getNamespaceString() . '\\' . $path;
153
    }
154
}
155