public function shouldTraverse(NodeTraversal $traversal, \PHPParser_Node $node, \PHPParser_Node $parent = null)
 {
     if (NodeUtil::isScopeCreator($node) && null !== $parent) {
         if ($node instanceof \PHPParser_Node_Expr_Closure) {
             $node->setAttribute('type', $this->typeRegistry->getClassOrCreate('Closure'));
         }
         return false;
     }
     return true;
 }
 private function addToDefIfLocal($name, \PHPParser_Node $node = null, \PHPParser_Node $rValue = null, DefinitionLattice $definitions)
 {
     $var = $this->scope->getVar($name);
     if (null === $var) {
         return;
     }
     // Invalidate other definitions if they depended on this variable as it has been changed.
     foreach ($definitions as $otherVar) {
         if (null === ($otherDef = $definitions[$otherVar])) {
             continue;
         }
         if ($otherDef->dependsOn($var)) {
             $definitions[$otherVar] = null;
         }
     }
     // The node can be null if we are dealing with a conditional definition. For conditional
     // definitions, this analysis cannot do much.
     if (null === $node) {
         $definitions[$var] = null;
         return;
     }
     $definition = new Definition($node, $rValue);
     if (null !== $rValue) {
         NodeTraversal::traverseWithCallback($rValue, new PreOrderCallback(function ($t, \PHPParser_Node $node) use($definition) {
             if (NodeUtil::isScopeCreator($node)) {
                 return false;
             }
             if (!NodeUtil::isName($node)) {
                 return;
             }
             if (null === ($var = $this->scope->getVar($node->name))) {
                 if (null !== $this->logger) {
                     $this->logger->debug(sprintf('Could not find variable "%s" in the current scope. ' . 'This could imply an error in SyntacticScopeCreator.', $node->name));
                 }
                 // We simply assume that the variable was declared so that we can properly
                 // invalidate the definition if it is changed. For this analysis, it does not
                 // matter whether it actually exists. A later pass will add a warning anyway.
                 $var = $this->scope->declareVar($node->name);
             }
             $definition->addDependentVar($var);
         }));
     }
     $definitions[$var] = $definition;
 }
 private function handleGoto(\PHPParser_Node_Stmt_Goto $node)
 {
     $parent = $node->getAttribute('parent');
     while (!NodeUtil::isScopeCreator($parent)) {
         $newParent = $parent->getAttribute('parent');
         if (null === $newParent) {
             break;
         }
         $parent = $newParent;
     }
     $nodes = \PHPParser_Finder::create(array($parent))->find('Stmt_Label[name=' . $node->name . ']');
     if (!$nodes) {
         return;
     }
     $this->graph->connectIfNotConnected($node, GraphEdge::TYPE_UNCOND, $nodes[0]);
 }
 private function traverseScopeCreator(\PHPParser_Node $node, \PHPParser_Node $parent = null)
 {
     assert(NodeUtil::isScopeCreator($node));
     $this->curNode = $node;
     $isScopeActive = $this->getScopeRoot() === $node;
     if (!$isScopeActive) {
         $this->pushScopeWithRoot($node);
     }
     // args
     foreach ($node->params as $param) {
         $this->traverseBranch($param, $node);
     }
     // uses from parent scope
     if ($node instanceof \PHPParser_Node_Expr_Closure) {
         foreach ($node->uses as $use) {
             $this->traverseBranch($use, $node);
         }
     }
     // body
     // For abstract methods the stmts property is null, which we need to check here.
     if (null !== $node->stmts) {
         $this->traverseBranch($node->stmts, $node);
     }
     if (!$isScopeActive) {
         $this->popScope();
     }
 }
 /**
  * @param boolean $conditional
  */
 private function computeMayUse(\PHPParser_Node $node, \PHPParser_Node $cfgNode, UseLattice $output, $conditional)
 {
     switch (true) {
         case $node instanceof \JMS\PhpManipulator\PhpParser\BlockNode:
         case NodeUtil::isScopeCreator($node):
             return;
         case NodeUtil::isName($node):
             $this->addToUseIfLocal($node, $cfgNode, $output);
             return;
         case $node instanceof \PHPParser_Node_Stmt_Catch:
             $this->computeMayUse($node->stmts, $cfgNode, $output, $conditional);
             $this->addDefToVarNodes($node->var, $node, $node, $output);
             $this->removeFromUseIfLocal($node->var, $output);
             return;
         case $node instanceof \PHPParser_Node_Stmt_While:
         case $node instanceof \PHPParser_Node_Stmt_Do:
         case $node instanceof \PHPParser_Node_Stmt_If:
         case $node instanceof \PHPParser_Node_Stmt_ElseIf:
         case $node instanceof \PHPParser_Node_Stmt_For:
             if (null !== ($cond = NodeUtil::getConditionExpression($node))) {
                 $this->computeMayUse($cond, $cfgNode, $output, $conditional);
             }
             return;
         case $node instanceof \PHPParser_Node_Stmt_Foreach:
             if (!$conditional) {
                 if (null !== $node->keyVar && NodeUtil::isName($node->keyVar)) {
                     $this->removeFromUseIfLocal($node->keyVar->name, $output);
                 }
                 if (NodeUtil::isName($node->valueVar)) {
                     $this->removeFromUseIfLocal($node->valueVar->name, $output);
                 }
             }
             $this->computeMayUse($node->expr, $cfgNode, $output, $conditional);
             return;
         case $node instanceof \PHPParser_Node_Expr_BooleanAnd:
         case $node instanceof \PHPParser_Node_Expr_LogicalAnd:
         case $node instanceof \PHPParser_Node_Expr_BooleanOr:
         case $node instanceof \PHPParser_Node_Expr_LogicalOr:
             $this->computeMayUse($node->right, $cfgNode, $output, true);
             $this->computeMayUse($node->left, $cfgNode, $output, $conditional);
             return;
         case $node instanceof \PHPParser_Node_Expr_Ternary:
             $this->computeMayUse($node->else, $cfgNode, $output, true);
             if (null !== $node->if) {
                 $this->computeMayUse($node->if, $cfgNode, $output, true);
             }
             $this->computeMayUse($node->cond, $cfgNode, $output, $conditional);
             return;
         default:
             if (NodeUtil::isAssignmentOp($node)) {
                 if ($node instanceof \PHPParser_Node_Expr_AssignList) {
                     foreach ($node->vars as $var) {
                         if (null === $var) {
                             continue;
                         }
                         if (!$conditional) {
                             $this->removeFromUseIfLocal($var->name, $output);
                         }
                     }
                     $this->computeMayUse($node->expr, $cfgNode, $output, $conditional);
                     return;
                 }
                 if (NodeUtil::isName($node->var)) {
                     $this->addDefToVarNodes($node->var->name, $node->var, $node->expr, $output);
                     if (!$conditional) {
                         $this->removeFromUseIfLocal($node->var->name, $output);
                     }
                     // Handle the cases where we assign, and read at the same time, e.g.
                     // ``$a += 5``.
                     if (!$node instanceof \PHPParser_Node_Expr_Assign && !$node instanceof \PHPParser_Node_Expr_AssignRef) {
                         $this->addToUseIfLocal($node->var, $cfgNode, $output);
                     }
                     $this->computeMayUse($node->expr, $cfgNode, $output, $conditional);
                     return;
                 }
                 return;
             }
             $inOrder = array();
             foreach ($node as $subNode) {
                 if (is_array($subNode)) {
                     foreach ($subNode as $aSubNode) {
                         if (!$aSubNode instanceof \PHPParser_Node) {
                             continue;
                         }
                         $inOrder[] = $aSubNode;
                     }
                 } else {
                     if ($subNode instanceof \PHPParser_Node) {
                         $inOrder[] = $subNode;
                     }
                 }
             }
             foreach (array_reverse($inOrder) as $subNode) {
                 $this->computeMayUse($subNode, $cfgNode, $output, $conditional);
             }
     }
 }
 /**
  * Computes the GEN and KILL set.
  *
  * @param boolean $conditional
  */
 private function computeGenKill(\PHPParser_Node $node, BitSet $gen, BitSet $kill, $conditional)
 {
     switch (true) {
         case $node instanceof \PHPParser_Node_Expr_Closure:
             foreach ($node->uses as $use) {
                 assert($use instanceof \PHPParser_Node_Expr_ClosureUse);
                 $this->addToSetIfLocal($use->var, $gen);
             }
             return;
         case $node instanceof BlockNode:
         case NodeUtil::isScopeCreator($node):
             return;
         case $node instanceof \PHPParser_Node_Stmt_While:
         case $node instanceof \PHPParser_Node_Stmt_Do:
         case $node instanceof \PHPParser_Node_Stmt_If:
             $this->computeGenKill($node->cond, $gen, $kill, $conditional);
             return;
         case $node instanceof \PHPParser_Node_Stmt_Foreach:
             if (null !== $node->keyVar) {
                 if ($node->keyVar instanceof \PHPParser_Node_Expr_Variable) {
                     $this->addToSetIfLocal($node->keyVar, $kill);
                     $this->addToSetIfLocal($node->keyVar, $gen);
                 } else {
                     $this->computeGenKill($node->keyVar, $gen, $kill, $conditional);
                 }
             }
             if ($node->valueVar instanceof \PHPParser_Node_Expr_Variable) {
                 $this->addToSetIfLocal($node->valueVar, $kill);
                 $this->addToSetIfLocal($node->valueVar, $gen);
             } else {
                 $this->computeGenKill($node->valueVar, $gen, $kill, $conditional);
             }
             $this->computeGenKill($node->expr, $gen, $kill, $conditional);
             return;
         case $node instanceof \PHPParser_Node_Stmt_For:
             foreach ($node->cond as $cond) {
                 $this->computeGenKill($cond, $gen, $kill, $conditional);
             }
             return;
         case $node instanceof \PHPParser_Node_Expr_BooleanAnd:
         case $node instanceof \PHPParser_Node_Expr_BooleanOr:
             $this->computeGenKill($node->left, $gen, $kill, $conditional);
             // May short circuit.
             $this->computeGenKill($node->right, $gen, $kill, true);
             return;
         case $node instanceof \PHPParser_Node_Expr_Ternary:
             $this->computeGenKill($node->cond, $gen, $kill, $conditional);
             // Assume both sides are conditional.
             if (null !== $node->if) {
                 $this->computeGenKill($node->if, $gen, $kill, true);
             }
             $this->computeGenKill($node->else, $gen, $kill, true);
             return;
         case $node instanceof \PHPParser_Node_Param:
             $this->markAllParametersEscaped();
             return;
         case $node instanceof \PHPParser_Node_Expr_Variable:
             if (!is_string($node->name)) {
                 $this->addAllToSetIfLocal($gen);
                 return;
             }
             $this->addToSetIfLocal($node->name, $gen);
             return;
         case $node instanceof \PHPParser_Node_Expr_Include:
             $this->computeGenKill($node->expr, $gen, $kill, $conditional);
             if ($node->type === \PHPParser_Node_Expr_Include::TYPE_INCLUDE || $node->type === \PHPParser_Node_Expr_Include::TYPE_REQUIRE) {
                 $this->addAllToSetIfLocal($gen);
             }
             return;
         case NodeUtil::isMaybeFunctionCall($node, 'get_defined_vars'):
             $this->addAllToSetIfLocal($gen);
             break;
         case NodeUtil::isMaybeFunctionCall($node, 'compact'):
             foreach ($node->args as $arg) {
                 $this->computeGenKill($arg, $gen, $kill, $conditional);
             }
             $varNames = array();
             $isDynamic = false;
             foreach ($node->args as $arg) {
                 if ($arg->value instanceof \PHPParser_Node_Scalar_String) {
                     $varNames[] = $arg->value->value;
                     continue;
                 }
                 if ($arg->value instanceof \PHPParser_Node_Expr_Array) {
                     foreach ($arg->value->items as $item) {
                         assert($item instanceof \PHPParser_Node_Expr_ArrayItem);
                         if ($item->value instanceof \PHPParser_Node_Scalar_String) {
                             $varNames[] = $item->value->value;
                             continue;
                         }
                         $isDynamic = true;
                         break 2;
                     }
                     continue;
                 }
                 $isDynamic = true;
                 break;
             }
             $this->addAllToSetIfLocal($gen, $isDynamic ? null : $varNames);
             return;
         case $node instanceof \PHPParser_Node_Expr_AssignList:
             foreach ($node->vars as $var) {
                 if (!$var instanceof \PHPParser_Node_Expr_Variable) {
                     continue;
                 }
                 if (!$conditional) {
                     $this->addToSetIfLocal($var->name, $kill);
                 }
                 $this->addToSetIfLocal($var->name, $gen);
             }
             $this->computeGenKill($node->expr, $gen, $kill, $conditional);
             return;
             // AssignList is already handled in the previous CASE block.
         // AssignList is already handled in the previous CASE block.
         case NodeUtil::isAssignmentOp($node) && $node->var instanceof \PHPParser_Node_Expr_Variable:
             if ($node->var->name instanceof \PHPParser_Node_Expr) {
                 $this->computeGenKill($node->var->name, $gen, $kill, $conditional);
             }
             if (!$conditional) {
                 $this->addToSetIfLocal($node->var->name, $kill);
             }
             if (!$node instanceof \PHPParser_Node_Expr_Assign) {
                 // Assignments such as a += 1 reads a first.
                 $this->addToSetIfLocal($node->var->name, $gen);
             }
             $this->computeGenKill($node->expr, $gen, $kill, $conditional);
             return;
         default:
             foreach ($node as $subNode) {
                 if (is_array($subNode)) {
                     foreach ($subNode as $aSubNode) {
                         if (!$aSubNode instanceof \PHPParser_Node) {
                             continue;
                         }
                         $this->computeGenKill($aSubNode, $gen, $kill, $conditional);
                     }
                     continue;
                 } else {
                     if (!$subNode instanceof \PHPParser_Node) {
                         continue;
                     }
                 }
                 $this->computeGenKill($subNode, $gen, $kill, $conditional);
             }
     }
 }
 private function scanVars(Node $node, Node $parent)
 {
     switch (true) {
         case $node instanceof \PHPParser_Node_Stmt_StaticVar:
             $this->declareVar($node->name, null, true, $node);
             return;
         case $node instanceof \PHPParser_Node_Expr_Variable:
             if (($parent instanceof \PHPParser_Node_Expr_Assign || $parent instanceof \PHPParser_Node_Expr_AssignRef) && is_string($node->name) && $parent->var === $node) {
                 $this->declareVar($node->name, null, true, $node);
             }
             // PHP automatically creates a variable (without issuing a warning) if an item is added
             // to a variable without the variable being declared as array previously.
             // ``function() { $a[] = 'foo'; }`` is perfectly permissible, and will create ``$a``.
             if ($parent instanceof \PHPParser_Node_Expr_ArrayDimFetch && $parent->var === $node) {
                 $parentsParent = $parent->getAttribute('parent');
                 if (($parentsParent instanceof \PHPParser_Node_Expr_Assign || $parentsParent instanceof \PHPParser_Node_Expr_AssignRef) && is_string($node->name) && $parentsParent->var === $parent) {
                     // TODO: We should better track which variables have been initialized
                     //       and which have not. This can be done by adding an undefined
                     //       type for those that have not.
                     if (!$this->scope->isDeclared($node->name)) {
                         $node->setAttribute('array_initializing_variable', true);
                     }
                     $this->declareVar($node->name, null, true, $node);
                 }
             }
             if ($parent instanceof \PHPParser_Node_Arg && $parent->getAttribute('param_expects_ref', false) && is_string($node->name)) {
                 $this->declareVar($node->name, null, true, $node);
             }
             return;
         case $node instanceof \PHPParser_Node_Expr_AssignList:
             foreach ($node->vars as $var) {
                 if ($var instanceof \PHPParser_Node_Expr_Variable && is_string($var->name)) {
                     $this->declareVar($var->name, null, true, $var);
                 }
             }
             $this->scanVars($node->expr, $node);
             return;
         case $node instanceof \PHPParser_Node_Stmt_Trait:
         case $node instanceof \PHPParser_Node_Stmt_Interface:
         case $node instanceof \PHPParser_Node_Stmt_Class:
         case NodeUtil::isScopeCreator($node):
             return;
             // do not examine their children as they belong to a different scope
         // do not examine their children as they belong to a different scope
         case $node instanceof \PHPParser_Node_Stmt_Catch:
             $this->declareVar($node->var, null, true, $node);
             $this->scanVars($node->stmts, $node);
             return;
         case $node instanceof \PHPParser_Node_Stmt_Foreach:
             if ($node->keyVar !== null && $node->keyVar instanceof \PHPParser_Node_Expr_Variable && is_string($node->keyVar->name)) {
                 $this->declareVar($node->keyVar->name, null, true, $node->keyVar);
             }
             if ($node->valueVar instanceof \PHPParser_Node_Expr_Variable && is_string($node->valueVar->name)) {
                 $this->declareVar($node->valueVar->name, null, true, $node->valueVar);
             }
             $this->scanVars($node->stmts, $node);
             return;
         default:
             foreach ($node as $subNode) {
                 if (is_array($subNode)) {
                     foreach ($subNode as $aSubNode) {
                         if (!$aSubNode instanceof \PHPParser_Node) {
                             continue;
                         }
                         $this->scanVars($aSubNode, $node);
                     }
                 } else {
                     if ($subNode instanceof \PHPParser_Node) {
                         $this->scanVars($subNode, $node);
                     }
                 }
             }
     }
 }