6
6
use PhpParser \Node \Name ;
7
7
use PhpParser \Node \Stmt \ClassMethod ;
8
8
use PhpParser \NodeVisitorAbstract ;
9
+ use PHPStan \Node \AnonymousClassNode ;
9
10
use PHPStan \Reflection \ParametersAcceptor ;
10
11
use PHPStan \TrinaryLogic ;
11
12
use function array_key_exists ;
@@ -20,6 +21,11 @@ final class VariadicMethodsVisitor extends NodeVisitorAbstract
20
21
21
22
private ?string $ inClassLike = null ;
22
23
24
+ /**
25
+ * @var array<string>
26
+ */
27
+ private array $ classStack = [];
28
+
23
29
private ?string $ inMethod = null ;
24
30
25
31
/** @var array<string, array<string, TrinaryLogic>> */
@@ -32,6 +38,7 @@ public function beforeTraverse(array $nodes): ?array
32
38
$ this ->topNode = null ;
33
39
$ this ->variadicMethods = [];
34
40
$ this ->inNamespace = null ;
41
+ $ this ->classStack = [];
35
42
$ this ->inClassLike = null ;
36
43
$ this ->inMethod = null ;
37
44
@@ -48,21 +55,28 @@ public function enterNode(Node $node): ?Node
48
55
$ this ->inNamespace = $ node ->name ->toString ();
49
56
}
50
57
51
- if ($ node instanceof Node \Stmt \ClassLike && $ node ->name instanceof Node \Identifier) {
52
- $ this ->inClassLike = $ this ->inNamespace !== null ? $ this ->inNamespace . '\\' . $ node ->name ->name : $ node ->name ->name ;
58
+ if (
59
+ $ node instanceof Node \Stmt \Class_
60
+ || $ node instanceof Node \Stmt \ClassLike
61
+ ) {
62
+ if (!$ node ->name instanceof Node \Identifier) {
63
+ $ className = 'class@anonymous ' ;
64
+ } else {
65
+ $ className = $ node ->name ->name ;
66
+ }
67
+
68
+ $ this ->classStack [] = $ className ;
69
+ $ this ->inClassLike = $ this ->inNamespace !== null ? $ this ->inNamespace . '\\' . implode ('\\' , $ this ->classStack ) : implode ('\\' , $ this ->classStack );
53
70
$ this ->variadicMethods [$ this ->inClassLike ] ??= [];
54
71
}
55
72
56
73
if ($ this ->inClassLike !== null && $ node instanceof ClassMethod) {
57
- if ($ node ->getStmts () === null ) {
58
- return null ; // interface
59
- }
60
-
61
74
$ this ->inMethod = $ node ->name ->name ;
62
75
}
63
76
64
77
if (
65
- $ this ->inMethod !== null
78
+ $ this ->inClassLike !== null
79
+ && $ this ->inMethod !== null
66
80
&& $ node instanceof Node \Expr \FuncCall
67
81
&& $ node ->name instanceof Name
68
82
&& in_array ((string ) $ node ->name , ParametersAcceptor::VARIADIC_FUNCTIONS , true )
@@ -80,17 +94,29 @@ public function enterNode(Node $node): ?Node
80
94
81
95
public function leaveNode (Node $ node ): ?Node
82
96
{
83
- if ($ node instanceof Node \Stmt \Namespace_ && $ node ->name !== null ) {
84
- $ this ->inNamespace = null ;
97
+ if (
98
+ $ node instanceof ClassMethod
99
+ && $ this ->inClassLike !== null
100
+ ) {
101
+ $ this ->variadicMethods [$ this ->inClassLike ][$ node ->name ->name ] ??= TrinaryLogic::createNo ();
102
+ $ this ->inMethod = null ;
85
103
}
86
104
87
- if ($ node instanceof Node \Stmt \ClassLike && $ node ->name instanceof Node \Identifier) {
88
- $ this ->inClassLike = null ;
105
+ if (
106
+ $ node instanceof Node \Stmt \Class_
107
+ || $ node instanceof Node \Stmt \ClassLike
108
+ ) {
109
+ array_pop ($ this ->classStack );
110
+
111
+ if ($ this ->classStack !== []) {
112
+ $ this ->inClassLike = $ this ->inNamespace !== null ? $ this ->inNamespace . '\\' . implode ('\\' , $ this ->classStack ) : implode ('\\' , $ this ->classStack );
113
+ } else {
114
+ $ this ->inClassLike = null ;
115
+ }
89
116
}
90
117
91
- if ($ node instanceof ClassMethod && $ this ->inClassLike !== null && $ this ->inMethod !== null ) {
92
- $ this ->variadicMethods [$ this ->inClassLike ][$ this ->inMethod ] ??= TrinaryLogic::createNo ();
93
- $ this ->inMethod = null ;
118
+ if ($ node instanceof Node \Stmt \Namespace_ && $ node ->name !== null ) {
119
+ $ this ->inNamespace = null ;
94
120
}
95
121
96
122
return null ;
0 commit comments