public function persist(MethodContainer $container, $packageVersionId)
 {
     switch (true) {
         case $container instanceof Clazz:
             $type = 'class';
             $superClass = $container->getSuperClass();
             if ($superClasses = $container->getSuperClasses()) {
                 $superClasses = implode(',', $superClasses);
             } else {
                 $superClasses = null;
             }
             if ($implementedInterfaces = $container->getImplementedInterfaces()) {
                 $implementedInterfaces = implode(',', $implementedInterfaces);
             } else {
                 $implementedInterfaces = null;
             }
             $modifier = $container->getModifier();
             $extendedInterfaces = null;
             break;
         case $container instanceof InterfaceC:
             $type = 'interface';
             $superClass = null;
             $superClasses = null;
             $implementedInterfaces = null;
             $modifier = 0;
             if ($extendedInterfaces = $container->getExtendedInterfaces()) {
                 $extendedInterfaces = implode(',', $extendedInterfaces);
             } else {
                 $extendedInterfaces = null;
             }
             break;
         case $container instanceof TraitC:
             $type = 'trait';
             $superClass = null;
             $superClasses = null;
             $implementedInterfaces = null;
             $modifier = 0;
             $extendedInterfaces = null;
             break;
         default:
             throw new \InvalidArgumentException('Unknown MethodContainer ' . get_class($container));
     }
     $this->insertStmt->bindValue(1, $container->getName());
     $this->insertStmt->bindValue(2, $container->isNormalized() ? 1 : 0, \PDO::PARAM_INT);
     $this->insertStmt->bindValue(3, $packageVersionId, \PDO::PARAM_INT);
     $this->insertStmt->bindValue(4, $type);
     $this->insertStmt->bindValue(5, $superClass, null === $superClass ? \PDO::PARAM_NULL : \PDO::PARAM_STR);
     $this->insertStmt->bindValue(6, $superClasses, null === $superClasses ? \PDO::PARAM_NULL : \PDO::PARAM_STR);
     $this->insertStmt->bindValue(7, $implementedInterfaces, null === $implementedInterfaces ? \PDO::PARAM_NULL : \PDO::PARAM_STR);
     $this->insertStmt->bindValue(8, $modifier, \PDO::PARAM_INT);
     $this->insertStmt->bindValue(9, $extendedInterfaces, null === $extendedInterfaces ? \PDO::PARAM_NULL : \PDO::PARAM_STR);
     $this->insertStmt->execute();
     $containerId = $this->con->lastInsertId();
     foreach ($container->getMethods() as $method) {
         $this->methodPersister->persist($method, $packageVersionId, $containerId);
     }
     switch (true) {
         case $container instanceof Clazz:
             foreach ($container->getProperties() as $property) {
                 $this->propertyPersister->persist($property, $packageVersionId, $containerId);
             }
             foreach ($container->getConstants() as $constant) {
                 $this->constantPersister->persist($constant, $packageVersionId, $containerId);
             }
             break;
         case $container instanceof InterfaceC:
             foreach ($container->getConstants() as $constant) {
                 $this->constantPersister->persist($constant, $packageVersionId, $containerId);
             }
             break;
         case $container instanceof TraitC:
             break;
         default:
             throw new \InvalidArgumentException('Unknown MethodContainer ' . get_class($container));
     }
 }
 public function registerClass(MethodContainer $class)
 {
     $class->setTypeRegistry($this);
     $this->classes[strtolower($class->getName())] = $class;
 }
 public function setPackageVersion(PackageVersion $packageVersion)
 {
     parent::setPackageVersion($packageVersion);
     foreach ($this->constants as $constant) {
         if ($constant->isInherited()) {
             continue;
         }
         $constant->setPackageVersion($packageVersion);
     }
 }
 public function addContainer(MethodContainer $container)
 {
     $container->setPackageVersion($this);
     $this->containers->set($container->getName(), $container);
 }
 /**
  * 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);
 }
 public function addClass(MethodContainer $container)
 {
     $this->classes[strtolower($container->getName())] = $container;
 }
 public function __construct($name)
 {
     parent::__construct($name);
     $this->methods = new ArrayCollection();
     $this->properties = new ArrayCollection();
 }
 private function scanMethod(\PHPParser_Node_Stmt_ClassMethod $stmt, MethodContainer $class)
 {
     $method = new Method($stmt->name);
     $method->setAstNode($stmt);
     $method->setReturnByRef($stmt->byRef);
     // convert PHPParser modifier to our modifier
     $modifier = 0;
     if (\PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT === ($stmt->type & \PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT)) {
         $modifier |= Method::MODIFIER_ABSTRACT;
     }
     if (\PHPParser_Node_Stmt_Class::MODIFIER_FINAL === ($stmt->type & \PHPParser_Node_Stmt_Class::MODIFIER_FINAL)) {
         $modifier |= Method::MODIFIER_FINAL;
     }
     if (\PHPParser_Node_Stmt_Class::MODIFIER_STATIC === ($stmt->type & \PHPParser_Node_Stmt_Class::MODIFIER_STATIC)) {
         $modifier |= Method::MODIFIER_STATIC;
     }
     // All interface methods are automatically abstract without being declared as such.
     if ($class instanceof InterfaceC) {
         $modifier |= Method::MODIFIER_ABSTRACT;
     }
     $method->setModifier($modifier);
     $method->setVisibility(\PHPParser_Node_Stmt_Class::MODIFIER_PRIVATE === ($stmt->type & \PHPParser_Node_Stmt_Class::MODIFIER_PRIVATE) ? Method::VISIBILITY_PRIVATE : (\PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED === ($stmt->type & \PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED) ? Method::VISIBILITY_PROTECTED : Method::VISIBILITY_PUBLIC));
     foreach ($this->paramParser->parse($stmt->params, 'Scrutinizer\\PhpAnalyzer\\Model\\MethodParameter') as $param) {
         $method->addParameter($param);
     }
     foreach ($stmt->params as $i => $param) {
         if (null !== ($docType = $this->commentParser->getTypeFromParamAnnotation($param, $param->name, true))) {
             $method->setParamDocType($i, $docType);
         }
     }
     if (null !== ($returnDocType = $this->commentParser->getTypeFromReturnAnnotation($stmt, true))) {
         $method->setReturnDocType($returnDocType);
     }
     $class->addMethod($method);
 }
 private function copyMethods(MethodContainer $a, MethodContainer $b)
 {
     // merge in methods from $b into $a
     foreach ($b->getMethods() as $containerMethod) {
         // method already exists on $a
         if ($a->hasMethod($containerMethod->getName())) {
             // TODO: Check types for the method in $a, and if not complete
             //       copy over all available types from $b
             continue;
         }
         $method = $containerMethod->getMethod();
         // We do copy over all methods, even private ones. See above for properties.
         $a->addMethod($method, $containerMethod->getDeclaringClass());
     }
 }