From d418bf395113b6a3293bda1d08ddc9b0209d5dcf Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 1 Oct 2017 16:54:43 +0200 Subject: [PATCH] Preserve comments on empty blocks (#382) --- CHANGELOG.md | 4 ++++ grammar/php5.y | 10 +++++++++- grammar/php7.y | 10 +++++++++- grammar/rebuildParsers.php | 2 +- lib/PhpParser/Parser/Php5.php | 9 ++++++++- lib/PhpParser/Parser/Php7.php | 9 ++++++++- test/code/parser/blockComments.test | 8 ++++++++ 7 files changed, 47 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a524e1d..2fdca50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Version 3.1.2-dev ----------------- +### Fixed + +* Comments on empty blocks are now preserved on a `Stmt\Nop` node. (#382) + ### Added * Added `kind` attribute for `Stmt\Namespace_` node, which is one of `KIND_SEMICOLON` or diff --git a/grammar/php5.y b/grammar/php5.y index 19651d8..4588046 100644 --- a/grammar/php5.y +++ b/grammar/php5.y @@ -161,7 +161,15 @@ inner_statement: ; non_empty_statement: - '{' inner_statement_list '}' { $$ = $2; prependLeadingComments($$); } + '{' inner_statement_list '}' + { + if ($2) { + $$ = $2; prependLeadingComments($$); + } else { + makeNop($$, $this->startAttributeStack[#1]); + if (null === $$) { $$ = array(); } + } + } | T_IF parentheses_expr statement elseif_list else_single { $$ = Stmt\If_[$2, ['stmts' => toArray($3), 'elseifs' => $4, 'else' => $5]]; } | T_IF parentheses_expr ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' diff --git a/grammar/php7.y b/grammar/php7.y index f24a98e..b941c49 100644 --- a/grammar/php7.y +++ b/grammar/php7.y @@ -197,7 +197,15 @@ inner_statement: ; non_empty_statement: - '{' inner_statement_list '}' { $$ = $2; prependLeadingComments($$); } + '{' inner_statement_list '}' + { + if ($2) { + $$ = $2; prependLeadingComments($$); + } else { + makeNop($$, $this->startAttributeStack[#1]); + if (null === $$) { $$ = array(); } + } + } | T_IF '(' expr ')' statement elseif_list else_single { $$ = Stmt\If_[$3, ['stmts' => toArray($5), 'elseifs' => $6, 'else' => $7]]; } | T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' diff --git a/grammar/rebuildParsers.php b/grammar/rebuildParsers.php index 0959981..340b0ea 100644 --- a/grammar/rebuildParsers.php +++ b/grammar/rebuildParsers.php @@ -205,7 +205,7 @@ function resolveMacros($code) { assertArgs(1, $args, $name); return '$attrs = $this->startAttributeStack[#1]; $stmts = ' . $args[0] . '; ' - . 'if (!empty($attrs[\'comments\']) && isset($stmts[0])) {' + . 'if (!empty($attrs[\'comments\'])) {' . '$stmts[0]->setAttribute(\'comments\', ' . 'array_merge($attrs[\'comments\'], $stmts[0]->getAttribute(\'comments\', []))); }'; } diff --git a/lib/PhpParser/Parser/Php5.php b/lib/PhpParser/Parser/Php5.php index c8ee06f..52ca59c 100644 --- a/lib/PhpParser/Parser/Php5.php +++ b/lib/PhpParser/Parser/Php5.php @@ -1416,7 +1416,14 @@ class Php5 extends \PhpParser\ParserAbstract } protected function reduceRule127() { - $this->semValue = $this->semStack[$this->stackPos-(3-2)]; $attrs = $this->startAttributeStack[$this->stackPos-(3-1)]; $stmts = $this->semValue; if (!empty($attrs['comments']) && isset($stmts[0])) {$stmts[0]->setAttribute('comments', array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); }; + + if ($this->semStack[$this->stackPos-(3-2)]) { + $this->semValue = $this->semStack[$this->stackPos-(3-2)]; $attrs = $this->startAttributeStack[$this->stackPos-(3-1)]; $stmts = $this->semValue; if (!empty($attrs['comments'])) {$stmts[0]->setAttribute('comments', array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); }; + } else { + $startAttributes = $this->startAttributeStack[$this->stackPos-(3-1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $this->semValue = null; }; + if (null === $this->semValue) { $this->semValue = array(); } + } + } protected function reduceRule128() { diff --git a/lib/PhpParser/Parser/Php7.php b/lib/PhpParser/Parser/Php7.php index eeaa637..56f5268 100644 --- a/lib/PhpParser/Parser/Php7.php +++ b/lib/PhpParser/Parser/Php7.php @@ -1370,7 +1370,14 @@ class Php7 extends \PhpParser\ParserAbstract } protected function reduceRule138() { - $this->semValue = $this->semStack[$this->stackPos-(3-2)]; $attrs = $this->startAttributeStack[$this->stackPos-(3-1)]; $stmts = $this->semValue; if (!empty($attrs['comments']) && isset($stmts[0])) {$stmts[0]->setAttribute('comments', array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); }; + + if ($this->semStack[$this->stackPos-(3-2)]) { + $this->semValue = $this->semStack[$this->stackPos-(3-2)]; $attrs = $this->startAttributeStack[$this->stackPos-(3-1)]; $stmts = $this->semValue; if (!empty($attrs['comments'])) {$stmts[0]->setAttribute('comments', array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); }; + } else { + $startAttributes = $this->startAttributeStack[$this->stackPos-(3-1)]; if (isset($startAttributes['comments'])) { $this->semValue = new Stmt\Nop(['comments' => $startAttributes['comments']]); } else { $this->semValue = null; }; + if (null === $this->semValue) { $this->semValue = array(); } + } + } protected function reduceRule139() { diff --git a/test/code/parser/blockComments.test b/test/code/parser/blockComments.test index 0d12326..a985485 100644 --- a/test/code/parser/blockComments.test +++ b/test/code/parser/blockComments.test @@ -10,6 +10,9 @@ Comments on blocks $a; } } + +// empty +{} ----- array( 0: Expr_Variable( @@ -20,4 +23,9 @@ array( 2: // baz ) ) + 1: Stmt_Nop( + comments: array( + 0: // empty + ) + ) ) \ No newline at end of file