private function computeUseDef($code)
 {
     $code = sprintf('<?php function foo($param1, $param2) { %s }', $code);
     $ast = \JMS\PhpManipulator\PhpParser\ParseUtils::parse($code);
     $scope = (new \Scrutinizer\PhpAnalyzer\PhpParser\Scope\SyntacticScopeCreator())->createScope($ast);
     $cfa = new \Scrutinizer\PhpAnalyzer\ControlFlow\ControlFlowAnalysis();
     $cfa->process($ast);
     $cfg = $cfa->getGraph();
     $this->analysis = new \Scrutinizer\PhpAnalyzer\DataFlow\VariableReachability\MayBeReachingUseAnalysis($cfg, $scope);
     $this->analysis->analyze();
     $this->def = null;
     $this->uses = array();
     \Scrutinizer\PhpAnalyzer\PhpParser\NodeTraversal::traverseWithCallback($ast, new \Scrutinizer\PhpAnalyzer\PhpParser\PreOrderCallback(function ($t, \PHPParser_Node $node) {
         if (!$node instanceof \PHPParser_Node_Stmt_Label) {
             return;
         }
         if ('D' === $node->name) {
             $this->def = $node->getAttribute('next');
         } else {
             if (0 === strpos($node->name, 'U')) {
                 $this->uses[] = $node->getAttribute('next');
             }
         }
     }));
     $this->assertNotNull($this->def);
     $this->assertNotEmpty($this->uses);
 }
 /**
  * Returns the inferred return type for the given function.
  *
  * If we cannot infer any type NO type is returned, this is also returned if we can only infer
  * ALL type, or UNKNOWN type.
  *
  * We use two characteristics for inferring a return type. First, we are looking at how the
  * return value of the function is used in the places from where it is called. Currently, we
  * are only looking at whether it is passed to other functions/methods and what their expected
  * parameter types are.
  *
  * Second, we also take a look at the exit points of the CFG of the function itself to see
  * whether there are some specific types which we can infer. For example, a function might return
  * NULL type, or ALL type in which case its return type would normally be set to ALL type.
  * However, for our analysis here, we just ignore the ALL type, and add the NULL type to the
  * list of allowed types.
  *
  * @param AbstractFunction $function
  *
  * @return PhpType
  */
 private function inferReturnTypeForFunction(AbstractFunction $function, MethodContainer $container = null)
 {
     $types = array();
     if ($container instanceof \Scrutinizer\PhpAnalyzer\Model\InterfaceC) {
         foreach ($container->getImplementingClasses() as $class) {
             if (null === ($implementedFunction = $class->getMethod($function->getName()))) {
                 continue;
             }
             $returnType = $implementedFunction->getReturnType();
             if ($returnType->isUnknownType() || $returnType->isAllType()) {
                 continue;
             }
             $types[] = $returnType;
         }
     }
     if (!$types) {
         foreach ($function->getInCallSites() as $site) {
             // We can only analyze call sites which are part of the code which is currently being
             // scanned. Otherwise, we would need to persist the possible types to the database.
             // This could be a future improvement though if we deem it necessary.
             if (null === ($node = $site->getAstNode())) {
                 continue;
             }
             if (null === ($parent = $node->getAttribute('parent'))) {
                 continue;
             }
             switch (true) {
                 case $parent instanceof \PHPParser_Node_Arg:
                     if (null === ($callNode = $parent->getAttribute('parent'))) {
                         break;
                     }
                     $paramType = $this->getSpecificParamTypeForArg($callNode, $parent);
                     if ($paramType) {
                         $types[] = $paramType;
                     }
                     break;
                 case $parent instanceof \PHPParser_Node_Expr_Assign:
                 case $parent instanceof \PHPParser_Node_Expr_AssignRef:
                     foreach ($parent->var->getAttribute('maybe_using_vars', array()) as $varNode) {
                         if (null === ($argNode = $varNode->getAttribute('parent'))) {
                             continue;
                         }
                         if (!$argNode instanceof \PHPParser_Node_Arg) {
                             continue;
                         }
                         $callNode = $argNode->getAttribute('parent');
                         $paramType = $this->getSpecificParamTypeForArg($callNode, $argNode);
                         if (null !== $paramType) {
                             $types[] = $paramType;
                         }
                     }
                     break;
             }
         }
     }
     $cfa = new \Scrutinizer\PhpAnalyzer\ControlFlow\ControlFlowAnalysis();
     $cfa->process($function->getAstNode());
     $cfg = $cfa->getGraph();
     foreach ($cfg->getDirectedSuccNodes($cfg->getImplicitReturn()) as $exitGraphNode) {
         $exitNode = $exitGraphNode->getAstNode();
         if (!$exitNode instanceof \PHPParser_Node_Stmt_Return || null === $exitNode->expr) {
             $types[] = $this->registry->getNativeType('null');
             continue;
         }
         $returnType = $exitNode->expr->getAttribute('type');
         if ($returnType && !$returnType->isUnknownType() && !$returnType->isAllType()) {
             $types[] = $returnType;
         }
     }
     return $this->refineTypeForAnnotation($this->registry->createUnionType($types), true);
 }