Passed
Push — master ( 056350...65484c )
by Satoshi
05:02
created

ExtraPhpDocTagResolver::resolveDepsInternalTag()   C

Complexity

Conditions 12
Paths 192

Size

Total Lines 71
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 45
nc 192
nop 1
dl 0
loc 71
rs 6.2
c 0
b 0
f 0

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
declare(strict_types=1);
3
4
namespace DependencyAnalyzer\DependencyGraph;
5
6
use DependencyAnalyzer\DependencyDumper;
7
use DependencyAnalyzer\DependencyGraph\ExtraPhpDocTagResolver\DepsInternal;
8
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName as FQSEN;
9
use DependencyAnalyzer\Exceptions\InvalidFullyQualifiedStructureElementNameException;
10
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
11
use PHPStan\PhpDocParser\Lexer\Lexer;
12
use PHPStan\PhpDocParser\Parser\PhpDocParser;
13
use PHPStan\PhpDocParser\Parser\TokenIterator;
14
use PHPStan\Reflection\ClassReflection;
15
16
class ExtraPhpDocTagResolver
17
{
18
    const DEPS_INTERNAL = '@deps-internal';
19
    const ONLY_USED_BY_TAGS = '@canOnlyUsedBy';
20
    const DEPENDER_TAGS = '@dependee';
21
    const DEPENDEE_TAGS = '@dependee';
22
23
    /**
24
     * @var Lexer
25
     */
26
    protected $phpDocLexer;
27
28
    /**
29
     * @var PhpDocParser
30
     */
31
    protected $phpDocParser;
32
33
    public function __construct(Lexer $phpDocLexer, PhpDocParser $phpDocParser)
34
    {
35
        $this->phpDocLexer = $phpDocLexer;
36
        $this->phpDocParser = $phpDocParser;
37
    }
38
39
    public function collectExtraPhpDocs(\ReflectionClass $reflectionClass)
40
    {
41
//        $this->resolveInternalTag($reflectionClass);
42
        $this->resolveDepsInternalTag($reflectionClass);
43
//        $this->resolveUsesTag($reflectionClass);
44
    }
45
46
    /**
47
     * @param \ReflectionClass $reflectionClass
48
     * @return DepsInternal[]
49
     */
50
    public function resolveDepsInternalTag(\ReflectionClass $reflectionClass): array
51
    {
52
        $ret = [];
53
54
        if ($this->haveTag($reflectionClass, self::DEPS_INTERNAL)) {
55
            try {
56
                $ret[] = new DepsInternal(
57
                    FQSEN::createClass($reflectionClass->getName()),
58
                    $this->resolve($reflectionClass->getDocComment(), self::DEPS_INTERNAL)
0 ignored issues
show
Bug introduced by
It seems like $reflectionClass->getDocComment() can also be of type boolean; however, parameter $phpdoc of DependencyAnalyzer\Depen...cTagResolver::resolve() does only seem to accept string, 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

58
                    $this->resolve(/** @scrutinizer ignore-type */ $reflectionClass->getDocComment(), self::DEPS_INTERNAL)
Loading history...
59
                );
60
            } catch (InvalidFullyQualifiedStructureElementNameException $e) {
61
                DependencyDumper::getObserver()->notifyResolvePhpDocError(
62
                    $reflectionClass->getFileName(),
63
                    FQSEN::createClass($reflectionClass->getName()),
0 ignored issues
show
Bug introduced by
DependencyAnalyzer\Depen...ectionClass->getName()) of type DependencyAnalyzer\Depen...turalElementName\Class_ is incompatible with the type DependencyAnalyzer\Depen...edStructuralElementName expected by parameter $fqsen of DependencyAnalyzer\Depen...ifyResolvePhpDocError(). ( Ignorable by Annotation )

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

63
                    /** @scrutinizer ignore-type */ FQSEN::createClass($reflectionClass->getName()),
Loading history...
64
                    $e
65
                );
66
            }
67
        }
68
69
        foreach ($reflectionClass->getProperties() as $reflectionProperty) {
70
            if ($this->haveTag($reflectionProperty, self::DEPS_INTERNAL)) {
71
                try {
72
                    $ret[] = new DepsInternal(
73
                        FQSEN::createProperty($reflectionClass->getName(), $reflectionProperty->getName()),
74
                        $this->resolve($reflectionProperty->getDocComment(), self::DEPS_INTERNAL)
75
                    );
76
                } catch (InvalidFullyQualifiedStructureElementNameException $e) {
77
                    DependencyDumper::getObserver()->notifyResolvePhpDocError(
78
                        $reflectionClass->getFileName(),
79
                        FQSEN::createClass($reflectionClass->getName()),
80
                        $e
81
                    );
82
                }
83
            }
84
        }
85
86
        foreach ($reflectionClass->getMethods() as $reflectionMethod) {
87
            if ($this->haveTag($reflectionMethod, self::DEPS_INTERNAL)) {
88
                try {
89
                    $ret[] = new DepsInternal(
90
                        FQSEN::createMethod($reflectionClass->getName(), $reflectionMethod->getName()),
91
                        $this->resolve($reflectionMethod->getDocComment(), self::DEPS_INTERNAL)
92
                    );
93
                } catch (InvalidFullyQualifiedStructureElementNameException $e) {
94
                    DependencyDumper::getObserver()->notifyResolvePhpDocError(
95
                        $reflectionClass->getFileName(),
96
                        FQSEN::createClass($reflectionClass->getName()),
97
                        $e
98
                    );
99
                }
100
            }
101
        }
102
103
        foreach ($reflectionClass->getReflectionConstants() as $reflectionClassConstant) {
104
            if ($this->haveTag($reflectionClassConstant, self::DEPS_INTERNAL)) {
105
                try {
106
                    $ret[] = new DepsInternal(
107
                        FQSEN::createClassConstant($reflectionClass->getName(), $reflectionClassConstant->getName()),
108
                        $this->resolve($reflectionClassConstant->getDocComment(), self::DEPS_INTERNAL)
109
                    );
110
                } catch (InvalidFullyQualifiedStructureElementNameException $e) {
111
                    DependencyDumper::getObserver()->notifyResolvePhpDocError(
112
                        $reflectionClass->getFileName(),
113
                        FQSEN::createClass($reflectionClass->getName()),
114
                        $e
115
                    );
116
                }
117
            }
118
        }
119
120
        return $ret;
121
    }
