GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#837)
by E
07:31 queued 05:03
created

Backend::parseClassLists()   D

Complexity

Conditions 10
Paths 48

Size

Total Lines 43
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 10.1

Importance

Changes 0
Metric Value
cc 10
eloc 22
nc 48
nop 0
dl 0
loc 43
ccs 18
cts 20
cp 0.9
crap 10.1
rs 4.8196
c 0
b 0
f 0

How to fix   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 declare(strict_types=1);
2
3
namespace ApiGen\Parser\Broker;
4
5
use ApiGen\Contracts\Parser\Broker\BackendInterface;
6
use ApiGen\Contracts\Parser\Reflection\Behavior\InNamespaceInterface;
7
use ApiGen\Contracts\Parser\Reflection\ClassReflectionInterface;
8
use ApiGen\Contracts\Parser\Reflection\ConstantReflectionInterface;
9
use ApiGen\Contracts\Parser\Reflection\FunctionReflectionInterface;
10
use ApiGen\Contracts\Parser\Reflection\MethodReflectionInterface;
11
use ApiGen\Contracts\Parser\Reflection\TokenReflection\ReflectionFactoryInterface;
12
use ApiGen\Parser\Reflection\ReflectionClass;
13
use ApiGen\Parser\Reflection\ReflectionFunction;
14
use ApiGen\Parser\Reflection\ReflectionMethod;
15
use TokenReflection;
16
use TokenReflection\Broker;
17
use TokenReflection\IReflectionConstant;
18
use TokenReflection\IReflectionFunction;
19
use TokenReflection\Resolver;
20
21
/**
22
 * Customized TokenReflection broker backend.
23
 * Adds internal classes from @param, @var, @return, @throws annotations as well
24
 * as parent classes to the overall class list.
25
 *
26
 * @method TokenReflection\ReflectionNamespace[] getNamespaces()
27
 */
