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