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