comparison vendor/nikic/php-parser/test/PhpParser/CodeParsingTest.php @ 13:5fb285c0d0e3

Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've been lucky to get away with this so far, as we don't support self-registration which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5 was vulnerable to.
author Chris Cannam
date Mon, 23 Apr 2018 09:33:26 +0100
parents 4c8ae668cc8c
children 129ea1e6d783
comparison
equal deleted inserted replaced
12:7a779792577d 13:5fb285c0d0e3
1 <?php 1 <?php declare(strict_types=1);
2 2
3 namespace PhpParser; 3 namespace PhpParser;
4
5 use PhpParser\Node\Expr;
6 use PhpParser\Node\Stmt;
4 7
5 require_once __DIR__ . '/CodeTestAbstract.php'; 8 require_once __DIR__ . '/CodeTestAbstract.php';
6 9
7 class CodeParsingTest extends CodeTestAbstract 10 class CodeParsingTest extends CodeTestAbstract
8 { 11 {
14 $modes = array_fill_keys(explode(',', $modeLine), true); 17 $modes = array_fill_keys(explode(',', $modeLine), true);
15 } else { 18 } else {
16 $modes = []; 19 $modes = [];
17 } 20 }
18 21
19 22 list($parser5, $parser7) = $this->createParsers($modes);
20 $lexer = new Lexer\Emulative(array('usedAttributes' => array( 23 list($stmts5, $output5) = $this->getParseOutput($parser5, $code, $modes);
21 'startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments' 24 list($stmts7, $output7) = $this->getParseOutput($parser7, $code, $modes);
22 )));
23 $parser5 = new Parser\Php5($lexer);
24 $parser7 = new Parser\Php7($lexer);
25
26 $dumpPositions = isset($modes['positions']);
27 $output5 = $this->getParseOutput($parser5, $code, $dumpPositions);
28 $output7 = $this->getParseOutput($parser7, $code, $dumpPositions);
29 25
30 if (isset($modes['php5'])) { 26 if (isset($modes['php5'])) {
31 $this->assertSame($expected, $output5, $name); 27 $this->assertSame($expected, $output5, $name);
32 $this->assertNotSame($expected, $output7, $name); 28 $this->assertNotSame($expected, $output7, $name);
33 } else if (isset($modes['php7'])) { 29 } elseif (isset($modes['php7'])) {
34 $this->assertNotSame($expected, $output5, $name); 30 $this->assertNotSame($expected, $output5, $name);
35 $this->assertSame($expected, $output7, $name); 31 $this->assertSame($expected, $output7, $name);
36 } else { 32 } else {
37 $this->assertSame($expected, $output5, $name); 33 $this->assertSame($expected, $output5, $name);
38 $this->assertSame($expected, $output7, $name); 34 $this->assertSame($expected, $output7, $name);
39 } 35 }
36
37 $this->checkAttributes($stmts5);
38 $this->checkAttributes($stmts7);
40 } 39 }
41 40
42 private function getParseOutput(Parser $parser, $code, $dumpPositions) { 41 public function createParsers(array $modes) {
42 $lexer = new Lexer\Emulative(['usedAttributes' => [
43 'startLine', 'endLine',
44 'startFilePos', 'endFilePos',
45 'startTokenPos', 'endTokenPos',
46 'comments'
47 ]]);
48
49 return [
50 new Parser\Php5($lexer),
51 new Parser\Php7($lexer),
52 ];
53 }
54
55 private function getParseOutput(Parser $parser, $code, array $modes) {
56 $dumpPositions = isset($modes['positions']);
57
43 $errors = new ErrorHandler\Collecting; 58 $errors = new ErrorHandler\Collecting;
44 $stmts = $parser->parse($code, $errors); 59 $stmts = $parser->parse($code, $errors);
45 60
46 $output = ''; 61 $output = '';
47 foreach ($errors->getErrors() as $error) { 62 foreach ($errors->getErrors() as $error) {
51 if (null !== $stmts) { 66 if (null !== $stmts) {
52 $dumper = new NodeDumper(['dumpComments' => true, 'dumpPositions' => $dumpPositions]); 67 $dumper = new NodeDumper(['dumpComments' => true, 'dumpPositions' => $dumpPositions]);
53 $output .= $dumper->dump($stmts, $code); 68 $output .= $dumper->dump($stmts, $code);
54 } 69 }
55 70
56 return canonicalize($output); 71 return [$stmts, canonicalize($output)];
57 } 72 }
58 73
59 public function provideTestParse() { 74 public function provideTestParse() {
60 return $this->getTests(__DIR__ . '/../code/parser', 'test'); 75 return $this->getTests(__DIR__ . '/../code/parser', 'test');
61 } 76 }
65 return $e->getMessageWithColumnInfo($code); 80 return $e->getMessageWithColumnInfo($code);
66 } else { 81 } else {
67 return $e->getMessage(); 82 return $e->getMessage();
68 } 83 }
69 } 84 }
85
86 private function checkAttributes($stmts) {
87 if ($stmts === null) {
88 return;
89 }
90
91 $traverser = new NodeTraverser();
92 $traverser->addVisitor(new class extends NodeVisitorAbstract {
93 public function enterNode(Node $node) {
94 $startLine = $node->getStartLine();
95 $endLine = $node->getEndLine();
96 $startFilePos = $node->getStartFilePos();
97 $endFilePos = $node->getEndFilePos();
98 $startTokenPos = $node->getStartTokenPos();
99 $endTokenPos = $node->getEndTokenPos();
100 if ($startLine < 0 || $endLine < 0 ||
101 $startFilePos < 0 || $endFilePos < 0 ||
102 $startTokenPos < 0 || $endTokenPos < 0
103 ) {
104 throw new \Exception('Missing location information on ' . $node->getType());
105 }
106
107 if ($endLine < $startLine ||
108 $endFilePos < $startFilePos ||
109 $endTokenPos < $startTokenPos
110 ) {
111 // Nops and error can have inverted order, if they are empty
112 if (!$node instanceof Stmt\Nop && !$node instanceof Expr\Error) {
113 throw new \Exception('End < start on ' . $node->getType());
114 }
115 }
116 }
117 });
118 $traverser->traverse($stmts);
119 }
70 } 120 }