122
123
    protected function resolveInternalTag(\ReflectionClass $reflectionClass)
124
    {
125
        $phpDocs = [];
126
127
        $phpDocs[] = $reflectionClass->getDocComment();
128
        foreach ($reflectionClass->getProperties() as $reflectionProperty) {
129
            $phpDocs[] = $reflectionProperty->getDocComment();
130
        }
131
        foreach ($reflectionClass->getMethods() as $reflectionMethod) {
132
            $phpDocs[] = $reflectionMethod->getDocComment();
133
        }
134
        foreach ($reflectionClass->getReflectionConstants() as $reflectionClassConstant) {
135
            $phpDocs[] = $reflectionClassConstant->getDocComment();
136
        }
137
138
139
    }
140
141
142
    protected function resolveUsesTag(\ReflectionClass $reflectionClass)
143
    {
144
        $reflectionClass->getDocComment();
145
    }
146
147
    public function resolveCanOnlyUsedByTag(\ReflectionClass $classReflection): array
148
    {
149
        if ($phpdoc = $classReflection->getDocComment()) {
150
            return $this->resolve($phpdoc, self::ONLY_USED_BY_TAGS);
0 ignored issues
show
Bug introduced by
It seems like $phpdoc can also be of type true; however, parameter $phpdoc of DependencyAnalyzer\Depen...cTagResolver::resolve() does only seem to accept string, 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

150
            return $this->resolve(/** @scrutinizer ignore-type */ $phpdoc, self::ONLY_USED_BY_TAGS);
Loading history...
151
        }
152
153
        return [];
154
//        $ret = [];
155
//        if ($phpdoc = $classReflection->getNativeReflection()->getDocComment()) {
156
//            $ret['class_must_have_special_chars_of_method'] = $this->resolve($phpdoc, self::ONLY_USED_BY_TAGS);
157
//        }
158
//
159
//        foreach ($classReflection->getNativeReflection()->getMethods() as $reflectionMethod) {
160
//            $phpdoc = $reflectionMethod->getDocComment();  // /**\n  * Hogefuga
161
//            $ret[$reflectionMethod->getName()] = $this->resolve($phpdoc, self::ONLY_USED_BY_TAGS);
162
//        }
163
//
164
//        return [];
165
    }
