forked from phpstan/phpstan-src
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVariadicFunctionsVisitor.php
94 lines (72 loc) · 2.3 KB
/
VariadicFunctionsVisitor.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php declare(strict_types = 1);
namespace PHPStan\Parser;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\NodeVisitorAbstract;
use PHPStan\Reflection\ParametersAcceptor;
use function array_filter;
use function array_key_exists;
use function in_array;
final class VariadicFunctionsVisitor extends NodeVisitorAbstract
{
private ?Node $topNode = null;
private ?string $inNamespace = null;
private ?string $inFunction = null;
/** @var array<string, bool> */
public static array $cache = [];
/** @var array<string, bool> */
private array $variadicFunctions = [];
public const ATTRIBUTE_NAME = 'variadicFunctions';
public function beforeTraverse(array $nodes): ?array
{
$this->topNode = null;
$this->variadicFunctions = [];
$this->inNamespace = null;
$this->inFunction = null;
return null;
}
public function enterNode(Node $node): ?Node
{
if ($this->topNode === null) {
$this->topNode = $node;
}
if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) {
$this->inNamespace = $node->name->toString();
}
if ($node instanceof Node\Stmt\Function_) {
$this->inFunction = $this->inNamespace !== null ? $this->inNamespace . '\\' . $node->name->name : $node->name->name;
}
if (
$this->inFunction !== null
&& $node instanceof Node\Expr\FuncCall
&& $node->name instanceof Name
&& in_array((string) $node->name, ParametersAcceptor::VARIADIC_FUNCTIONS, true)
&& !array_key_exists($this->inFunction, $this->variadicFunctions)
) {
$this->variadicFunctions[$this->inFunction] = true;
}
return null;
}
public function leaveNode(Node $node): ?Node
{
if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) {
$this->inNamespace = null;
}
if ($node instanceof Node\Stmt\Function_ && $this->inFunction !== null) {
$this->variadicFunctions[$this->inFunction] ??= false;
$this->inFunction = null;
}
return null;
}
public function afterTraverse(array $nodes): ?array
{
if ($this->topNode !== null && $this->variadicFunctions !== []) {
foreach ($this->variadicFunctions as $name => $variadic) {
self::$cache[$name] = $variadic;
}
$functions = array_filter($this->variadicFunctions, static fn (bool $variadic) => $variadic);
$this->topNode->setAttribute(self::ATTRIBUTE_NAME, $functions);
}
return null;
}
}