<commit_before><?php

namespace CodeInspector;

use CodeInspector\Issue\InvalidArgument;
use CodeInspector\Issue\FailedTypeResolution;
use CodeInspector\IssueBuffer;
use PhpParser;

class TypeChecker
{
    protected $_absolute_class;
    protected $_namespace;
    protected $_checker;
    protected $_check_nulls;

    const ASSIGNMENT_TO_RIGHT = 1;
    const ASSIGNMENT_TO_LEFT = -1;

    public function __construct(StatementsSource $source, StatementsChecker $statements_checker)
    {
        $this->_absolute_class = $source->getAbsoluteClass();
        $this->_namespace = $source->getNamespace();
        $this->_checker = $statements_checker;
    }

    /**
     * Gets all the type assertions in a conditional that are && together
     * @param  PhpParser\Node\Expr $conditional [description]
     * @return [type]                           [description]
     */
    public function getReconcilableTypeAssertions(PhpParser\Node\Expr $conditional)
    {
        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) {
            return [];
        }

        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) {
            $left_assertions = $this->getReconcilableTypeAssertions($conditional->left);
            $right_assertions = $this->getReconcilableTypeAssertions($conditional->right);

            return self::combineTypeAssertions($left_assertions, $right_assertions);
        }

        return $this->getTypeAssertions($conditional);
    }

    public function getNegatableTypeAssertions(PhpParser\Node\Expr $conditional)
    {
        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) {
            return [];
        }

        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) {
            $left_assertions = $this->getNegatableTypeAssertions($conditional->left);
            $right_assertions = $this->getNegatableTypeAssertions($conditional->right);

            return self::combineTypeAssertions($left_assertions, $right_assertions);
        }

        return $this->getTypeAssertions($conditional);
    }

    private static function combineTypeAssertions(array $left_assertions, array $right_assertions)
    {
        $keys = array_merge(array_keys($left_assertions), array_keys($right_assertions));
        $keys = array_unique($keys);

        $if_types = [];

        foreach ($keys as $key) {
            if (isset($left_assertions[$key]) && isset($right_assertions[$key])) {
                $type_assertions = array_merge(explode('|', $left_assertions[$key]), explode('|', $right_assertions[$key]));
                $if_types[$key] = implode('|', array_unique($type_assertions));
            }
            else if (isset($left_assertions[$key])) {
                $if_types[$key] = $left_assertions[$key];
            }
            else {
                $if_types[$key] = $right_assertions[$key];
            }
        }

        return $if_types;
    }

    /**
     * Gets all the type assertions in a conditional
     *
     * @param  PhpParser\Node\Expr $stmt
     * @return array
     */
    public function getTypeAssertions(PhpParser\Node\Expr $conditional)
    {
        $if_types = [];

        if ($conditional instanceof PhpParser\Node\Expr\Instanceof_) {
            $instanceof_type = $this->_getInstanceOfTypes($conditional);

            if ($instanceof_type) {<commit_msg>Fix combination of type assertions<commit_after><?php

namespace CodeInspector;

use CodeInspector\Issue\InvalidArgument;
use CodeInspector\Issue\FailedTypeResolution;
use CodeInspector\IssueBuffer;
use PhpParser;

class TypeChecker
{
    protected $_absolute_class;
    protected $_namespace;
    protected $_checker;
    protected $_check_nulls;

    const ASSIGNMENT_TO_RIGHT = 1;
    const ASSIGNMENT_TO_LEFT = -1;

    public function __construct(StatementsSource $source, StatementsChecker $statements_checker)
    {
        $this->_absolute_class = $source->getAbsoluteClass();
        $this->_namespace = $source->getNamespace();
        $this->_checker = $statements_checker;
    }

    /**
     * Gets all the type assertions in a conditional that are && together
     * @param  PhpParser\Node\Expr $conditional [description]
     * @return [type]                           [description]
     */
    public function getReconcilableTypeAssertions(PhpParser\Node\Expr $conditional)
    {
        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) {
            return [];
        }

        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) {
            $left_assertions = $this->getReconcilableTypeAssertions($conditional->left);
            $right_assertions = $this->getReconcilableTypeAssertions($conditional->right);

            return self::combineTypeAssertions($left_assertions, $right_assertions);
        }

        return $this->getTypeAssertions($conditional);
    }

    public function getNegatableTypeAssertions(PhpParser\Node\Expr $conditional)
    {
        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanAnd) {
            return [];
        }

        if ($conditional instanceof PhpParser\Node\Expr\BinaryOp\BooleanOr) {
            $left_assertions = $this->getNegatableTypeAssertions($conditional->left);
            $right_assertions = $this->getNegatableTypeAssertions($conditional->right);

            return self::combineTypeAssertions($left_assertions, $right_assertions);
        }

        return $this->getTypeAssertions($conditional);
    }

    private static function combineTypeAssertions(array $left_assertions, array $right_assertions)
    {
        $keys = array_merge(array_keys($left_assertions), array_keys($right_assertions));
        $keys = array_unique($keys);

        $if_types = [];

        foreach ($keys as $key) {
            if (isset($left_assertions[$key]) && isset($right_assertions[$key])) {
                if ($left_assertions[$key][0] !== '!' && $right_assertions[$key][0] !== '!') {
                    $if_types[$key] = $left_assertions[$key] . '&' . $right_assertions[$key];
                }
                else {
                    $if_types[$key] = $right_assertions[$key];
                }
            }
            else if (isset($left_assertions[$key])) {
                $if_types[$key] = $left_assertions[$key];
            }
            else {
                $if_types[$key] = $right_assertions[$key];
            }
        }

        return $if_types;
    }

    /**
     * Gets all the type assertions in a conditional
     *
     * @param  PhpParser\Node\Expr $stmt
     * @return array
     */
    public function getTypeAssertions(PhpParser\Node\Expr $conditional)
    {
        $if_types = [];

        if ($conditional instanceof PhpParser\Node\Expr\Instanceof_) {
            $instanceof_type = $this->_getInstanceOfTypes($conditional);

            if ($instanceof_type) {
{'fraction_non_alphanumeric': 0.11485606827715898, 'fraction_numerical': 0.0008679299869810502, 'mean_word_length': 2.705251875669882, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5916654', 'n_tokens_mistral': 1984, 'n_tokens_neox': 1896, 'n_words': 335}