grom358 / pharborist

A PHP library to query and transform source code via tree operations.
GNU General Public License v3.0
44 stars 10 forks source link

Fatal error: Call to a member function nextToken() on null #194

Closed pfrenssen closed 9 years ago

pfrenssen commented 9 years ago

We are using Pharborist as part of the Drupal Module Upgrader project. Recently we started getting fatal errors (ref #2409797):

PHP Fatal error:  Call to a member function previousToken() on a non-object in vendor/grom358/pharborist/src/Formatter.php on line 160
Fatal error: Call to a member function nextToken() on null in vendor/grom358/pharborist/src/Formatter.php on line 174

I tracked this down to commit 2bb27. This commit is labeled "Code cleanup" but some functional changes seem to have crept in there.

If I partially revert that commit the fatal errors go away:

diff --git a/src/Formatter.php b/src/Formatter.php
index 2449a58..eea00e0 100644
--- a/src/Formatter.php
+++ b/src/Formatter.php
@@ -703,7 +703,8 @@ class Formatter extends VisitorBase {
     $arg_list = $node->getArgumentList();
     $this->removeSpaceBefore($arg_list);
     $this->removeSpaceAfter($arg_list);
-    $this->removeSpaceBefore($node->getOpenParen());
+    $open_paren = $arg_list->previousUntil(Filter::isTokenType('('), TRUE)->get(0);
+    $this->removeSpaceBefore($open_paren);
   }

   /**
@@ -803,7 +804,8 @@ class Formatter extends VisitorBase {
   }

   public function visitObjectMethodCallNode(ObjectMethodCallNode $node) {
-    $this->removeSpaceAfter($node->getOperator());
+    $object_operator = $node->getMethodName()->previousUntil(Filter::isTokenType(T_OBJECT_OPERATOR), TRUE)->get(0);
+    $this->removeSpaceAfter($object_operator);
   }

   public function endRootNode(RootNode $node) {

I've not yet had the time to familiarize myself with the Pharborist code base, so this report might be due to a wrong implementation on our end.

phenaproxima commented 9 years ago

A possible failing test:

$class = Parser::parseSnippet('class Foo {}');
$func = Parser::parseSnippet(<<<END
function translate_set_settings_form_validate($form, $form_state) {
  if ($form_state['values']['translate_set_tracking_enabled'] && empty($form_state['values']['translate_set_tracking_contexts'])) {
    form_set_error('translate_set_tracking_contexts', t('Tracking contexts is required.'));
  }
}
END
);
$method = ClassMethodNode::fromFunction($func);
$method->setName('validateForm');
$class->appendMethod($method);
grom358 commented 9 years ago

Fixed on master