166
167
    /**
168
     * @param ClassReflection $classReflection
169
     * @return string[]
170
     */
171
    public function resolveDependerTag(ClassReflection $classReflection): array
172
    {
173
        if ($phpdoc = $classReflection->getNativeReflection()->getDocComment()) {
174
            return $this->resolve($phpdoc, self::DEPENDER_TAGS);
0 ignored issues
show
Bug introduced by
It seems like $phpdoc can also be of type true; however, parameter $phpdoc of DependencyAnalyzer\Depen...cTagResolver::resolve() does only seem to accept string, 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

174
            return $this->resolve(/** @scrutinizer ignore-type */ $phpdoc, self::DEPENDER_TAGS);
Loading history...
175
        }
176
177
        return [];
178
    }
179
180
    /**
181
     * @param ClassReflection $classReflection
182
     * @return string[]
183
     */
184
    public function resolveDependeeTag(ClassReflection $classReflection): array
185
    {
186
        if ($phpdoc = $classReflection->getNativeReflection()->getDocComment()) {
187
            return $this->resolve($phpdoc, self::DEPENDEE_TAGS);
0 ignored issues
show
Bug introduced by
It seems like $phpdoc can also be of type true; however, parameter $phpdoc of DependencyAnalyzer\Depen...cTagResolver::resolve() does only seem to accept string, 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

187
            return $this->resolve(/** @scrutinizer ignore-type */ $phpdoc, self::DEPENDEE_TAGS);
Loading history...
188
        }
189
190
        return [];
191
    }
192
193
    protected function haveTag(\Reflector $reflector, string $tag): bool
194
    {
195
        if (!method_exists($reflector, 'getDocComment') && $reflector->getDocComment() !== false) {
0 ignored issues
show
Bug introduced by
The method getDocComment() does not exist on Reflector. It seems like you code against a sub-type of said class. However, the method does not exist in ReflectionExtension or ReflectionZendExtension or ReflectionParameter. Are you sure you never get one of those? ( Ignorable by Annotation )

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

195
        if (!method_exists($reflector, 'getDocComment') && $reflector->/** @scrutinizer ignore-call */ getDocComment() !== false) {
Loading history...
196
            return false;
197
        } elseif (($docComment = $reflector->getDocComment()) === false) {
0 ignored issues
show
Unused Code introduced by
The assignment to $docComment is dead and can be removed.
Loading history...
198
            return false;
199
    }
200
201
        $tokens = new TokenIterator($this->phpDocLexer->tokenize($reflector->getDocComment()));
202
        $phpDocNode = $this->phpDocParser->parse($tokens);
203
204
        foreach ($phpDocNode->getTagsByName($tag) as $phpDocTagNode) {
205
            /** @var PhpDocTagNode $phpDocTagNode */
206
            if (preg_match('/^' . $tag . '/', $phpDocTagNode->__toString()) === 1) {
207
                return true;
208
            }
209
        }
210
211
        return false;
212
    }
213
214
    protected function resolve(string $phpdoc, string $tag): array
215
    {
216
        $tokens = new TokenIterator($this->phpDocLexer->tokenize($phpdoc));
217
        $phpDocNode = $this->phpDocParser->parse($tokens);
218
219
        $ret = [];
220
        foreach ($phpDocNode->getTagsByName($tag) as $phpDocTagNode) {
221
            /** @var PhpDocTagNode $phpDocTagNode */
222
            if (preg_match('/^' . $tag . '\s+(.+)$/', $phpDocTagNode->__toString(), $matches) === 1) {
223
                $ret[] = $matches[1];
224
            }
225
        };
226
227
        return $ret;
228
    }
229
}
230