Completed
Pull Request — master (#194)
by
unknown
05:57
created

UsedSymbolCollector   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Test Coverage

Coverage 97.67%

Importance

Changes 10
Bugs 1 Features 0
Metric Value
wmc 44
eloc 62
c 10
b 1
f 0
dl 0
loc 176
ccs 84
cts 86
cp 0.9767
rs 8.8798

15 Methods

Rating   Name   Duplication   Size   Complexity  
B recordFunctionParameterTypesUsage() 0 11 7
A getCollectedSymbols() 0 3 1
A recordCatchUsage() 0 5 3
A __construct() 0 2 1
A recordImplementsUsage() 0 4 2
A beforeTraverse() 0 5 1
A recordFunctionCallUsage() 0 6 3
A recordExtendsUsage() 0 8 3
B recordClassExpressionUsage() 0 11 7
A enterNode() 0 13 1
A recordConstantFetchUsage() 0 4 2
A recordUsageOfByString() 0 3 1
A recordUsageOf() 0 3 1
A recordTraitUsage() 0 15 5
A recordFunctionReturnTypeUsage() 0 15 6

How to fix   Complexity   

Complex Class

Complex classes like UsedSymbolCollector often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UsedSymbolCollector, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace ComposerRequireChecker\NodeVisitor;
4
5
use PhpParser\Node;
6
use PhpParser\NodeVisitorAbstract;
7
8
final class UsedSymbolCollector extends NodeVisitorAbstract
9
{
10
    /**
11
     * @var mixed[]
12
     */
13
    private $collectedSymbols = [];
14
15 26
    public function __construct()
16
    {
17 26
    }
18
19
    /**
20
     * @return string[]
21
     */
22 26
    public function getCollectedSymbols(): array
23
    {
24 26
        return array_keys($this->collectedSymbols);
25
    }
26
27
    /**
28
     * {@inheritDoc}
29
     */
30 5
    public function beforeTraverse(array $nodes)
31
    {
32 5
        $this->collectedSymbols = [];
33
34 5
        return parent::beforeTraverse($nodes);
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::beforeTraverse($nodes) targeting PhpParser\NodeVisitorAbstract::beforeTraverse() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
35
    }
36
37
    /**
38
     * {@inheritDoc}
39
     */
40 26
    public function enterNode(Node $node)
41
    {
42 26
        $this->recordExtendsUsage($node);
43 26
        $this->recordImplementsUsage($node);
44 26
        $this->recordClassExpressionUsage($node);
45 26
        $this->recordCatchUsage($node);
46 26
        $this->recordFunctionCallUsage($node);
47 26
        $this->recordFunctionParameterTypesUsage($node);
48 26
        $this->recordFunctionReturnTypeUsage($node);
49 26
        $this->recordConstantFetchUsage($node);
50 26
        $this->recordTraitUsage($node);
51
52 26
        return parent::enterNode($node);
0 ignored issues
show
Bug introduced by
Are you sure the usage of parent::enterNode($node) targeting PhpParser\NodeVisitorAbstract::enterNode() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
53
    }
54
55 26
    private function recordExtendsUsage(Node $node)
56
    {
57 26
        if ($node instanceof Node\Stmt\Class_) {
58 7
            array_map([$this, 'recordUsageOf'], array_filter([$node->extends]));
59
        }
60
61 26
        if ($node instanceof Node\Stmt\Interface_) {
62 5
            array_map([$this, 'recordUsageOf'], array_filter($node->extends));
63
        }
64 26
    }
65
66 26
    private function recordImplementsUsage(Node $node)
67
    {
68 26
        if ($node instanceof Node\Stmt\Class_) {
69 7
            array_map([$this, 'recordUsageOf'], $node->implements);
70
        }
71 26
    }
72
73 26
    private function recordClassExpressionUsage(Node $node)
74
    {
75 26
        if (($node instanceof Node\Expr\StaticCall
76 25
                || $node instanceof Node\Expr\StaticPropertyFetch
77 24
                || $node instanceof Node\Expr\ClassConstFetch
78 23
                || $node instanceof Node\Expr\New_
79 26
                || $node instanceof Node\Expr\Instanceof_
80
            )
81 26
            && $node->class instanceof Node\Name
82
        ) {
83 9
            $this->recordUsageOf($node->class);
84
        }
85 26
    }
86
87 26
    private function recordCatchUsage(Node $node)
88
    {
89 26
        if ($node instanceof Node\Stmt\Catch_) {
90 5
            foreach ($node->types as $type) {
91 5
                $this->recordUsageOf($type);
92
            }
93
        }
94 26
    }
95
96 26
    private function recordFunctionCallUsage(Node $node)
97
    {
98 26
        if ($node instanceof Node\Expr\FuncCall
99 26
            && $node->name instanceof Node\Name
100
        ) {
101 5
            $this->recordUsageOf($node->name);
102
        }
103 26
    }
104
105 26
    private function recordFunctionParameterTypesUsage(Node $node)
106
    {
107 26
        if ($node instanceof Node\Stmt\Function_
108 26
            || $node instanceof Node\Stmt\ClassMethod
109
        ) {
110 12
            foreach ($node->getParams() as $param) {
111 8
                if ($param->type instanceof Node\Name) {
112 6
                    $this->recordUsageOf($param->type);
113
                }
114 8
                if (is_string($param->type) || $param->type instanceof Node\Identifier) {
115 6
                    $this->recordUsageOfByString($param->type);
116
                }
117
            }
118
        }
119 26
    }
120
121 26
    private function recordFunctionReturnTypeUsage(Node $node)
122
    {
123 26
        if ($node instanceof Node\Stmt\Function_
124 26
            || $node instanceof Node\Stmt\ClassMethod
125
        ) {
126 12
            $returnType = $node->getReturnType();
127
128 12
            if ($returnType instanceof Node\Name) {
129 6
                $this->recordUsageOf($returnType);
130
            }
131 12
            if ($returnType instanceof Node\Identifier) {
132 4
                $this->recordUsageOfByString($returnType->toString());
133
            }
134 12
            if (is_string($returnType)) {
0 ignored issues
show
introduced by
The condition is_string($returnType) is always false.
Loading history...
135 2
                $this->recordUsageOfByString($returnType);
136
            }
137
        }
138 26
    }
139
140 26
    private function recordConstantFetchUsage(Node $node)
141
    {
142 26
        if ($node instanceof Node\Expr\ConstFetch) {
143 5
            $this->recordUsageOf($node->name);
144
        }
145 26
    }
146
147 26
    private function recordTraitUsage(Node $node)
148
    {
149 26
        if (!$node instanceof Node\Stmt\TraitUse) {
150 24
            return;
151
        }
152
153 2
        array_map([$this, 'recordUsageOf'], $node->traits);
154
155 2
        foreach ($node->adaptations as $adaptation) {
156 1
            if (null !== $adaptation->trait) {
157
                $this->recordUsageOf($adaptation->trait);
158
            }
159
160 1
            if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Precedence) {
161
                array_map([$this, 'recordUsageOf'], $adaptation->insteadof);
162
            }
163
        }
164 2
    }
165
166
    /**
167
     * @param Node\Name $symbol
168
     *
169
     * @return void
170
     */
171 22
    private function recordUsageOf(Node\Name $symbol)
172
    {
173 22
        $this->collectedSymbols[(string)$symbol] = $symbol;
174 22
    }
175
176
    /**
177
     * @param string $symbol
178
     *
179
     * @return void
180
     */
181 8
    private function recordUsageOfByString(string $symbol)
182
    {
183 8
        $this->collectedSymbols[$symbol] = $symbol;
184 8
    }
185
}
186