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
|
29 |
|
public function __construct() |
16
|
|
|
{ |
17
|
29 |
|
} |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @return string[] |
21
|
|
|
*/ |
22
|
28 |
|
public function getCollectedSymbols(): array |
23
|
|
|
{ |
24
|
28 |
|
return array_keys($this->collectedSymbols); |
25
|
|
|
} |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* {@inheritDoc} |
29
|
|
|
*/ |
30
|
8 |
|
public function beforeTraverse(array $nodes) |
31
|
|
|
{ |
32
|
8 |
|
$this->collectedSymbols = []; |
33
|
|
|
|
34
|
8 |
|
return parent::beforeTraverse($nodes); |
|
|
|
|
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* {@inheritDoc} |
39
|
|
|
*/ |
40
|
28 |
|
public function enterNode(Node $node) |
41
|
|
|
{ |
42
|
28 |
|
$this->recordExtendsUsage($node); |
43
|
28 |
|
$this->recordImplementsUsage($node); |
44
|
28 |
|
$this->recordClassExpressionUsage($node); |
45
|
28 |
|
$this->recordCatchUsage($node); |
46
|
28 |
|
$this->recordFunctionCallUsage($node); |
47
|
28 |
|
$this->recordFunctionParameterTypesUsage($node); |
48
|
28 |
|
$this->recordFunctionReturnTypeUsage($node); |
49
|
28 |
|
$this->recordConstantFetchUsage($node); |
50
|
28 |
|
$this->recordTraitUsage($node); |
51
|
|
|
|
52
|
28 |
|
return parent::enterNode($node); |
|
|
|
|
53
|
|
|
} |
54
|
|
|
|
55
|
28 |
|
private function recordExtendsUsage(Node $node) |
56
|
|
|
{ |
57
|
28 |
|
if ($node instanceof Node\Stmt\Class_) { |
58
|
10 |
|
array_map([$this, 'recordUsageOf'], array_filter([$node->extends])); |
59
|
|
|
} |
60
|
|
|
|
61
|
28 |
|
if ($node instanceof Node\Stmt\Interface_) { |
62
|
5 |
|
array_map([$this, 'recordUsageOf'], array_filter($node->extends)); |
63
|
|
|
} |
64
|
28 |
|
} |
65
|
|
|
|
66
|
28 |
|
private function recordImplementsUsage(Node $node) |
67
|
|
|
{ |
68
|
28 |
|
if ($node instanceof Node\Stmt\Class_) { |
69
|
10 |
|
array_map([$this, 'recordUsageOf'], $node->implements); |
70
|
|
|
} |
71
|
28 |
|
} |
72
|
|
|
|
73
|
28 |
|
private function recordClassExpressionUsage(Node $node) |
74
|
|
|
{ |
75
|
28 |
|
if (($node instanceof Node\Expr\StaticCall |
76
|
27 |
|
|| $node instanceof Node\Expr\StaticPropertyFetch |
77
|
26 |
|
|| $node instanceof Node\Expr\ClassConstFetch |
78
|
25 |
|
|| $node instanceof Node\Expr\New_ |
79
|
28 |
|
|| $node instanceof Node\Expr\Instanceof_ |
80
|
|
|
) |
81
|
28 |
|
&& $node->class instanceof Node\Name |
82
|
|
|
) { |
83
|
10 |
|
$this->recordUsageOf($node->class); |
84
|
|
|
} |
85
|
28 |
|
} |
86
|
|
|
|
87
|
28 |
|
private function recordCatchUsage(Node $node) |
88
|
|
|
{ |
89
|
28 |
|
if ($node instanceof Node\Stmt\Catch_) { |
90
|
5 |
|
foreach ($node->types as $type) { |
91
|
5 |
|
$this->recordUsageOf($type); |
92
|
|
|
} |
93
|
|
|
} |
94
|
28 |
|
} |
95
|
|
|
|
96
|
28 |
|
private function recordFunctionCallUsage(Node $node) |
97
|
|
|
{ |
98
|
28 |
|
if ($node instanceof Node\Expr\FuncCall |
99
|
28 |
|
&& $node->name instanceof Node\Name |
100
|
|
|
) { |
101
|
8 |
|
$this->recordUsageOf($node->name); |
102
|
|
|
} |
103
|
28 |
|
} |
104
|
|
|
|
105
|
28 |
|
private function recordFunctionParameterTypesUsage(Node $node) |
106
|
|
|
{ |
107
|
28 |
|
if ($node instanceof Node\Stmt\Function_ |
108
|
28 |
|
|| $node instanceof Node\Stmt\ClassMethod |
109
|
|
|
) { |
110
|
13 |
|
foreach ($node->getParams() as $param) { |
111
|
11 |
|
if ($param->type instanceof Node\Name) { |
112
|
7 |
|
$this->recordUsageOf($param->type); |
113
|
|
|
} |
114
|
11 |
|
if (is_string($param->type) || $param->type instanceof Node\Identifier) { |
115
|
8 |
|
$this->recordUsageOfByString($param->type); |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
} |
119
|
28 |
|
} |
120
|
|
|
|
121
|
28 |
|
private function recordFunctionReturnTypeUsage(Node $node) |
122
|
|
|
{ |
123
|
28 |
|
if ($node instanceof Node\Stmt\Function_ |
124
|
28 |
|
|| $node instanceof Node\Stmt\ClassMethod |
125
|
|
|
) { |
126
|
13 |
|
$returnType = $node->getReturnType(); |
127
|
|
|
|
128
|
13 |
|
if ($returnType instanceof Node\Name) { |
129
|
6 |
|
$this->recordUsageOf($returnType); |
130
|
|
|
} |
131
|
13 |
|
if ($returnType instanceof Node\Identifier) { |
132
|
6 |
|
$this->recordUsageOfByString($returnType->toString()); |
133
|
|
|
} |
134
|
|
|
} |
135
|
28 |
|
} |
136
|
|
|
|
137
|
28 |
|
private function recordConstantFetchUsage(Node $node) |
138
|
|
|
{ |
139
|
28 |
|
if ($node instanceof Node\Expr\ConstFetch) { |
140
|
6 |
|
$this->recordUsageOf($node->name); |
141
|
|
|
} |
142
|
28 |
|
} |
143
|
|
|
|
144
|
28 |
|
private function recordTraitUsage(Node $node) |
145
|
|
|
{ |
146
|
28 |
|
if (!$node instanceof Node\Stmt\TraitUse) { |
147
|
25 |
|
return; |
148
|
|
|
} |
149
|
|
|
|
150
|
3 |
|
array_map([$this, 'recordUsageOf'], $node->traits); |
151
|
|
|
|
152
|
3 |
|
foreach ($node->adaptations as $adaptation) { |
153
|
2 |
|
if (null !== $adaptation->trait) { |
154
|
1 |
|
$this->recordUsageOf($adaptation->trait); |
155
|
|
|
} |
156
|
|
|
|
157
|
2 |
|
if ($adaptation instanceof Node\Stmt\TraitUseAdaptation\Precedence) { |
158
|
1 |
|
array_map([$this, 'recordUsageOf'], $adaptation->insteadof); |
159
|
|
|
} |
160
|
|
|
} |
161
|
3 |
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* @param Node\Name $symbol |
165
|
|
|
* |
166
|
|
|
* @return void |
167
|
|
|
*/ |
168
|
26 |
|
private function recordUsageOf(Node\Name $symbol) |
169
|
|
|
{ |
170
|
26 |
|
$this->collectedSymbols[(string)$symbol] = $symbol; |
171
|
26 |
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @param string $symbol |
175
|
|
|
* |
176
|
|
|
* @return void |
177
|
|
|
*/ |
178
|
8 |
|
private function recordUsageOfByString(string $symbol) |
179
|
|
|
{ |
180
|
8 |
|
$this->collectedSymbols[$symbol] = $symbol; |
181
|
8 |
|
} |
182
|
|
|
} |
183
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
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.