Completed
Push — master ( 454e04...38876e )
by Marco
21s queued 11s
created

FindReflectionsInTree.php$0 ➔ enterNode()   C

Complexity

Conditions 17

Size

Total Lines 75

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 17

Importance

Changes 0
Metric Value
dl 0
loc 75
rs 5.2166
c 0
b 0
f 0
ccs 19
cts 19
cp 1
cc 17
crap 17

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Roave\BetterReflection\SourceLocator\Ast;
6
7
use Closure;
8
use PhpParser\Node;
9
use PhpParser\Node\Stmt\Namespace_;
10
use PhpParser\NodeTraverser;
11
use PhpParser\NodeVisitor\NameResolver;
12
use PhpParser\NodeVisitorAbstract;
13
use Roave\BetterReflection\Identifier\IdentifierType;
14
use Roave\BetterReflection\Reflection\Exception\InvalidConstantNode;
15
use Roave\BetterReflection\Reflection\Reflection;
16
use Roave\BetterReflection\Reflector\Exception\IdentifierNotFound;
17
use Roave\BetterReflection\Reflector\FunctionReflector;
18
use Roave\BetterReflection\Reflector\Reflector;
19
use Roave\BetterReflection\SourceLocator\Ast\Strategy\AstConversionStrategy;
20
use Roave\BetterReflection\SourceLocator\Located\LocatedSource;
21
use Roave\BetterReflection\Util\ConstantNodeChecker;
22
use function count;
23
24
/**
25
 * @internal
26 6
 */
27
final class FindReflectionsInTree
28 6
{
29 6
    /** @var AstConversionStrategy */
30
    private $astConversionStrategy;
31
32
    /** @var FunctionReflector */
33
    private $functionReflector;
34
35
    /** @var Closure */
36
    private $functionReflectorGetter;
37
38 27
    public function __construct(AstConversionStrategy $astConversionStrategy, Closure $functionReflectorGetter)
39
    {
40
        $this->astConversionStrategy   = $astConversionStrategy;
41
        $this->functionReflectorGetter = $functionReflectorGetter;
42
    }
43
44
    /**
45
     * Find all reflections of a given type in an Abstract Syntax Tree
46
     *
47
     * @param Node[] $ast
48
     *
49
     * @return Reflection[]
50
     */
51
    public function __invoke(
52
        Reflector $reflector,
53
        array $ast,
54
        IdentifierType $identifierType,
55
        LocatedSource $locatedSource
56
    ) : array {
57
        $nodeVisitor = new class($reflector, $identifierType, $locatedSource, $this->astConversionStrategy, $this->functionReflectorGetter->__invoke())
58
            extends NodeVisitorAbstract
59
        {
60
            /** @var Reflection[] */
61
            private $reflections = [];
62
63
            /** @var Reflector */
64
            private $reflector;
65 27
66
            /** @var IdentifierType */
67
            private $identifierType;
68
69
            /** @var LocatedSource */
70
            private $locatedSource;
71 27
72 27
            /** @var AstConversionStrategy */
73 27
            private $astConversionStrategy;
74 27
75 27
            /** @var Namespace_|null */
76
            private $currentNamespace;
77
78
            /** @var FunctionReflector */
79
            private $functionReflector;
80 27
81
            public function __construct(
82 27
                Reflector $reflector,
83 13
                IdentifierType $identifierType,
84
                LocatedSource $locatedSource,
85 13
                AstConversionStrategy $astConversionStrategy,
86
                FunctionReflector $functionReflector
87
            ) {
88 27
                $this->reflector             = $reflector;
89 24
                $this->identifierType        = $identifierType;
90 24
                $this->locatedSource         = $locatedSource;
91
                $this->astConversionStrategy = $astConversionStrategy;
92 24
                $this->functionReflector     = $functionReflector;
93 24
            }
94
95
            /**
96 24
             * {@inheritDoc}
97
             */
98
            public function enterNode(Node $node)
99 27
            {
100 27
                if ($node instanceof Namespace_) {
101
                    $this->currentNamespace = $node;
102
103 2
                    return null;
104
                }
105 2
106 1
                if ($node instanceof Node\Stmt\ClassLike) {
107
                    $classNamespace = $node->name === null ? null : $this->currentNamespace;
108
                    $reflection     = $this->astConversionStrategy->__invoke($this->reflector, $node, $this->locatedSource, $classNamespace);
109 1
110 1
                    if ($this->identifierType->isMatchingReflector($reflection)) {
111
                        $this->reflections[] = $reflection;
112
                    }
113
114
                    return null;
115 27
                }
116
117 27
                if ($node instanceof Node\Stmt\ClassConst) {
118 27
                    return null;
119
                }
120
121 13
                if ($node instanceof Node\Stmt\Const_) {
122 13
                    for ($i = 0; $i < count($node->consts); $i++) {
0 ignored issues
show
Performance Best Practice introduced by Jaroslav Hanslík
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
123
                        $reflection = $this->astConversionStrategy->__invoke($this->reflector, $node, $this->locatedSource, $this->currentNamespace, $i);
124
125
                        if (! $this->identifierType->isMatchingReflector($reflection)) {
126
                            continue;
127 27
                        }
128
129 27
                        $this->reflections[] = $reflection;
130
                    }
131
132
                    return null;
133 27
                }
134 27
135 27
                if ($node instanceof Node\Expr\FuncCall) {
136 27
                    try {
137
                        ConstantNodeChecker::assertValidDefineFunctionCall($node);
138 27
                    } catch (InvalidConstantNode $e) {
139
                        return null;
140
                    }
141
142
                    if ($node->name->hasAttribute('namespacedName') && count($node->name->getAttribute('namespacedName')->parts) > 1) {
143
                        try {
144
                            $this->functionReflector->reflect($node->name->getAttribute('namespacedName')->toString());
145
146
                            return null;
147
                        } catch (IdentifierNotFound $e) {
148
                            // Global define()
149
                        }
150
                    }
151
152
                    $reflection = $this->astConversionStrategy->__invoke($this->reflector, $node, $this->locatedSource, $this->currentNamespace);
153
154
                    if ($this->identifierType->isMatchingReflector($reflection)) {
155
                        $this->reflections[] = $reflection;
156
                    }
157
158
                    return null;
159
                }
160
161
                if (! ($node instanceof Node\Stmt\Function_)) {
162
                    return null;
163
                }
164
165
                $reflection = $this->astConversionStrategy->__invoke($this->reflector, $node, $this->locatedSource, $this->currentNamespace);
166
167
                if (! $this->identifierType->isMatchingReflector($reflection)) {
168
                    return null;
169
                }
170
171
                $this->reflections[] = $reflection;
172
            }
173
174
            /**
175
             * {@inheritDoc}
176
             */
177
            public function leaveNode(Node $node)
178
            {
179
                if (! ($node instanceof Namespace_)) {
180
                    return null;
181
                }
182
183
                $this->currentNamespace = null;
184
            }
185
186
            /**
187
             * @return Reflection[]
188
             */
189
            public function getReflections() : array
190
            {
191
                return $this->reflections;
192
            }
193
        };
194
195
        $nodeTraverser = new NodeTraverser();
196
        $nodeTraverser->addVisitor(new NameResolver());
197
        $nodeTraverser->addVisitor($nodeVisitor);
198
        $nodeTraverser->traverse($ast);
199
200
        return $nodeVisitor->getReflections();
201
    }
202
}
203