private function computeMustDef(\PHPParser_Node $node, \PHPParser_Node $cfgNode, DefinitionLattice $output, $conditional)
 {
     switch (true) {
         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_For:
         case $node instanceof \PHPParser_Node_Stmt_If:
             if (null !== ($cond = NodeUtil::getConditionExpression($node))) {
                 $this->computeMustDef($cond, $cfgNode, $output, $conditional);
             }
             return;
         case $node instanceof \PHPParser_Node_Stmt_Foreach:
             if (null !== $node->keyVar && $node->keyVar instanceof \PHPParser_Node_Expr_Variable && is_string($node->keyVar->name)) {
                 $this->addToDefIfLocal($node->keyVar->name, $cfgNode, $node->expr, $output);
             }
             if ($node->valueVar instanceof \PHPParser_Node_Expr_Variable && is_string($node->valueVar->name)) {
                 $this->addToDefIfLocal($node->valueVar->name, $cfgNode, $node->expr, $output);
             }
             return;
         case $node instanceof \PHPParser_Node_Stmt_Catch:
             $this->addToDefIfLocal($node->var, $cfgNode, null, $output);
             return;
         case $node instanceof \PHPParser_Node_Expr_BooleanAnd:
         case $node instanceof \PHPParser_Node_Expr_BooleanOr:
         case $node instanceof \PHPParser_Node_Expr_LogicalAnd:
         case $node instanceof \PHPParser_Node_Expr_LogicalOr:
             $this->computeMustDef($node->left, $cfgNode, $output, $conditional);
             $this->computeMustDef($node->right, $cfgNode, $output, true);
             return;
         case $node instanceof \PHPParser_Node_Expr_Ternary:
             $this->computeMustDef($node->cond, $cfgNode, $output, $conditional);
             if (null !== $node->if) {
                 $this->computeMustDef($node->if, $cfgNode, $output, true);
             }
             $this->computeMustDef($node->else, $cfgNode, $output, true);
             return;
         case NodeUtil::isName($node):
             if (null !== ($var = $this->scope->getVar($node->name)) && isset($output[$var]) && null !== $output[$var]) {
                 $node->setAttribute('defining_expr', $output[$var]->getExpr());
             }
             return;
         default:
             if (NodeUtil::isAssignmentOp($node)) {
                 if ($node instanceof \PHPParser_Node_Expr_AssignList) {
                     $this->computeMustDef($node->expr, $cfgNode, $output, $conditional);
                     foreach ($node->vars as $var) {
                         if (null === $var) {
                             continue;
                         }
                         $this->addToDefIfLocal($var->name, $conditional ? null : $cfgNode, $node->expr, $output);
                     }
                     return;
                 }
                 if (NodeUtil::isName($node->var)) {
                     $this->computeMustDef($node->expr, $cfgNode, $output, $conditional);
                     $this->addToDefIfLocal($node->var->name, $conditional ? null : $cfgNode, $node->expr, $output);
                     return;
                 }
             }
             if (($node instanceof \PHPParser_Node_Expr_PostDec || $node instanceof \PHPParser_Node_Expr_PostInc || $node instanceof \PHPParser_Node_Expr_PreDec || $node instanceof \PHPParser_Node_Expr_PreInc) && NodeUtil::isName($node->var)) {
                 $this->addToDefIfLocal($node->var->name, $conditional ? null : $cfgNode, null, $output);
                 return;
             }
             foreach ($node as $subNode) {
                 if (is_array($subNode)) {
                     foreach ($subNode as $aSubNode) {
                         if (!$aSubNode instanceof \PHPParser_Node) {
                             continue;
                         }
                         $this->computeMustDef($aSubNode, $cfgNode, $output, $conditional);
                     }
                 } else {
                     if ($subNode instanceof \PHPParser_Node) {
                         $this->computeMustDef($subNode, $cfgNode, $output, $conditional);
                     }
                 }
             }
     }
 }
 private function checkForMissingProperty(\PHPParser_Node_Expr_PropertyFetch $node)
 {
     if (!is_string($node->name)) {
         return;
     }
     if (!($objType = $node->var->getAttribute('type'))) {
         return;
     }
     $objType = $objType->restrictByNotNull()->toMaybeObjectType();
     if (!$objType) {
         // TODO: Add support to check on union types.
         return;
     }
     if ($objType->isInterface()) {
         $this->phpFile->addComment($node->getLine(), Comment::warning('types.property_access_on_interface', 'Accessing "%property_name%" on the interface "%interface_name%" suggest that you code against a concrete implementation. How about adding an ``instanceof`` check?', array('property_name' => $node->name, 'interface_name' => $objType->getName())));
         return;
     }
     if (!$objType->isNormalized() || $objType->hasProperty($node->name)) {
         return;
     }
     // Ignore all property accesses on ``stdClass`` objects. Currently, we have
     // no way to describe, or track RECORD types. As such, any messages related to
     // stdClass are likely wrong, but at least there are too many false-positives
     // for now. So, we just disable this.
     if ($objType->isSubtypeOf($this->typeRegistry->getClassOrCreate('stdClass'))) {
         return;
     }
     // Ignore all property reads on ``SimpleXMLElement`` objects. The reasoning
     // behind this is similar to the exception for ``stdClass`` objects above.
     // We simply have no reliable way to describe the structure of these objects
     // for now. So, we disable checks for them to avoid a flood of false-positives.
     if (!\Scrutinizer\PhpAnalyzer\PhpParser\NodeUtil::isAssignmentOp($node->getAttribute('parent')) && $objType->isSubtypeOf($this->typeRegistry->getClassOrCreate('SimpleXMLElement'))) {
         return;
     }
     // Property accesses inside isset() are safe, do not make any noise just yet.
     if ($node->getAttribute('parent') instanceof \PHPParser_Node_Expr_Isset) {
         return;
     }
     if (null !== ($bestName = $this->getMostSimilarName($node->name, $objType->getPropertyNames()))) {
         $this->phpFile->addComment($node->getLine(), Comment::error('typos.mispelled_property_name', 'The property "%offending_property_name%" does not exist. Did you mean "%closest_property_name%"?', array('offending_property_name' => $node->name, 'closest_property_name' => $bestName)));
     } else {
         // Ignore additional accesses to this property.
         $objType->addProperty(new Property($node->name));
         if (\Scrutinizer\PhpAnalyzer\PhpParser\NodeUtil::isAssignmentOp($node->getAttribute('parent'))) {
             if ($objType->hasMethod('__set')) {
                 $this->phpFile->addComment($node->getLine(), Comment::warning('strict.maybe_undocument_property_write_capability', 'The property ``%property_name%`` does not exist. Since you implemented ``__set``, maybe consider adding a [@property annotation](http://www.phpdoc.org/docs/latest/for-users/tags/property.html).', array('property_name' => $node->name)));
                 return;
             }
         } else {
             if ($objType->hasMethod('__get')) {
                 $this->phpFile->addComment($node->getLine(), Comment::warning('strict.maybe_undocument_property_read_capability', 'The property ``%property_name%`` does not exist. Since you implemented ``__get``, maybe consider adding a [@property annotation](http://www.phpdoc.org/docs/latest/for-users/tags/property.html).', array('property_name' => $node->name)));
                 return;
             }
         }
         $thisType = $this->t->getScope()->getTypeOfThis();
         if ($thisType && $thisType->equals($objType)) {
             $this->phpFile->addComment($node->getLine(), Comment::warning('strict.undeclared_property', 'The property "%property_name%" does not exist. Did you maybe forget to declare it?', array('property_name' => $node->name)));
         } else {
             $this->phpFile->addComment($node->getLine(), Comment::error('typos.non_existent_property', 'The property "%property_name%" does not exist.', array('property_name' => $node->name)));
         }
     }
 }
 private function tryRemoveAssignment(NodeTraversal $t, \PHPParser_Node $n, \PHPParser_Node $exprRoot = null, $inState, $outState)
 {
     $parent = $n->getAttribute('parent');
     if (NodeUtil::isAssignmentOp($n)) {
         $lhs = $n->var;
         $rhs = $n->expr;
         if ($n instanceof \PHPParser_Node_Expr_AssignList) {
             $i = 0;
             foreach ($n->vars as $var) {
                 if (null === $var) {
                     $i += 1;
                     continue;
                 }
                 $newNode = new \PHPParser_Node_Expr_Assign($var, new \PHPParser_Node_Expr_ArrayDimFetch($rhs, new \PHPParser_Node_Scalar_LNumber($i)), $n->getLine());
                 $newNode->setAttribute('is_list_assign', true);
                 $this->tryRemoveAssignment($t, $newNode, $exprRoot, $inState, $outState);
                 $i += 1;
             }
             return;
         }
         // Recurse first. Example: dead_x = dead_y = 1; We try to clean up dead_y first.
         if (null !== $rhs) {
             $this->tryRemoveAssignment($t, $rhs, $exprRoot, $inState, $outState);
             $rhs = $lhs->getAttribute('next');
         }
         $scope = $t->getScope();
         if (!$lhs instanceof \PHPParser_Node_Expr_Variable || !is_string($lhs->name)) {
             return;
         }
         if (!$scope->isDeclared($lhs->name)) {
             return;
         }
         if (in_array($lhs->name, NodeUtil::$superGlobalNames, true)) {
             return;
         }
         $var = $scope->getVar($lhs->name);
         $escaped = $this->liveness->getEscapedLocals();
         if (isset($escaped[$var])) {
             return;
             // Local variable that might be escaped due to closures.
         }
         // If we have an identity assignment such as a=a, always remove it
         // regardless of what the liveness results because it does not
         // change the result afterward.
         if (null !== $rhs && $rhs instanceof \PHPParser_Node_Expr_Variable && $var->getName() === $rhs->name && $n instanceof \PHPParser_Node_Expr_Assign) {
             $this->phpFile->addComment($n->getLine(), Comment::warning('dead_assignment.assignment_to_itself', 'Why assign ``%variable%`` to itself?', array('variable' => '$' . $rhs->name)));
             return;
         }
         // At the moment we miss some dead assignments if a variable is killed,
         // and defined in the same node of the control flow graph.
         // Example: $a = 'foo'; return $a = 'bar';
         if ($outState->isLive($var)) {
             return;
             // Variable is not dead.
         }
         // Assignments to references do not need to be used in the
         // current scope.
         if ($var->isReference()) {
             return;
         }
         //             if ($inState->isLive($var)
         //                    /*&& $this->isVariableStillLiveWithinExpression($n, $exprRoot, $var->getName()) */) {
         // The variable is killed here but it is also live before it.
         // This is possible if we have say:
         //    if ($X = $a && $a = $C) {..} ; .......; $a = $S;
         // In this case we are safe to remove "$a = $C" because it is dead.
         // However if we have:
         //    if ($a = $C && $X = $a) {..} ; .......; $a = $S;
         // removing "a = C" is NOT correct, although the live set at the node
         // is exactly the same.
         // TODO: We need more fine grain CFA or we need to keep track
         // of GEN sets when we recurse here. Maybe add the comment anyway, and let the user decide?
         //                 return;
         //             }
         if ($n instanceof \PHPParser_Node_Expr_Assign) {
             if ($n->getAttribute('is_list_assign', false)) {
                 $this->phpFile->addComment($n->getLine(), Comment::warning('dead_assignment.unnecessary_list_assign', 'The assignment to ``$%variable%`` is dead. Consider omitting it like so ``list($first,,$third)``.', array('variable' => $var->getName())));
                 return;
             }
             $this->phpFile->addComment($n->getLine(), Comment::warning('dead_assignment.unnecessary_var_assign', 'The assignment to ``$%variable%`` is dead and can be removed.', array('variable' => $var->getName())));
             return;
         }
     }
 }
 /**
  * @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);
             }
     }
 }