private function checkForTypeFunctionCall(\PHPParser_Node $node, LinkedFlowScope $blindScope, $outcome)
 {
     if ($node instanceof \PHPParser_Node_Stmt_Case) {
         $left = $node->getAttribute('parent')->cond;
         $right = $node->cond;
     } else {
         $left = $node->left;
         $right = $node->right;
     }
     // Handle gettype() function calls.
     $gettypeNode = $stringNode = null;
     if (NodeUtil::isGetTypeFunctionCall($left) && $right instanceof \PHPParser_Node_Scalar_String) {
         $gettypeNode = $left;
         $stringNode = $right;
     } else {
         if (NodeUtil::isGetTypeFunctionCall($right) && $left instanceof \PHPParser_Node_Scalar_String) {
             $gettypeNode = $right;
             $stringNode = $left;
         }
     }
     if (null !== $gettypeNode && null !== $stringNode && isset($gettypeNode->args[0])) {
         $operandNode = $gettypeNode->args[0]->value;
         $operandType = $this->getTypeIfRefinable($operandNode, $blindScope);
         if (null !== $operandType) {
             $resultEqualsValue = $node instanceof \PHPParser_Node_Expr_Equal || $node instanceof \PHPParser_Node_Expr_Identical || $node instanceof \PHPParser_Node_Stmt_Case;
             if (!$outcome) {
                 $resultEqualsValue = !$resultEqualsValue;
             }
             return $this->caseGettypeFunctionCall($operandNode, $operandType, $stringNode->value, $resultEqualsValue, $blindScope);
         }
     }
     // Handle get_class() function calls.
     $getClassNode = $stringNode = null;
     if ('get_class' === NodeUtil::getFunctionName($left) && $right instanceof \PHPParser_Node_Scalar_String) {
         $getClassNode = $left;
         $stringNode = $right;
     } else {
         if ('get_class' === NodeUtil::getFunctionName($right) && $left instanceof \PHPParser_Node_Scalar_String) {
             $getClassNode = $right;
             $stringNode = $left;
         }
     }
     if (null !== $getClassNode && null !== $stringNode && isset($getClassNode->args[0])) {
         $operandNode = $getClassNode->args[0]->value;
         $operandType = $this->getTypeIfRefinable($operandNode, $blindScope);
         if (null !== $operandType) {
             $resultEqualsValue = $node instanceof \PHPParser_Node_Expr_Equal || $node instanceof \PHPParser_Node_Expr_Identical || $node instanceof \PHPParser_Node_Stmt_Case;
             if (!$outcome) {
                 $resultEqualsValue = !$resultEqualsValue;
             }
             return $this->caseGetClassFunctionCall($operandNode, $operandType, $stringNode->value, $resultEqualsValue, $blindScope);
         }
     }
     // Handle is_??? and assert function calls as well as instanceof checks.
     $typeFunctionNode = $booleanNode = null;
     if ((NodeUtil::isTypeFunctionCall($left) || NodeUtil::isMaybeFunctionCall($left, 'assert') || $left instanceof \PHPParser_Node_Expr_Instanceof) && NodeUtil::isBoolean($right)) {
         $typeFunctionNode = $left;
         $booleanNode = $right;
     } else {
         if ((NodeUtil::isTypeFunctionCall($right) || NodeUtil::isMaybeFunctionCall($right, 'assert') || $right instanceof \PHPParser_Node_Expr_Instanceof) && NodeUtil::isBoolean($left)) {
             $typeFunctionNode = $right;
             $booleanNode = $left;
         }
     }
     if (null !== $booleanNode && null !== $typeFunctionNode) {
         $expectedOutcome = NodeUtil::getBooleanValue($booleanNode) ? $outcome : !$outcome;
         if ($typeFunctionNode instanceof \PHPParser_Node_Expr_Instanceof) {
             return $this->firstPreciserScopeKnowingConditionOutcome($typeFunctionNode, $blindScope, $expectedOutcome);
         }
         if (isset($typeFunctionNode->args[0])) {
             if (NodeUtil::isMaybeFunctionCall($typeFunctionNode, 'assert')) {
                 return $this->firstPreciserScopeKnowingConditionOutcome($typeFunctionNode->args[0]->value, $blindScope, $expectedOutcome);
             }
             return $this->caseTypeFunctionCall($typeFunctionNode->name, $typeFunctionNode->args[0], $blindScope, $expectedOutcome);
         }
     }
     return null;
 }
 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;
     }
 }