private function inferTypesForParameter(Parameter $param, AbstractFunction $function, Clazz $clazz = null)
 {
     if (($type = $param->getPhpType()) && !$type->isUnknownType() && !$type->isNullType() && !$type->isFalse() && !$type->isAllType()) {
         return;
     }
     $allowsNull = $type && $type->isNullType();
     if (null !== ($node = $param->getAstNode())) {
         $type = $this->parser->getTypeFromParamAnnotation($node, $param->getName());
         // Check whether we can use the type of a overridden method.
         // We only do this if we find a parent method that has been defined
         // on an interface (I), or if we find an abstract method (II).
         if (null === $type && $function instanceof Method && null !== $clazz) {
             foreach ($this->findOverriddenMethodsForDocInheritance($function->getName(), $clazz) as $parentMethod) {
                 if (null !== ($docType = $parentMethod->getParamDocType($param->getIndex()))) {
                     $type = $this->parser->getType($docType);
                     break;
                 }
             }
         }
     }
     if (null === $type) {
         $type = $this->registry->getNativeType('unknown');
     } else {
         if ($allowsNull) {
             $type = $this->registry->createNullableType($type);
         }
     }
     $param->setPhpType($type);
     if ($node) {
         $node->setAttribute('type', $type);
     }
 }
 /**
  * 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);
 }