Chris@13
|
1 <?php declare(strict_types=1);
|
Chris@0
|
2
|
Chris@0
|
3 namespace PhpParser\NodeVisitor;
|
Chris@0
|
4
|
Chris@0
|
5 use PhpParser;
|
Chris@0
|
6 use PhpParser\Node;
|
Chris@0
|
7 use PhpParser\Node\Expr;
|
Chris@0
|
8 use PhpParser\Node\Name;
|
Chris@0
|
9 use PhpParser\Node\Stmt;
|
Chris@0
|
10
|
Chris@17
|
11 class NameResolverTest extends \PHPUnit\Framework\TestCase
|
Chris@0
|
12 {
|
Chris@0
|
13 private function canonicalize($string) {
|
Chris@0
|
14 return str_replace("\r\n", "\n", $string);
|
Chris@0
|
15 }
|
Chris@0
|
16
|
Chris@0
|
17 /**
|
Chris@17
|
18 * @covers \PhpParser\NodeVisitor\NameResolver
|
Chris@0
|
19 */
|
Chris@0
|
20 public function testResolveNames() {
|
Chris@0
|
21 $code = <<<'EOC'
|
Chris@0
|
22 <?php
|
Chris@0
|
23
|
Chris@0
|
24 namespace Foo {
|
Chris@0
|
25 use Hallo as Hi;
|
Chris@0
|
26
|
Chris@0
|
27 new Bar();
|
Chris@0
|
28 new Hi();
|
Chris@0
|
29 new Hi\Bar();
|
Chris@0
|
30 new \Bar();
|
Chris@0
|
31 new namespace\Bar();
|
Chris@0
|
32
|
Chris@0
|
33 bar();
|
Chris@0
|
34 hi();
|
Chris@0
|
35 Hi\bar();
|
Chris@0
|
36 foo\bar();
|
Chris@0
|
37 \bar();
|
Chris@0
|
38 namespace\bar();
|
Chris@0
|
39 }
|
Chris@0
|
40 namespace {
|
Chris@0
|
41 use Hallo as Hi;
|
Chris@0
|
42
|
Chris@0
|
43 new Bar();
|
Chris@0
|
44 new Hi();
|
Chris@0
|
45 new Hi\Bar();
|
Chris@0
|
46 new \Bar();
|
Chris@0
|
47 new namespace\Bar();
|
Chris@0
|
48
|
Chris@0
|
49 bar();
|
Chris@0
|
50 hi();
|
Chris@0
|
51 Hi\bar();
|
Chris@0
|
52 foo\bar();
|
Chris@0
|
53 \bar();
|
Chris@0
|
54 namespace\bar();
|
Chris@0
|
55 }
|
Chris@0
|
56 namespace Bar {
|
Chris@0
|
57 use function foo\bar as baz;
|
Chris@0
|
58 use const foo\BAR as BAZ;
|
Chris@0
|
59 use foo as bar;
|
Chris@0
|
60
|
Chris@0
|
61 bar();
|
Chris@0
|
62 baz();
|
Chris@0
|
63 bar\foo();
|
Chris@0
|
64 baz\foo();
|
Chris@0
|
65 BAR();
|
Chris@0
|
66 BAZ();
|
Chris@0
|
67 BAR\FOO();
|
Chris@0
|
68 BAZ\FOO();
|
Chris@0
|
69
|
Chris@0
|
70 bar;
|
Chris@0
|
71 baz;
|
Chris@0
|
72 bar\foo;
|
Chris@0
|
73 baz\foo;
|
Chris@0
|
74 BAR;
|
Chris@0
|
75 BAZ;
|
Chris@0
|
76 BAR\FOO;
|
Chris@0
|
77 BAZ\FOO;
|
Chris@0
|
78 }
|
Chris@0
|
79 namespace Baz {
|
Chris@0
|
80 use A\T\{B\C, D\E};
|
Chris@0
|
81 use function X\T\{b\c, d\e};
|
Chris@0
|
82 use const Y\T\{B\C, D\E};
|
Chris@0
|
83 use Z\T\{G, function f, const K};
|
Chris@0
|
84
|
Chris@0
|
85 new C;
|
Chris@0
|
86 new E;
|
Chris@0
|
87 new C\D;
|
Chris@0
|
88 new E\F;
|
Chris@0
|
89 new G;
|
Chris@0
|
90
|
Chris@0
|
91 c();
|
Chris@0
|
92 e();
|
Chris@0
|
93 f();
|
Chris@0
|
94 C;
|
Chris@0
|
95 E;
|
Chris@0
|
96 K;
|
Chris@17
|
97
|
Chris@17
|
98 class ClassWithTypeProperties
|
Chris@17
|
99 {
|
Chris@17
|
100 public float $php = 7.4;
|
Chris@17
|
101 public ?Foo $person;
|
Chris@17
|
102 protected static ?bool $probability;
|
Chris@17
|
103 }
|
Chris@0
|
104 }
|
Chris@0
|
105 EOC;
|
Chris@0
|
106 $expectedCode = <<<'EOC'
|
Chris@0
|
107 namespace Foo {
|
Chris@0
|
108 use Hallo as Hi;
|
Chris@0
|
109 new \Foo\Bar();
|
Chris@0
|
110 new \Hallo();
|
Chris@0
|
111 new \Hallo\Bar();
|
Chris@0
|
112 new \Bar();
|
Chris@0
|
113 new \Foo\Bar();
|
Chris@0
|
114 bar();
|
Chris@0
|
115 hi();
|
Chris@0
|
116 \Hallo\bar();
|
Chris@0
|
117 \Foo\foo\bar();
|
Chris@0
|
118 \bar();
|
Chris@0
|
119 \Foo\bar();
|
Chris@0
|
120 }
|
Chris@0
|
121 namespace {
|
Chris@0
|
122 use Hallo as Hi;
|
Chris@0
|
123 new \Bar();
|
Chris@0
|
124 new \Hallo();
|
Chris@0
|
125 new \Hallo\Bar();
|
Chris@0
|
126 new \Bar();
|
Chris@0
|
127 new \Bar();
|
Chris@0
|
128 \bar();
|
Chris@0
|
129 \hi();
|
Chris@0
|
130 \Hallo\bar();
|
Chris@0
|
131 \foo\bar();
|
Chris@0
|
132 \bar();
|
Chris@0
|
133 \bar();
|
Chris@0
|
134 }
|
Chris@0
|
135 namespace Bar {
|
Chris@0
|
136 use function foo\bar as baz;
|
Chris@0
|
137 use const foo\BAR as BAZ;
|
Chris@0
|
138 use foo as bar;
|
Chris@0
|
139 bar();
|
Chris@0
|
140 \foo\bar();
|
Chris@0
|
141 \foo\foo();
|
Chris@0
|
142 \Bar\baz\foo();
|
Chris@0
|
143 BAR();
|
Chris@0
|
144 \foo\bar();
|
Chris@0
|
145 \foo\FOO();
|
Chris@0
|
146 \Bar\BAZ\FOO();
|
Chris@0
|
147 bar;
|
Chris@0
|
148 baz;
|
Chris@0
|
149 \foo\foo;
|
Chris@0
|
150 \Bar\baz\foo;
|
Chris@0
|
151 BAR;
|
Chris@0
|
152 \foo\BAR;
|
Chris@0
|
153 \foo\FOO;
|
Chris@0
|
154 \Bar\BAZ\FOO;
|
Chris@0
|
155 }
|
Chris@0
|
156 namespace Baz {
|
Chris@0
|
157 use A\T\{B\C, D\E};
|
Chris@0
|
158 use function X\T\{b\c, d\e};
|
Chris@0
|
159 use const Y\T\{B\C, D\E};
|
Chris@0
|
160 use Z\T\{G, function f, const K};
|
Chris@0
|
161 new \A\T\B\C();
|
Chris@0
|
162 new \A\T\D\E();
|
Chris@0
|
163 new \A\T\B\C\D();
|
Chris@0
|
164 new \A\T\D\E\F();
|
Chris@0
|
165 new \Z\T\G();
|
Chris@0
|
166 \X\T\b\c();
|
Chris@0
|
167 \X\T\d\e();
|
Chris@0
|
168 \Z\T\f();
|
Chris@0
|
169 \Y\T\B\C;
|
Chris@0
|
170 \Y\T\D\E;
|
Chris@0
|
171 \Z\T\K;
|
Chris@17
|
172 class ClassWithTypeProperties
|
Chris@17
|
173 {
|
Chris@17
|
174 public float $php = 7.4;
|
Chris@17
|
175 public ?\Baz\Foo $person;
|
Chris@17
|
176 protected static ?bool $probability;
|
Chris@17
|
177 }
|
Chris@0
|
178 }
|
Chris@0
|
179 EOC;
|
Chris@0
|
180
|
Chris@0
|
181 $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
|
Chris@0
|
182 $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
Chris@0
|
183 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
184 $traverser->addVisitor(new NameResolver);
|
Chris@0
|
185
|
Chris@0
|
186 $stmts = $parser->parse($code);
|
Chris@0
|
187 $stmts = $traverser->traverse($stmts);
|
Chris@0
|
188
|
Chris@0
|
189 $this->assertSame(
|
Chris@0
|
190 $this->canonicalize($expectedCode),
|
Chris@0
|
191 $prettyPrinter->prettyPrint($stmts)
|
Chris@0
|
192 );
|
Chris@0
|
193 }
|
Chris@0
|
194
|
Chris@0
|
195 /**
|
Chris@17
|
196 * @covers \PhpParser\NodeVisitor\NameResolver
|
Chris@0
|
197 */
|
Chris@0
|
198 public function testResolveLocations() {
|
Chris@0
|
199 $code = <<<'EOC'
|
Chris@0
|
200 <?php
|
Chris@0
|
201 namespace NS;
|
Chris@0
|
202
|
Chris@0
|
203 class A extends B implements C, D {
|
Chris@0
|
204 use E, F, G {
|
Chris@0
|
205 f as private g;
|
Chris@0
|
206 E::h as i;
|
Chris@0
|
207 E::j insteadof F, G;
|
Chris@0
|
208 }
|
Chris@0
|
209 }
|
Chris@0
|
210
|
Chris@0
|
211 interface A extends C, D {
|
Chris@0
|
212 public function a(A $a) : A;
|
Chris@0
|
213 }
|
Chris@0
|
214
|
Chris@0
|
215 function fn(A $a) : A {}
|
Chris@0
|
216 function fn2(array $a) : array {}
|
Chris@0
|
217 function(A $a) : A {};
|
Chris@0
|
218
|
Chris@0
|
219 function fn3(?A $a) : ?A {}
|
Chris@0
|
220 function fn4(?array $a) : ?array {}
|
Chris@0
|
221
|
Chris@0
|
222 A::b();
|
Chris@0
|
223 A::$b;
|
Chris@0
|
224 A::B;
|
Chris@0
|
225 new A;
|
Chris@0
|
226 $a instanceof A;
|
Chris@0
|
227
|
Chris@0
|
228 namespace\a();
|
Chris@0
|
229 namespace\A;
|
Chris@0
|
230
|
Chris@0
|
231 try {
|
Chris@0
|
232 $someThing;
|
Chris@0
|
233 } catch (A $a) {
|
Chris@0
|
234 $someThingElse;
|
Chris@0
|
235 }
|
Chris@0
|
236 EOC;
|
Chris@0
|
237 $expectedCode = <<<'EOC'
|
Chris@0
|
238 namespace NS;
|
Chris@0
|
239
|
Chris@0
|
240 class A extends \NS\B implements \NS\C, \NS\D
|
Chris@0
|
241 {
|
Chris@0
|
242 use \NS\E, \NS\F, \NS\G {
|
Chris@0
|
243 f as private g;
|
Chris@0
|
244 \NS\E::h as i;
|
Chris@0
|
245 \NS\E::j insteadof \NS\F, \NS\G;
|
Chris@0
|
246 }
|
Chris@0
|
247 }
|
Chris@0
|
248 interface A extends \NS\C, \NS\D
|
Chris@0
|
249 {
|
Chris@0
|
250 public function a(\NS\A $a) : \NS\A;
|
Chris@0
|
251 }
|
Chris@0
|
252 function fn(\NS\A $a) : \NS\A
|
Chris@0
|
253 {
|
Chris@0
|
254 }
|
Chris@0
|
255 function fn2(array $a) : array
|
Chris@0
|
256 {
|
Chris@0
|
257 }
|
Chris@0
|
258 function (\NS\A $a) : \NS\A {
|
Chris@0
|
259 };
|
Chris@0
|
260 function fn3(?\NS\A $a) : ?\NS\A
|
Chris@0
|
261 {
|
Chris@0
|
262 }
|
Chris@0
|
263 function fn4(?array $a) : ?array
|
Chris@0
|
264 {
|
Chris@0
|
265 }
|
Chris@0
|
266 \NS\A::b();
|
Chris@0
|
267 \NS\A::$b;
|
Chris@0
|
268 \NS\A::B;
|
Chris@0
|
269 new \NS\A();
|
Chris@0
|
270 $a instanceof \NS\A;
|
Chris@0
|
271 \NS\a();
|
Chris@0
|
272 \NS\A;
|
Chris@0
|
273 try {
|
Chris@0
|
274 $someThing;
|
Chris@0
|
275 } catch (\NS\A $a) {
|
Chris@0
|
276 $someThingElse;
|
Chris@0
|
277 }
|
Chris@0
|
278 EOC;
|
Chris@0
|
279
|
Chris@0
|
280 $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
|
Chris@0
|
281 $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
Chris@0
|
282 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
283 $traverser->addVisitor(new NameResolver);
|
Chris@0
|
284
|
Chris@0
|
285 $stmts = $parser->parse($code);
|
Chris@0
|
286 $stmts = $traverser->traverse($stmts);
|
Chris@0
|
287
|
Chris@0
|
288 $this->assertSame(
|
Chris@0
|
289 $this->canonicalize($expectedCode),
|
Chris@0
|
290 $prettyPrinter->prettyPrint($stmts)
|
Chris@0
|
291 );
|
Chris@0
|
292 }
|
Chris@0
|
293
|
Chris@0
|
294 public function testNoResolveSpecialName() {
|
Chris@13
|
295 $stmts = [new Node\Expr\New_(new Name('self'))];
|
Chris@0
|
296
|
Chris@0
|
297 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
298 $traverser->addVisitor(new NameResolver);
|
Chris@0
|
299
|
Chris@0
|
300 $this->assertEquals($stmts, $traverser->traverse($stmts));
|
Chris@0
|
301 }
|
Chris@0
|
302
|
Chris@0
|
303 public function testAddDeclarationNamespacedName() {
|
Chris@13
|
304 $nsStmts = [
|
Chris@0
|
305 new Stmt\Class_('A'),
|
Chris@0
|
306 new Stmt\Interface_('B'),
|
Chris@0
|
307 new Stmt\Function_('C'),
|
Chris@13
|
308 new Stmt\Const_([
|
Chris@0
|
309 new Node\Const_('D', new Node\Scalar\LNumber(42))
|
Chris@13
|
310 ]),
|
Chris@0
|
311 new Stmt\Trait_('E'),
|
Chris@0
|
312 new Expr\New_(new Stmt\Class_(null)),
|
Chris@13
|
313 ];
|
Chris@0
|
314
|
Chris@0
|
315 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
316 $traverser->addVisitor(new NameResolver);
|
Chris@0
|
317
|
Chris@0
|
318 $stmts = $traverser->traverse([new Stmt\Namespace_(new Name('NS'), $nsStmts)]);
|
Chris@0
|
319 $this->assertSame('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
|
Chris@0
|
320 $this->assertSame('NS\\B', (string) $stmts[0]->stmts[1]->namespacedName);
|
Chris@0
|
321 $this->assertSame('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName);
|
Chris@0
|
322 $this->assertSame('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
Chris@0
|
323 $this->assertSame('NS\\E', (string) $stmts[0]->stmts[4]->namespacedName);
|
Chris@0
|
324 $this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
|
Chris@0
|
325
|
Chris@0
|
326 $stmts = $traverser->traverse([new Stmt\Namespace_(null, $nsStmts)]);
|
Chris@0
|
327 $this->assertSame('A', (string) $stmts[0]->stmts[0]->namespacedName);
|
Chris@0
|
328 $this->assertSame('B', (string) $stmts[0]->stmts[1]->namespacedName);
|
Chris@0
|
329 $this->assertSame('C', (string) $stmts[0]->stmts[2]->namespacedName);
|
Chris@0
|
330 $this->assertSame('D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
|
Chris@0
|
331 $this->assertSame('E', (string) $stmts[0]->stmts[4]->namespacedName);
|
Chris@0
|
332 $this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
|
Chris@0
|
333 }
|
Chris@0
|
334
|
Chris@0
|
335 public function testAddRuntimeResolvedNamespacedName() {
|
Chris@13
|
336 $stmts = [
|
Chris@13
|
337 new Stmt\Namespace_(new Name('NS'), [
|
Chris@0
|
338 new Expr\FuncCall(new Name('foo')),
|
Chris@0
|
339 new Expr\ConstFetch(new Name('FOO')),
|
Chris@13
|
340 ]),
|
Chris@13
|
341 new Stmt\Namespace_(null, [
|
Chris@0
|
342 new Expr\FuncCall(new Name('foo')),
|
Chris@0
|
343 new Expr\ConstFetch(new Name('FOO')),
|
Chris@13
|
344 ]),
|
Chris@13
|
345 ];
|
Chris@0
|
346
|
Chris@0
|
347 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
348 $traverser->addVisitor(new NameResolver);
|
Chris@0
|
349 $stmts = $traverser->traverse($stmts);
|
Chris@13
|
350
|
Chris@0
|
351 $this->assertSame('NS\\foo', (string) $stmts[0]->stmts[0]->name->getAttribute('namespacedName'));
|
Chris@0
|
352 $this->assertSame('NS\\FOO', (string) $stmts[0]->stmts[1]->name->getAttribute('namespacedName'));
|
Chris@0
|
353
|
Chris@0
|
354 $this->assertFalse($stmts[1]->stmts[0]->name->hasAttribute('namespacedName'));
|
Chris@0
|
355 $this->assertFalse($stmts[1]->stmts[1]->name->hasAttribute('namespacedName'));
|
Chris@0
|
356 }
|
Chris@0
|
357
|
Chris@0
|
358 /**
|
Chris@0
|
359 * @dataProvider provideTestError
|
Chris@0
|
360 */
|
Chris@0
|
361 public function testError(Node $stmt, $errorMsg) {
|
Chris@13
|
362 $this->expectException(\PhpParser\Error::class);
|
Chris@13
|
363 $this->expectExceptionMessage($errorMsg);
|
Chris@0
|
364
|
Chris@0
|
365 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
366 $traverser->addVisitor(new NameResolver);
|
Chris@13
|
367 $traverser->traverse([$stmt]);
|
Chris@0
|
368 }
|
Chris@0
|
369
|
Chris@0
|
370 public function provideTestError() {
|
Chris@13
|
371 return [
|
Chris@13
|
372 [
|
Chris@13
|
373 new Stmt\Use_([
|
Chris@13
|
374 new Stmt\UseUse(new Name('A\B'), 'B', 0, ['startLine' => 1]),
|
Chris@13
|
375 new Stmt\UseUse(new Name('C\D'), 'B', 0, ['startLine' => 2]),
|
Chris@13
|
376 ], Stmt\Use_::TYPE_NORMAL),
|
Chris@0
|
377 'Cannot use C\D as B because the name is already in use on line 2'
|
Chris@13
|
378 ],
|
Chris@13
|
379 [
|
Chris@13
|
380 new Stmt\Use_([
|
Chris@13
|
381 new Stmt\UseUse(new Name('a\b'), 'b', 0, ['startLine' => 1]),
|
Chris@13
|
382 new Stmt\UseUse(new Name('c\d'), 'B', 0, ['startLine' => 2]),
|
Chris@13
|
383 ], Stmt\Use_::TYPE_FUNCTION),
|
Chris@0
|
384 'Cannot use function c\d as B because the name is already in use on line 2'
|
Chris@13
|
385 ],
|
Chris@13
|
386 [
|
Chris@13
|
387 new Stmt\Use_([
|
Chris@13
|
388 new Stmt\UseUse(new Name('A\B'), 'B', 0, ['startLine' => 1]),
|
Chris@13
|
389 new Stmt\UseUse(new Name('C\D'), 'B', 0, ['startLine' => 2]),
|
Chris@13
|
390 ], Stmt\Use_::TYPE_CONSTANT),
|
Chris@0
|
391 'Cannot use const C\D as B because the name is already in use on line 2'
|
Chris@13
|
392 ],
|
Chris@13
|
393 [
|
Chris@13
|
394 new Expr\New_(new Name\FullyQualified('self', ['startLine' => 3])),
|
Chris@0
|
395 "'\\self' is an invalid class name on line 3"
|
Chris@13
|
396 ],
|
Chris@13
|
397 [
|
Chris@13
|
398 new Expr\New_(new Name\Relative('self', ['startLine' => 3])),
|
Chris@0
|
399 "'\\self' is an invalid class name on line 3"
|
Chris@13
|
400 ],
|
Chris@13
|
401 [
|
Chris@13
|
402 new Expr\New_(new Name\FullyQualified('PARENT', ['startLine' => 3])),
|
Chris@0
|
403 "'\\PARENT' is an invalid class name on line 3"
|
Chris@13
|
404 ],
|
Chris@13
|
405 [
|
Chris@13
|
406 new Expr\New_(new Name\Relative('STATIC', ['startLine' => 3])),
|
Chris@0
|
407 "'\\STATIC' is an invalid class name on line 3"
|
Chris@13
|
408 ],
|
Chris@13
|
409 ];
|
Chris@0
|
410 }
|
Chris@0
|
411
|
Chris@0
|
412 public function testClassNameIsCaseInsensitive()
|
Chris@0
|
413 {
|
Chris@0
|
414 $source = <<<'EOC'
|
Chris@0
|
415 <?php
|
Chris@0
|
416 namespace Foo;
|
Chris@0
|
417 use Bar\Baz;
|
Chris@0
|
418 $test = new baz();
|
Chris@0
|
419 EOC;
|
Chris@0
|
420
|
Chris@0
|
421 $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
|
Chris@0
|
422 $stmts = $parser->parse($source);
|
Chris@0
|
423
|
Chris@0
|
424 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
425 $traverser->addVisitor(new NameResolver);
|
Chris@0
|
426
|
Chris@0
|
427 $stmts = $traverser->traverse($stmts);
|
Chris@0
|
428 $stmt = $stmts[0];
|
Chris@0
|
429
|
Chris@13
|
430 $assign = $stmt->stmts[1]->expr;
|
Chris@13
|
431 $this->assertSame(['Bar', 'Baz'], $assign->expr->class->parts);
|
Chris@0
|
432 }
|
Chris@0
|
433
|
Chris@0
|
434 public function testSpecialClassNamesAreCaseInsensitive() {
|
Chris@0
|
435 $source = <<<'EOC'
|
Chris@0
|
436 <?php
|
Chris@0
|
437 namespace Foo;
|
Chris@0
|
438
|
Chris@0
|
439 class Bar
|
Chris@0
|
440 {
|
Chris@0
|
441 public static function method()
|
Chris@0
|
442 {
|
Chris@0
|
443 SELF::method();
|
Chris@0
|
444 PARENT::method();
|
Chris@0
|
445 STATIC::method();
|
Chris@0
|
446 }
|
Chris@0
|
447 }
|
Chris@0
|
448 EOC;
|
Chris@0
|
449
|
Chris@0
|
450 $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
|
Chris@0
|
451 $stmts = $parser->parse($source);
|
Chris@0
|
452
|
Chris@0
|
453 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
454 $traverser->addVisitor(new NameResolver);
|
Chris@0
|
455
|
Chris@0
|
456 $stmts = $traverser->traverse($stmts);
|
Chris@0
|
457 $classStmt = $stmts[0];
|
Chris@0
|
458 $methodStmt = $classStmt->stmts[0]->stmts[0];
|
Chris@0
|
459
|
Chris@13
|
460 $this->assertSame('SELF', (string) $methodStmt->stmts[0]->expr->class);
|
Chris@13
|
461 $this->assertSame('PARENT', (string) $methodStmt->stmts[1]->expr->class);
|
Chris@13
|
462 $this->assertSame('STATIC', (string) $methodStmt->stmts[2]->expr->class);
|
Chris@0
|
463 }
|
Chris@0
|
464
|
Chris@0
|
465 public function testAddOriginalNames() {
|
Chris@0
|
466 $traverser = new PhpParser\NodeTraverser;
|
Chris@0
|
467 $traverser->addVisitor(new NameResolver(null, ['preserveOriginalNames' => true]));
|
Chris@0
|
468
|
Chris@0
|
469 $n1 = new Name('Bar');
|
Chris@0
|
470 $n2 = new Name('bar');
|
Chris@0
|
471 $origStmts = [
|
Chris@0
|
472 new Stmt\Namespace_(new Name('Foo'), [
|
Chris@0
|
473 new Expr\ClassConstFetch($n1, 'FOO'),
|
Chris@0
|
474 new Expr\FuncCall($n2),
|
Chris@0
|
475 ])
|
Chris@0
|
476 ];
|
Chris@0
|
477
|
Chris@0
|
478 $stmts = $traverser->traverse($origStmts);
|
Chris@0
|
479
|
Chris@0
|
480 $this->assertSame($n1, $stmts[0]->stmts[0]->class->getAttribute('originalName'));
|
Chris@0
|
481 $this->assertSame($n2, $stmts[0]->stmts[1]->name->getAttribute('originalName'));
|
Chris@0
|
482 }
|
Chris@13
|
483
|
Chris@13
|
484 public function testAttributeOnlyMode() {
|
Chris@13
|
485 $traverser = new PhpParser\NodeTraverser;
|
Chris@13
|
486 $traverser->addVisitor(new NameResolver(null, ['replaceNodes' => false]));
|
Chris@13
|
487
|
Chris@13
|
488 $n1 = new Name('Bar');
|
Chris@13
|
489 $n2 = new Name('bar');
|
Chris@13
|
490 $origStmts = [
|
Chris@13
|
491 new Stmt\Namespace_(new Name('Foo'), [
|
Chris@13
|
492 new Expr\ClassConstFetch($n1, 'FOO'),
|
Chris@13
|
493 new Expr\FuncCall($n2),
|
Chris@13
|
494 ])
|
Chris@13
|
495 ];
|
Chris@13
|
496
|
Chris@13
|
497 $traverser->traverse($origStmts);
|
Chris@13
|
498
|
Chris@13
|
499 $this->assertEquals(
|
Chris@13
|
500 new Name\FullyQualified('Foo\Bar'), $n1->getAttribute('resolvedName'));
|
Chris@13
|
501 $this->assertFalse($n2->hasAttribute('resolvedName'));
|
Chris@13
|
502 $this->assertEquals(
|
Chris@13
|
503 new Name\FullyQualified('Foo\bar'), $n2->getAttribute('namespacedName'));
|
Chris@13
|
504 }
|
Chris@0
|
505 }
|