28
final class Backend extends Broker\Backend\Memory implements BackendInterface
0 ignored issues
show
Bug introduced by
There is one abstract method getClasses in this class; you could implement it, or declare this class as abstract.
Loading history...
29
{
30
    /**
31
     * @var ClassReflectionInterface[][]
32
     */
33
    private $allClasses = [
34
        self::TOKENIZED_CLASSES => [],
35
        self::INTERNAL_CLASSES => [],
36
        self::NONEXISTENT_CLASSES => []
37
    ];
38
39
    /**
40
     * @var mixed[]
41
     */
42
    private $declared = [];
43
44
    /**
45
     * @var ReflectionFactoryInterface
46
     */
47
    private $reflectionFactory;
48 138
49
    public function __construct(ReflectionFactoryInterface $reflectionFactory)
50 138
    {
51 138
        $this->reflectionFactory = $reflectionFactory;
52
    }
53
54
    /**
55
     * @return ConstantReflectionInterface[]
56 131
     */
57
    public function getConstants(): array
58
    {
59 12
        return array_map(function (IReflectionConstant $constant) {
60 131
            return $this->reflectionFactory->createFromReflection($constant);
61
        }, parent::getConstants());
62
    }
63
64
    /**
65
     * @return FunctionReflectionInterface[]
66 131
     */
67
    public function getFunctions(): array
68
    {
69 8
        return array_map(function (IReflectionFunction $function) {
70 131
            return $this->reflectionFactory->createFromReflection($function);
71
        }, parent::getFunctions());
72
    }
73
74
    /**
75
     * @return ClassReflectionInterface[]
76 131
     */
77
    protected function parseClassLists(): array
78 131
    {
79
        $this->declared = array_flip(array_merge(get_declared_classes(), get_declared_interfaces()));
80
81
        foreach ($this->getNamespaces() as $namespace) {
82
            foreach ($namespace->getClasses() as $name => $ref) {
83
                $class = $this->reflectionFactory->createFromReflection($ref);
84 131
85 131
                $this->allClasses[self::TOKENIZED_CLASSES][$name] = $class;
86 126
                if (! $class->isDocumented()) {
87
                    continue;
88 126
                }
89 126
90
                $this->loadParentClassesAndInterfacesFromClassReflection($ref);
91
            }
92
        }
93 131
94
        foreach ($this->allClasses[self::TOKENIZED_CLASSES] as $class) {
95
            if (! $class->isDocumented()) {
96
                continue;
97 131
            }
98 126
99
            foreach ($class->getOwnMethods() as $method) {
100
                $this->processFunction($method);
101
            }
102 126
103 108
            foreach ($class->getOwnProperties() as $property) {
104
                $this->loadAnnotationFromReflection($class, $property->getAnnotations(), 'var');
105
            }
106 126
        }
107 126
108
        foreach ($this->getFunctions() as $function) {
109
            $this->processFunction($function);
110
        }
111 131
112 8
        array_walk_recursive($this->allClasses, function (&$reflection) {
113
            if (! $reflection instanceof ReflectionClass) {
114
                $reflection = $this->reflectionFactory->createFromReflection($reflection);
115 131
            }
116 126
        });
117
118
        return $this->allClasses;
119 131
    }
120
121 131
    /**
122
     * Processes a function/method and adds classes from annotations to the overall class array.
123
     *
124
     * @param ReflectionMethod|ReflectionFunction $reflection
125
     */
126
    private function processFunction($reflection): void
127
    {
128
        $annotations = $reflection->getAnnotations();
129 116
        foreach (['param', 'return', 'throws'] as $annotation) {
130
            $this->loadAnnotationFromReflection($reflection, $annotations, $annotation);
131 116
        }
132 116
133 116
        foreach ($reflection->getParameters() as $parameter) {
134
            $hint = $parameter->getClassName();
135
            if ($hint) {
136 116
                $this->addClass($hint);
137 61
            }
138 61
        }
139
    }
140
141
    /**
142 116
     * @return false|void
143
     */
144
    private function addClass(string $name)
145
    {
146
        $name = ltrim($name, '\\');
147 108
148
        if (! isset($this->declared[$name]) || $this->isClassLoaded($name)) {
149 108
            return false;
150
        }
151 108
152 108
        $parameterClass = $this->getBroker()->getClass($name);
153
154
        if ($parameterClass->isInternal()) {
155
            $this->allClasses[self::INTERNAL_CLASSES][$name] = $parameterClass;
156
            $parentClasses = array_merge($parameterClass->getInterfaces(), $parameterClass->getParentClasses());
157
            foreach ($parentClasses as $parentClass) {
158
                $parentName = $parentClass->getName();
159
160
                if (! isset($this->allClasses[self::INTERNAL_CLASSES][$parentName])) {
161
                    $this->allClasses[self::INTERNAL_CLASSES][$parentName] = $parentClass;
162
                }
163
            }
164
        } elseif (! $parameterClass->isTokenized()) {
165
            if (! isset($this->allClasses[self::NONEXISTENT_CLASSES][$name])) {
166
                $this->allClasses[self::NONEXISTENT_CLASSES][$name] = $parameterClass;
167
            }
168
        }
169
    }
170
171
    /**
172
     * @param TokenReflection\ReflectionClass|TokenReflection\Invalid\ReflectionClass $reflection
173 126
     */
174
    private function loadParentClassesAndInterfacesFromClassReflection($reflection): void
175 126
    {
176 126
        $reflectionRelatedClassElements = array_merge($reflection->getParentClasses(), $reflection->getInterfaces());
177
        foreach ($reflectionRelatedClassElements as $parentName => $parentReflection) {
178 56
            /** @var TokenReflection\ReflectionClass $parentReflection */
179
            if ($parentReflection->isInternal()) {
180 View Code Duplication
                if (! isset($this->allClasses[self::INTERNAL_CLASSES][$parentName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
                    $this->allClasses[self::INTERNAL_CLASSES][$parentName] = $parentReflection;
182
                }
183 View Code Duplication
            } elseif (! $parentReflection->isTokenized()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184 126
                if (! isset($this->allClasses[self::NONEXISTENT_CLASSES][$parentName])) {
185
                    $this->allClasses[self::NONEXISTENT_CLASSES][$parentName] = $parentReflection;
186
                }
187
            }
188
        }
189
    }
190
191
    private function isClassLoaded(string $name): bool
192
    {
193
        return isset($this->allClasses[self::TOKENIZED_CLASSES][$name])
194
            || isset($this->allClasses[self::INTERNAL_CLASSES][$name])
195
            || isset($this->allClasses[self::NONEXISTENT_CLASSES][$name]);
196
    }
197
198 116
    /**
199
     * @param ClassReflectionInterface|MethodReflectionInterface $reflection
200 116
     * @param mixed[] $annotations
201 116
     * @param string $name
202
     */
203
    private function loadAnnotationFromReflection($reflection, array $annotations, $name): void
204 108
    {
205 108
        if (! isset($annotations[$name])) {
206 108
            return;
207 108
        }
208 108
209 108
        foreach ($annotations[$name] as $doc) {
210
            foreach (explode('|', preg_replace('~\\s.*~', '', $doc)) as $name) {
211
                $name = rtrim($name, '[]');
212
                if ($name) {
213 108
                    $name = $this->getClassFqn($name, $reflection);
214
                    $this->addClass($name);
215
                }
216
            }
217
        }
218
    }
219 108
220
    /**
221 108
     * @param string $name
222
     * @param ClassReflectionInterface|MethodReflectionInterface|InNamespaceInterface $reflection
223 108
     */
224 108
    private function getClassFqn(string $name, $reflection): string
225
    {
226
        return Resolver::resolveClassFQN(
227
            $name,
228
            $reflection->getNamespaceAliases(),
229
            $reflection->getNamespaceName()
230
        );
231
    }
232
}
233