public function parse(\PHPParser_Node_Stmt_Function $node)
 {
     $function = new GlobalFunction(implode("\\", $node->namespacedName->parts));
     $function->setImportedNamespaces($this->importedNamespaces);
     $function->setAstNode($node);
     $function->setReturnByRef($node->byRef);
     $function->setVariableParameters(false !== strpos($node->getDocComment(), '@jms-variable-parameters'));
     foreach ($this->paramParser->parse($node->params, 'Scrutinizer\\PhpAnalyzer\\Model\\FunctionParameter') as $param) {
         $function->addParameter($param);
     }
     return $function;
 }
 public function persist(GlobalFunction $function, $packageVersionId)
 {
     $this->insertStmt->bindValue(1, $this->phpType->convertToDatabaseValue($function->getReturnType(), $this->platform));
     $this->insertStmt->bindValue(2, $function->getName());
     $this->insertStmt->bindValue(3, $function->isReturnByRef() ? 1 : 0, \PDO::PARAM_INT);
     $this->insertStmt->bindValue(4, $packageVersionId, \PDO::PARAM_INT);
     $this->insertStmt->bindValue(5, $function->hasVariableParameters() ? 1 : 0, \PDO::PARAM_INT);
     $this->insertStmt->execute();
     $functionId = $this->con->lastInsertId();
     $this->functionIdRef->setValue($function, $functionId);
     foreach ($function->getParameters() as $param) {
         $this->paramPersister->persist($param, $function);
     }
     foreach ($function->getInCallSites() as $callSite) {
         $this->callSitePersister->persist($callSite);
     }
     foreach ($function->getOutCallSites() as $callSite) {
         $this->callSitePersister->persist($callSite);
     }
 }
 public function registerFunction(GlobalFunction $function)
 {
     $this->functions[strtolower($function->getName())] = $function;
 }
 /**
  * @group definingExpr
  */
 public function testDefiningExprIsCheckedForVariables()
 {
     $this->registry->registerFunction($function = new GlobalFunction('is_array'));
     $function->setReturnType($this->registry->getNativeType('boolean'));
     $ast = $this->analyzeAst('TypeInference/defining_expr_for_variable.php');
     $this->assertTypedAst($ast, 'defining_expr_for_variable');
 }
 public function addFunction(GlobalFunction $function)
 {
     $function->setPackageVersion($this);
     $this->functions->set($function->getName(), $function);
 }
 private function createFunction($name, $returnType = 'all')
 {
     $func = new GlobalFunction($name);
     $func->setReturnType($this->registry->resolveType($returnType));
     return $func;
 }
 public function getPreciserFunctionReturnTypeKnowingArguments(GlobalFunction $function, array $argValues, array $argTypes)
 {
     switch ($function->getName()) {
         case 'array_change_key_case':
             return $this->casePreserveIncomingArray($argTypes, 'false');
         case 'array_chunk':
         case 'array_combine':
             // TODO
             break;
         case 'array_diff_assoc':
         case 'array_diff_key':
         case 'array_diff_uassoc':
         case 'array_diff_ukey':
         case 'array_diff':
             return $this->casePreserveIncomingArray($argTypes);
         case 'array_fill_keys':
         case 'array_fill':
         case 'array_filter':
         case 'array_flip':
             // TODO
             break;
         case 'array_intersect_assoc':
         case 'array_intersect_key':
         case 'array_intersect_uassoc':
         case 'array_intersect_ukey':
         case 'array_intersect':
             return $this->casePreserveIncomingArray($argTypes);
         case 'array_keys':
             return $this->caseArrayKeys($argTypes);
         case 'array_merge_recursive':
         case 'array_replace_recursive':
         case 'array_merge':
         case 'array_replace':
             return $this->caseArrayMergeReplace($argTypes, $function->getName());
         case 'array_pad':
             return $this->caseArrayPad($argTypes);
         case 'array_pop':
             return $this->caseArrayPop($argTypes);
         case 'array_rand':
             // TODO
             break;
         case 'array_reverse':
             return $this->casePreserveIncomingArray($argTypes);
         case 'array_search':
             return $this->caseArraySearch($argTypes);
         case 'array_shift':
             return $this->caseElementTypeOrElse($argTypes, 'null');
         case 'array_slice':
         case 'array_splice':
             return $this->casePreserveIncomingArray($argTypes);
         case 'array_udiff_assoc':
         case 'array_udiff_uassoc':
         case 'array_udiff':
         case 'array_uintersect_assoc':
         case 'array_uintersect_uassoc':
         case 'array_uintersect':
             return $this->casePreserveIncomingArray($argTypes);
         case 'array_unique':
             return $this->casePreserveIncomingArray($argTypes);
         case 'array_values':
             return $this->caseArrayValues($argTypes);
         case 'compact':
             // TODO
             break;
         case 'current':
         case 'end':
         case 'next':
         case 'pos':
         case 'prev':
         case 'reset':
             return $this->caseElementTypeOrElse($argTypes, 'false');
         case 'each':
         case 'extract':
         case 'key':
         case 'range':
             // TODO
             break;
     }
     return null;
 }
 public function addFunction(GlobalFunction $function)
 {
     $this->functions[$function->getName()] = $function;
 }
 public function getPreciserFunctionReturnTypeKnowingArguments(GlobalFunction $function, array $argValues, array $argTypes)
 {
     switch ($function->getName()) {
         case 'version_compare':
             switch (count($argTypes)) {
                 case 2:
                     return $this->registry->getNativeType('integer');
                 case 3:
                     return $this->registry->getNativeType('boolean');
                 default:
                     return $this->registry->resolveType('integer|boolean');
             }
         case 'unserialize':
             return $this->registry->getNativeType('unknown_checked');
         case 'var_export':
             if (count($argValues) !== 2) {
                 return null;
             }
             if (\Scrutinizer\PhpAnalyzer\PhpParser\NodeUtil::isBoolean($argValues[1]) && \Scrutinizer\PhpAnalyzer\PhpParser\NodeUtil::getBooleanValue($argValues[1]) === true) {
                 return $this->registry->getNativeType('string');
             }
             return null;
         case 'min':
         case 'max':
             switch (count($argTypes)) {
                 case 0:
                     return null;
                 case 1:
                     if ($argTypes[0]->isArrayType()) {
                         return $argTypes[0]->getElementType();
                     }
                     return null;
                 default:
                     // TODO: We could make this a bit smarter as some types are always considered
                     //       greater/smaller than other types.
                     //       See http://de1.php.net/manual/en/language.operators.comparison.php
                     return $this->registry->createUnionType($argTypes);
             }
         case 'str_replace':
         case 'preg_filter':
         case 'preg_replace':
         case 'preg_replace_callback':
             if (isset($argTypes[2])) {
                 if ($argTypes[2]->isUnknownType()) {
                     return $this->registry->getNativeType('unknown');
                 }
                 if ($argTypes[2]->isArrayType()) {
                     return $this->registry->resolveType('array<string>');
                 }
                 $nullableScalar = $this->registry->createNullableType($this->registry->getNativeType('scalar'));
                 if ($argTypes[2]->isSubtypeOf($nullableScalar)) {
                     return $this->registry->getNativeType('string');
                 }
             }
             return null;
             // Use the non-restricted type if we don't know.
         // Use the non-restricted type if we don't know.
         default:
             return null;
     }
 }