@param  StatementsAnalyzer   $statements_analyzer
@param  PhpParser\Node\Expr $stmt
@param  Context             $context

@return false|null
487464
protected static function analyzeIssetVar(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr $stmt,
        Context $context
    ) {

        $context->inside_isset = true;

        if (self::analyze($statements_analyzer, $stmt, $context) === false) {
            return false;
        }

        $context->inside_isset = false;
    }
1250110
protected void executeStatements(TestContext context) {
        for (String stmt : statements)  {
            try {
                final String toExecute;

                if (stmt.trim().endsWith(";")) {
                    toExecute = context.replaceDynamicContentInString(stmt.trim().substring(0, stmt.trim().length()-1));
                } else {
                    toExecute = context.replaceDynamicContentInString(stmt.trim());
                }

                if (log.isDebugEnabled()) {
                    log.debug("Executing SQL statement: " + toExecute);
                }

                getJdbcTemplate().execute(toExecute);

                log.info("SQL statement execution successful");
            } catch (Exception e) {
                if (ignoreErrors) {
                    log.error("Ignoring error while executing SQL statement: " + e.getLocalizedMessage());
                    continue;
                } else {
                    throw new CitrusRuntimeException(e);
                }
            }
        }
    }
1210576
public static function analyzeAssignmentRef(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr\AssignRef $stmt,
        Context $context
    ) {
        if (self::analyze(
            $statements_analyzer,
            $stmt->var,
            $stmt->expr,
            null,
            $context,
            (string)$stmt->getDocComment()
        ) === false) {
            return false;
        }

        $lhs_var_id = ExpressionAnalyzer::getVarId(
            $stmt->var,
            $statements_analyzer->getFQCLN(),
            $statements_analyzer
        );

        $rhs_var_id = ExpressionAnalyzer::getVarId(
            $stmt->expr,
            $statements_analyzer->getFQCLN(),
            $statements_analyzer
        );

        if ($lhs_var_id) {
            $context->vars_in_scope[$lhs_var_id] = Type::getMixed();
        }

        if ($rhs_var_id) {
            $context->vars_in_scope[$rhs_var_id] = Type::getMixed();
        }
    }
523087
public static function analyzeClassConst(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr\ClassConstFetch $stmt,
        Context $context
    ) {
        $codebase = $statements_analyzer->getCodebase();

        if ($stmt->class instanceof PhpParser\Node\Name) {
            if ($context->check_consts
                || ($stmt->name instanceof PhpParser\Node\Identifier && $stmt->name->name === 'class')
            ) {
                $first_part_lc = strtolower($stmt->class->parts[0]);

                if ($first_part_lc === 'self' || $first_part_lc === 'static') {
                    if (!$context->self) {
                        throw new \UnexpectedValueException('$context->self cannot be null');
                    }

                    $fq_class_name = (string)$context->self;
                } elseif ($first_part_lc === 'parent') {
                    $fq_class_name = $statements_analyzer->getParentFQCLN();

                    if ($fq_class_name === null) {
                        if (IssueBuffer::accepts(
                            new ParentNotFound(
                                'Cannot check property fetch on parent as this class does not extend another',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            return false;
                        }

                        return;
                    }
                } else {
                    $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject(
                        $stmt->class,
                        $statements_analyzer->getAliases()
                    );

                    if ($stmt->name instanceof PhpParser\Node\Identifier) {
                        if (!$context->inside_class_exists || $stmt->name->name !== 'class') {
                            if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                                $statements_analyzer,
                                $fq_class_name,
                                new CodeLocation($statements_analyzer->getSource(), $stmt->class),
                                $statements_analyzer->getSuppressedIssues(),
                                false,
                                true
                            ) === false) {
                                return false;
                            }
                        }
                    }
                }

                if ($stmt->name instanceof PhpParser\Node\Identifier && $stmt->name->name === 'class') {
                    $stmt->inferredType = Type::getLiteralClassString($fq_class_name);

                    if ($codebase->store_node_types) {
                        $codebase->analyzer->addNodeReference(
                            $statements_analyzer->getFilePath(),
                            $stmt->class,
                            $fq_class_name
                        );
                    }

                    return null;
                }

                // if we're ignoring that the class doesn't exist, exit anyway
                if (!$codebase->classOrInterfaceExists($fq_class_name)) {
                    $stmt->inferredType = Type::getMixed();

                    return null;
                }

                if ($codebase->store_node_types) {
                    $codebase->analyzer->addNodeReference(
                        $statements_analyzer->getFilePath(),
                        $stmt->class,
                        $fq_class_name
                    );
                }

                if (!$stmt->name instanceof PhpParser\Node\Identifier) {
                    return null;
                }

                $const_id = $fq_class_name . '::' . $stmt->name;

                if ($codebase->store_node_types) {
                    $codebase->analyzer->addNodeReference(
                        $statements_analyzer->getFilePath(),
                        $stmt->name,
                        $const_id
                    );
                }

                if ($fq_class_name === $context->self
                    || (
                        $statements_analyzer->getSource()->getSource() instanceof TraitAnalyzer &&
                        $fq_class_name === $statements_analyzer->getSource()->getFQCLN()
                    )
                ) {
                    $class_visibility = \ReflectionProperty::IS_PRIVATE;
                } elseif ($context->self &&
                    $codebase->classExtends($context->self, $fq_class_name)
                ) {
                    $class_visibility = \ReflectionProperty::IS_PROTECTED;
                } else {
                    $class_visibility = \ReflectionProperty::IS_PUBLIC;
                }

                $class_constants = $codebase->classlikes->getConstantsForClass(
                    $fq_class_name,
                    $class_visibility
                );

                if (!isset($class_constants[$stmt->name->name]) && $first_part_lc !== 'static') {
                    $all_class_constants = [];

                    if ($fq_class_name !== $context->self) {
                        $all_class_constants = $codebase->classlikes->getConstantsForClass(
                            $fq_class_name,
                            \ReflectionProperty::IS_PRIVATE
                        );
                    }

                    if ($all_class_constants && isset($all_class_constants[$stmt->name->name])) {
                        if (IssueBuffer::accepts(
                            new InaccessibleClassConstant(
                                'Constant ' . $const_id . ' is not visible in this context',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }
                    } else {
                        if (IssueBuffer::accepts(
                            new UndefinedConstant(
                                'Constant ' . $const_id . ' is not defined',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }
                    }

                    return false;
                }

                if ($context->calling_method_id) {
                    $codebase->file_reference_provider->addMethodReferenceToClassMember(
                        $context->calling_method_id,
                        strtolower($fq_class_name) . '::' . $stmt->name->name
                    );
                }

                $class_const_storage = $codebase->classlike_storage_provider->get($fq_class_name);

                if (isset($class_const_storage->deprecated_constants[$stmt->name->name])) {
                    if (IssueBuffer::accepts(
                        new DeprecatedConstant(
                            'Constant ' . $const_id . ' is deprecated',
                            new CodeLocation($statements_analyzer->getSource(), $stmt)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }

                if (isset($class_constants[$stmt->name->name]) && $first_part_lc !== 'static') {
                    $stmt->inferredType = clone $class_constants[$stmt->name->name];
                    $context->vars_in_scope[$const_id] = $stmt->inferredType;
                } else {
                    $stmt->inferredType = Type::getMixed();
                }

                return null;
            }
        } elseif ($stmt->name instanceof PhpParser\Node\Identifier && $stmt->name->name === 'class') {
            ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context);
            $lhs_type = $stmt->class->inferredType;

            $class_string_types = [];

            $has_mixed_or_object = false;

            if ($lhs_type) {
                foreach ($lhs_type->getTypes() as $lhs_atomic_type) {
                    if ($lhs_atomic_type instanceof Type\Atomic\TNamedObject) {
                        $class_string_types[] = new Type\Atomic\TClassString(
                            $lhs_atomic_type->value,
                            clone $lhs_atomic_type
                        );
                    } elseif ($lhs_atomic_type instanceof Type\Atomic\TObject
                        || $lhs_atomic_type instanceof Type\Atomic\TMixed
                    ) {
                        $has_mixed_or_object = true;
                    }
                }
            }

            if ($has_mixed_or_object) {
                $stmt->inferredType = new Type\Union([new Type\Atomic\TClassString()]);
            } elseif ($class_string_types) {
                $stmt->inferredType = new Type\Union($class_string_types);
            } else {
                $stmt->inferredType = Type::getMixed();
            }

            return;
        }

        $stmt->inferredType = Type::getMixed();

        if ($stmt->class instanceof PhpParser\Node\Expr) {
            if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context) === false) {
                return false;
            }
        }

        return null;
    }
1057906
public static function analyze(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr\ArrayDimFetch $stmt,
        Context $context
    ) {
        $array_var_id = ExpressionAnalyzer::getArrayVarId(
            $stmt->var,
            $statements_analyzer->getFQCLN(),
            $statements_analyzer
        );

        $keyed_array_var_id = ExpressionAnalyzer::getArrayVarId(
            $stmt,
            $statements_analyzer->getFQCLN(),
            $statements_analyzer
        );

        if ($stmt->dim && ExpressionAnalyzer::analyze($statements_analyzer, $stmt->dim, $context) === false) {
            return false;
        }

        $dim_var_id = null;
        $new_offset_type = null;

        if ($stmt->dim) {
            if (isset($stmt->dim->inferredType)) {
                $used_key_type = $stmt->dim->inferredType;
            } else {
                $used_key_type = Type::getMixed();
            }

            $dim_var_id = ExpressionAnalyzer::getArrayVarId(
                $stmt->dim,
                $statements_analyzer->getFQCLN(),
                $statements_analyzer
            );
        } else {
            $used_key_type = Type::getInt();
        }

        if (ExpressionAnalyzer::analyze(
            $statements_analyzer,
            $stmt->var,
            $context
        ) === false) {
            return false;
        }

        if ($keyed_array_var_id
            && $context->hasVariable($keyed_array_var_id)
            && !$context->vars_in_scope[$keyed_array_var_id]->possibly_undefined
        ) {
            $stmt->inferredType = clone $context->vars_in_scope[$keyed_array_var_id];

            return;
        }

        $codebase = $statements_analyzer->getCodebase();

        if (isset($stmt->var->inferredType)) {
            $var_type = $stmt->var->inferredType;

            if ($var_type->isNull()) {
                if (!$context->inside_isset) {
                    if (IssueBuffer::accepts(
                        new NullArrayAccess(
                            'Cannot access array value on null variable ' . $array_var_id,
                            new CodeLocation($statements_analyzer->getSource(), $stmt)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }

                if (isset($stmt->inferredType)) {
                    $stmt->inferredType = Type::combineUnionTypes($stmt->inferredType, Type::getNull());
                } else {
                    $stmt->inferredType = Type::getNull();
                }

                return;
            }

            $stmt->inferredType = self::getArrayAccessTypeGivenOffset(
                $statements_analyzer,
                $stmt,
                $stmt->var->inferredType,
                $used_key_type,
                false,
                $array_var_id,
                $context,
                null
            );

            if ($context->inside_isset
                && $stmt->dim
                && isset($stmt->dim->inferredType)
                && $stmt->var->inferredType->hasArray()
                && ($stmt->var instanceof PhpParser\Node\Expr\ClassConstFetch
                    || $stmt->var instanceof PhpParser\Node\Expr\ConstFetch)
            ) {
                /** @var TArray|ObjectLike */
                $array_type = $stmt->var->inferredType->getTypes()['array'];

                if ($array_type instanceof TArray) {
                    $const_array_key_type = $array_type->type_params[0];
                } else {
                    $const_array_key_type = $array_type->getGenericKeyType();
                }

                if ($dim_var_id
                    && !$const_array_key_type->hasMixed()
                    && !$stmt->dim->inferredType->hasMixed()
                ) {
                    $new_offset_type = clone $stmt->dim->inferredType;
                    $const_array_key_atomic_types = $const_array_key_type->getTypes();

                    foreach ($new_offset_type->getTypes() as $offset_key => $offset_atomic_type) {
                        if ($offset_atomic_type instanceof TString
                            || $offset_atomic_type instanceof TInt
                        ) {
                            if (!isset($const_array_key_atomic_types[$offset_key])
                                && !TypeAnalyzer::isContainedBy(
                                    $codebase,
                                    new Type\Union([$offset_atomic_type]),
                                    $const_array_key_type
                                )
                            ) {
                                $new_offset_type->removeType($offset_key);
                            }
                        } elseif (!TypeAnalyzer::isContainedBy(
                            $codebase,
                            $const_array_key_type,
                            new Type\Union([$offset_atomic_type])
                        )) {
                            $new_offset_type->removeType($offset_key);
                        }
                    }
                }
            }
        }

        if ($keyed_array_var_id && $context->hasVariable($keyed_array_var_id, $statements_analyzer)) {
            $stmt->inferredType = $context->vars_in_scope[$keyed_array_var_id];
        }

        if (!isset($stmt->inferredType)) {
            $stmt->inferredType = Type::getMixed();
        } else {
            if ($stmt->inferredType->possibly_undefined && !$context->inside_isset && !$context->inside_unset) {
                if (IssueBuffer::accepts(
                    new PossiblyUndefinedArrayOffset(
                        'Possibly undefined array key ' . $keyed_array_var_id,
                        new CodeLocation($statements_analyzer->getSource(), $stmt)
                    ),
                    $statements_analyzer->getSuppressedIssues()
                )) {
                    // fall through
                }
            }

            $stmt->inferredType->possibly_undefined = false;
        }

        if ($context->inside_isset && $dim_var_id && $new_offset_type && $new_offset_type->getTypes()) {
            $context->vars_in_scope[$dim_var_id] = $new_offset_type;
        }

        if ($keyed_array_var_id && !$context->inside_isset) {
            $context->vars_in_scope[$keyed_array_var_id] = $stmt->inferredType;
            $context->vars_possibly_in_scope[$keyed_array_var_id] = true;

            // reference the variable too
            $context->hasVariable($keyed_array_var_id, $statements_analyzer);
        }

        return null;
    }
744699
public static function analyze(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr $stmt,
        Context $context,
        $array_assignment = false,
        Context $global_context = null
    ) {
        $codebase = $statements_analyzer->getCodebase();

        if ($stmt instanceof PhpParser\Node\Expr\Variable) {
            if (VariableFetchAnalyzer::analyze(
                $statements_analyzer,
                $stmt,
                $context,
                false,
                null,
                $array_assignment
            ) === false
            ) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Assign) {
            $assignment_type = AssignmentAnalyzer::analyze(
                $statements_analyzer,
                $stmt->var,
                $stmt->expr,
                null,
                $context,
                (string)$stmt->getDocComment(),
                $stmt->getLine()
            );

            if ($assignment_type === false) {
                return false;
            }

            $stmt->inferredType = $assignment_type;
        } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp) {
            if (AssignmentAnalyzer::analyzeAssignmentOperation($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\MethodCall) {
            if (MethodCallAnalyzer::analyze($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\StaticCall) {
            if (StaticCallAnalyzer::analyze($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\ConstFetch) {
            ConstFetchAnalyzer::analyze($statements_analyzer, $stmt, $context);
        } elseif ($stmt instanceof PhpParser\Node\Scalar\String_) {
            $stmt->inferredType = Type::getString($stmt->value);
        } elseif ($stmt instanceof PhpParser\Node\Scalar\EncapsedStringPart) {
            // do nothing
        } elseif ($stmt instanceof PhpParser\Node\Scalar\MagicConst) {
            switch (strtolower($stmt->getName())) {
                case '__line__':
                    $stmt->inferredType = Type::getInt();
                    break;

                case '__class__':
                    if (!$context->self) {
                        if (IssueBuffer::accepts(
                            new UndefinedConstant(
                                'Cannot get __class__ outside a class',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }

                        $stmt->inferredType = Type::getClassString();
                        break;
                    }

                    $stmt->inferredType = Type::getLiteralClassString($context->self);
                    break;

                case '__namespace__':
                    $namespace = $statements_analyzer->getNamespace();
                    if ($namespace === null &&
                    IssueBuffer::accepts(
                        new UndefinedConstant(
                            'Cannot get __namespace__ outside a namespace',
                            new CodeLocation($statements_analyzer->getSource(), $stmt)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }

                    $stmt->inferredType = Type::getString($namespace);
                    break;

                case '__file__':
                case '__dir__':
                case '__function__':
                case '__trait__':
                case '__method__':
                    $stmt->inferredType = Type::getString();
                    break;
            }
        } elseif ($stmt instanceof PhpParser\Node\Scalar\LNumber) {
            $stmt->inferredType = Type::getInt(false, $stmt->value);
        } elseif ($stmt instanceof PhpParser\Node\Scalar\DNumber) {
            $stmt->inferredType = Type::getFloat($stmt->value);
        } elseif ($stmt instanceof PhpParser\Node\Expr\UnaryMinus ||
            $stmt instanceof PhpParser\Node\Expr\UnaryPlus
        ) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            if (!isset($stmt->expr->inferredType)) {
                $stmt->inferredType = new Type\Union([new TInt, new TFloat]);
            } elseif ($stmt->expr->inferredType->isMixed()) {
                $stmt->inferredType = Type::getMixed();
            } else {
                $acceptable_types = [];

                foreach ($stmt->expr->inferredType->getTypes() as $type_part) {
                    if ($type_part instanceof TInt || $type_part instanceof TFloat) {
                        if ($type_part instanceof Type\Atomic\TLiteralInt
                            && $stmt instanceof PhpParser\Node\Expr\UnaryMinus
                        ) {
                            $type_part->value = -$type_part->value;
                        } elseif ($type_part instanceof Type\Atomic\TLiteralFloat
                            && $stmt instanceof PhpParser\Node\Expr\UnaryMinus
                        ) {
                            $type_part->value = -$type_part->value;
                        }

                        $acceptable_types[] = $type_part;
                    } elseif ($type_part instanceof TString) {
                        $acceptable_types[] = new TInt;
                        $acceptable_types[] = new TFloat;
                    } else {
                        $acceptable_types[] = new TInt;
                    }
                }

                $stmt->inferredType = new Type\Union($acceptable_types);
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Isset_) {
            self::analyzeIsset($statements_analyzer, $stmt, $context);
            $stmt->inferredType = Type::getBool();
        } elseif ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) {
            if (ConstFetchAnalyzer::analyzeClassConst($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\PropertyFetch) {
            if (PropertyFetchAnalyzer::analyzeInstance($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch) {
            if (PropertyFetchAnalyzer::analyzeStatic($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\BitwiseNot) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            if (!isset($stmt->expr->inferredType)) {
                $stmt->inferredType = new Type\Union([new TInt(), new TString()]);
            } elseif ($stmt->expr->inferredType->isMixed()) {
                $stmt->inferredType = Type::getMixed();
            } else {
                $acceptable_types = [];
                $unacceptable_type = null;
                $has_valid_operand = false;

                foreach ($stmt->expr->inferredType->getTypes() as $type_string => $type_part) {
                    if ($type_part instanceof TInt || $type_part instanceof TString) {
                        if ($type_part instanceof Type\Atomic\TLiteralInt) {
                            $type_part->value = ~$type_part->value;
                        } elseif ($type_part instanceof Type\Atomic\TLiteralString) {
                            $type_part->value = ~$type_part->value;
                        }

                        $acceptable_types[] = $type_part;
                        $has_valid_operand = true;
                    } elseif ($type_part instanceof TFloat) {
                        $type_part = ($type_part instanceof Type\Atomic\TLiteralFloat) ?
                            new Type\Atomic\TLiteralInt(~$type_part->value) :
                            new TInt;

                        $stmt->expr->inferredType->removeType($type_string);
                        $stmt->expr->inferredType->addType($type_part);

                        $acceptable_types[] = $type_part;
                        $has_valid_operand = true;
                    } elseif (!$unacceptable_type) {
                        $unacceptable_type = $type_part;
                    }
                }

                if ($unacceptable_type) {
                    $message = 'Cannot negate a non-numeric non-string type ' . $unacceptable_type;
                    if ($has_valid_operand) {
                        if (IssueBuffer::accepts(
                            new PossiblyInvalidOperand(
                                $message,
                                new CodeLocation($statements_analyzer, $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }
                    } else {
                        if (IssueBuffer::accepts(
                            new InvalidOperand(
                                $message,
                                new CodeLocation($statements_analyzer, $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }
                    }

                    $stmt->inferredType = Type::getMixed();
                } else {
                    $stmt->inferredType = new Type\Union($acceptable_types);
                }
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\BinaryOp) {
            if (BinaryOpAnalyzer::analyze(
                $statements_analyzer,
                $stmt,
                $context
            ) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\PostInc ||
            $stmt instanceof PhpParser\Node\Expr\PostDec ||
            $stmt instanceof PhpParser\Node\Expr\PreInc ||
            $stmt instanceof PhpParser\Node\Expr\PreDec
        ) {
            if (self::analyze($statements_analyzer, $stmt->var, $context) === false) {
                return false;
            }

            if (isset($stmt->var->inferredType)) {
                $return_type = null;

                $fake_right_expr = new PhpParser\Node\Scalar\LNumber(1, $stmt->getAttributes());
                $fake_right_expr->inferredType = Type::getInt();

                BinaryOpAnalyzer::analyzeNonDivArithmeticOp(
                    $statements_analyzer,
                    $stmt->var,
                    $fake_right_expr,
                    $stmt,
                    $return_type,
                    $context
                );

                $stmt->inferredType = clone $stmt->var->inferredType;
                $stmt->inferredType->from_calculation = true;

                foreach ($stmt->inferredType->getTypes() as $atomic_type) {
                    if ($atomic_type instanceof Type\Atomic\TLiteralInt) {
                        $stmt->inferredType->addType(new Type\Atomic\TInt);
                    } elseif ($atomic_type instanceof Type\Atomic\TLiteralFloat) {
                        $stmt->inferredType->addType(new Type\Atomic\TFloat);
                    }
                }

                $var_id = self::getArrayVarId($stmt->var, null);

                if ($var_id && isset($context->vars_in_scope[$var_id])) {
                    $context->vars_in_scope[$var_id] = $stmt->inferredType;

                    if ($context->collect_references && $stmt->var instanceof PhpParser\Node\Expr\Variable) {
                        $location = new CodeLocation($statements_analyzer, $stmt->var);
                        $context->assigned_var_ids[$var_id] = true;
                        $context->possibly_assigned_var_ids[$var_id] = true;
                        $statements_analyzer->registerVariableAssignment(
                            $var_id,
                            $location
                        );
                        $context->unreferenced_vars[$var_id] = [$location->getHash() => $location];
                    }
                }
            } else {
                $stmt->inferredType = Type::getMixed();
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\New_) {
            if (NewAnalyzer::analyze($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Array_) {
            if (ArrayAnalyzer::analyze($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Scalar\Encapsed) {
            if (self::analyzeEncapsulatedString($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\FuncCall) {
            if (FunctionCallAnalyzer::analyze(
                $statements_analyzer,
                $stmt,
                $context
            ) === false
            ) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Ternary) {
            if (TernaryAnalyzer::analyze($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\BooleanNot) {
            if (self::analyzeBooleanNot($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Empty_) {
            self::analyzeEmpty($statements_analyzer, $stmt, $context);
        } elseif ($stmt instanceof PhpParser\Node\Expr\Closure) {
            $closure_analyzer = new ClosureAnalyzer($stmt, $statements_analyzer);

            if (self::analyzeClosureUses($statements_analyzer, $stmt, $context) === false) {
                return false;
            }

            $use_context = new Context($context->self);
            $use_context->collect_references = $codebase->collect_references;

            if (!$statements_analyzer->isStatic()) {
                if ($context->collect_mutations &&
                    $context->self &&
                    $codebase->classExtends(
                        $context->self,
                        (string)$statements_analyzer->getFQCLN()
                    )
                ) {
                    $use_context->vars_in_scope['$this'] = clone $context->vars_in_scope['$this'];
                } elseif ($context->self) {
                    $use_context->vars_in_scope['$this'] = new Type\Union([new TNamedObject($context->self)]);
                }
            }

            foreach ($context->vars_in_scope as $var => $type) {
                if (strpos($var, '$this->') === 0) {
                    $use_context->vars_in_scope[$var] = clone $type;
                }
            }

            foreach ($context->vars_possibly_in_scope as $var => $_) {
                if (strpos($var, '$this->') === 0) {
                    $use_context->vars_possibly_in_scope[$var] = true;
                }
            }

            $byref_uses = [];

            foreach ($stmt->uses as $use) {
                if (!is_string($use->var->name)) {
                    continue;
                }

                $use_var_id = '$' . $use->var->name;

                if ($use->byRef) {
                    $byref_uses[$use_var_id] = true;
                }

                // insert the ref into the current context if passed by ref, as whatever we're passing
                // the closure to could execute it straight away.
                if (!$context->hasVariable($use_var_id, $statements_analyzer) && $use->byRef) {
                    $context->vars_in_scope[$use_var_id] = Type::getMixed();
                }

                $use_context->vars_in_scope[$use_var_id] =
                    $context->hasVariable($use_var_id, $statements_analyzer) && !$use->byRef
                    ? clone $context->vars_in_scope[$use_var_id]
                    : Type::getMixed();

                $use_context->vars_possibly_in_scope[$use_var_id] = true;
            }

            $use_context->calling_method_id = $context->calling_method_id;

            $closure_analyzer->analyze($use_context, $context, false, $byref_uses);

            if (!isset($stmt->inferredType)) {
                $stmt->inferredType = Type::getClosure();
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) {
            if (ArrayFetchAnalyzer::analyze(
                $statements_analyzer,
                $stmt,
                $context
            ) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Int_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            $stmt->inferredType = Type::getInt();
        } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Double) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            $stmt->inferredType = Type::getFloat();
        } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Bool_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            $stmt->inferredType = Type::getBool();
        } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\String_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            if (isset($stmt->expr->inferredType)) {
                self::castStringAttempt($statements_analyzer, $stmt->expr);
            }

            $stmt->inferredType = Type::getString();
        } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Object_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            $stmt->inferredType = new Type\Union([new TNamedObject('stdClass')]);
        } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Array_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            $permissible_atomic_types = [];
            $all_permissible = false;

            if (isset($stmt->expr->inferredType)) {
                $all_permissible = true;

                foreach ($stmt->expr->inferredType->getTypes() as $type) {
                    if ($type instanceof Scalar) {
                        $permissible_atomic_types[] = new ObjectLike([new Type\Union([$type])]);
                    } elseif ($type instanceof TNull) {
                        $permissible_atomic_types[] = new TArray([Type::getEmpty(), Type::getEmpty()]);
                    } elseif ($type instanceof TArray) {
                        $permissible_atomic_types[] = clone $type;
                    } elseif ($type instanceof ObjectLike) {
                        $permissible_atomic_types[] = clone $type;
                    } else {
                        $all_permissible = false;
                        break;
                    }
                }
            }

            if ($all_permissible) {
                $stmt->inferredType = TypeCombination::combineTypes($permissible_atomic_types);
            } else {
                $stmt->inferredType = Type::getArray();
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Cast\Unset_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            $stmt->inferredType = Type::getNull();
        } elseif ($stmt instanceof PhpParser\Node\Expr\Clone_) {
            self::analyzeClone($statements_analyzer, $stmt, $context);
        } elseif ($stmt instanceof PhpParser\Node\Expr\Instanceof_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }

            if ($stmt->class instanceof PhpParser\Node\Expr) {
                if (self::analyze($statements_analyzer, $stmt->class, $context) === false) {
                    return false;
                }
            } elseif (!in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true)
            ) {
                if ($context->check_classes) {
                    $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject(
                        $stmt->class,
                        $statements_analyzer->getAliases()
                    );

                    if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                        $statements_analyzer,
                        $fq_class_name,
                        new CodeLocation($statements_analyzer->getSource(), $stmt->class),
                        $statements_analyzer->getSuppressedIssues(),
                        false
                    ) === false) {
                        return false;
                    }

                    if ($codebase->store_node_types
                        && $fq_class_name
                        && $codebase->classOrInterfaceExists($fq_class_name)
                    ) {
                        $codebase->analyzer->addNodeReference(
                            $statements_analyzer->getFilePath(),
                            $stmt->class,
                            $fq_class_name
                        );
                    }
                }
            }

            $stmt->inferredType = Type::getBool();
        } elseif ($stmt instanceof PhpParser\Node\Expr\Exit_) {
            if ($stmt->expr) {
                if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                    return false;
                }
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Include_) {
            IncludeAnalyzer::analyze($statements_analyzer, $stmt, $context, $global_context);
        } elseif ($stmt instanceof PhpParser\Node\Expr\Eval_) {
            $context->check_classes = false;
            $context->check_variables = false;

            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\AssignRef) {
            if (AssignmentAnalyzer::analyzeAssignmentRef($statements_analyzer, $stmt, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\ErrorSuppress) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }
            $stmt->inferredType = isset($stmt->expr->inferredType) ? $stmt->expr->inferredType : null;
        } elseif ($stmt instanceof PhpParser\Node\Expr\ShellExec) {
            if (IssueBuffer::accepts(
                new ForbiddenCode(
                    'Use of shell_exec',
                    new CodeLocation($statements_analyzer->getSource(), $stmt)
                ),
                $statements_analyzer->getSuppressedIssues()
            )) {
                // continue
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Print_) {
            if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
                return false;
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\Yield_) {
            self::analyzeYield($statements_analyzer, $stmt, $context);
        } elseif ($stmt instanceof PhpParser\Node\Expr\YieldFrom) {
            self::analyzeYieldFrom($statements_analyzer, $stmt, $context);
        } elseif ($stmt instanceof PhpParser\Node\Expr\Error) {
            // do nothing
        } else {
            if (IssueBuffer::accepts(
                new UnrecognizedExpression(
                    'Psalm does not understand ' . get_class($stmt),
                    new CodeLocation($statements_analyzer->getSource(), $stmt)
                ),
                $statements_analyzer->getSuppressedIssues()
            )) {
                return false;
            }
        }

        if (!$context->inside_conditional
            && ($stmt instanceof PhpParser\Node\Expr\BinaryOp
                || $stmt instanceof PhpParser\Node\Expr\Instanceof_
                || $stmt instanceof PhpParser\Node\Expr\Assign
                || $stmt instanceof PhpParser\Node\Expr\BooleanNot
                || $stmt instanceof PhpParser\Node\Expr\Empty_
                || $stmt instanceof PhpParser\Node\Expr\Isset_
                || $stmt instanceof PhpParser\Node\Expr\FuncCall)
        ) {
            AssertionFinder::scrapeAssertions(
                $stmt,
                $context->self,
                $statements_analyzer,
                $codebase
            );
        }

        $plugin_classes = $codebase->config->after_expression_checks;

        if ($plugin_classes) {
            $file_manipulations = [];

            foreach ($plugin_classes as $plugin_fq_class_name) {
                if ($plugin_fq_class_name::afterExpressionAnalysis(
                    $stmt,
                    $context,
                    $statements_analyzer->getSource(),
                    $codebase,
                    $file_manipulations
                ) === false) {
                    return false;
                }
            }

            if ($file_manipulations) {
                /** @psalm-suppress MixedTypeCoercion */
                FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations);
            }
        }

        return null;
    }
476538
public function check(
        StatementsSource $source,
        CodeLocation $code_location,
        array $suppressed_issues,
        array $phantom_classes = [],
        $inferred = true
    ) {
        if ($this->checked) {
            return;
        }

        if ($this instanceof TNamedObject) {
            if (!isset($phantom_classes[strtolower($this->value)]) &&
                ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                    $source,
                    $this->value,
                    $code_location,
                    $suppressed_issues,
                    $inferred
                ) === false
            ) {
                return false;
            }

            if ($this->extra_types) {
                foreach ($this->extra_types as $extra_type) {
                    if ($extra_type instanceof TTemplateParam) {
                        continue;
                    }

                    if (!isset($phantom_classes[strtolower($extra_type->value)]) &&
                        ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                            $source,
                            $extra_type->value,
                            $code_location,
                            $suppressed_issues,
                            $inferred
                        ) === false
                    ) {
                        return false;
                    }
                }
            }
        }

        if ($this instanceof TLiteralClassString) {
            if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                $source,
                $this->value,
                $code_location,
                $suppressed_issues,
                $inferred
            ) === false
            ) {
                return false;
            }
        }

        if ($this instanceof TClassString && $this->as !== 'object' && $this->as !== 'mixed') {
            if ($this->as_type) {
                if ($this->as_type->check(
                    $source,
                    $code_location,
                    $suppressed_issues,
                    $phantom_classes,
                    $inferred
                ) === false) {
                    return false;
                }
            } else {
                if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                    $source,
                    $this->as,
                    $code_location,
                    $suppressed_issues,
                    $inferred
                ) === false
                ) {
                    return false;
                }
            }
        }

        if ($this instanceof TTemplateParam) {
            $this->as->check($source, $code_location, $suppressed_issues, $phantom_classes, $inferred);
        }

        if ($this instanceof TScalarClassConstant) {
            $fq_classlike_name = $this->fq_classlike_name === 'self'
                ? $source->getClassName()
                : $this->fq_classlike_name;

            if (!$fq_classlike_name) {
                return;
            }

            if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                $source,
                $fq_classlike_name,
                $code_location,
                $suppressed_issues,
                $inferred
            ) === false
            ) {
                return false;
            }

            $class_constants = $source->getCodebase()->classlikes->getConstantsForClass(
                $fq_classlike_name,
                \ReflectionProperty::IS_PRIVATE
            );

            if (!isset($class_constants[$this->const_name])) {
                if (IssueBuffer::accepts(
                    new UndefinedConstant(
                        'Constant ' . $fq_classlike_name . '::' . $this->const_name . ' is not defined',
                        $code_location
                    ),
                    $source->getSuppressedIssues()
                )) {
                    // fall through
                }
            }
        }

        if ($this instanceof TResource && !$this->from_docblock) {
            if (IssueBuffer::accepts(
                new ReservedWord(
                    '\'resource\' is a reserved word',
                    $code_location,
                    'resource'
                ),
                $source->getSuppressedIssues()
            )) {
                // fall through
            }
        }

        if ($this instanceof Type\Atomic\Fn
            || $this instanceof Type\Atomic\TCallable
        ) {
            if ($this->params) {
                foreach ($this->params as $param) {
                    if ($param->type) {
                        $param->type->check(
                            $source,
                            $code_location,
                            $suppressed_issues,
                            $phantom_classes,
                            $inferred
                        );
                    }
                }
            }

            if ($this->return_type) {
                $this->return_type->check(
                    $source,
                    $code_location,
                    $suppressed_issues,
                    $phantom_classes,
                    $inferred
                );
            }
        }

        if ($this instanceof Type\Atomic\TArray
            || $this instanceof Type\Atomic\TGenericObject
            || $this instanceof Type\Atomic\TIterable
        ) {
            $codebase = $source->getCodebase();

            if ($this instanceof Type\Atomic\TGenericObject) {
                try {
                    $class_storage = $codebase->classlike_storage_provider->get($this->value);
                } catch (\InvalidArgumentException $e) {
                    return;
                }

                $expected_type_params = $class_storage->template_types ?: [];
            } else {
                $expected_type_params = [
                    'TKey' => [
                        '' =>  [Type::getMixed(), null],
                    ],
                    'TValue' => [
                        '' =>  [Type::getMixed(), null],
                    ]
                ];
            }

            $template_type_count = count($expected_type_params);
            $template_param_count = count($this->type_params);

            if ($template_type_count > $template_param_count) {
                if (IssueBuffer::accepts(
                    new MissingTemplateParam(
                        $this->value . ' has missing template params, expecting '
                            . $template_type_count,
                        $code_location
                    ),
                    $suppressed_issues
                )) {
                    // fall through
                }
            } elseif ($template_type_count < $template_param_count) {
                if (IssueBuffer::accepts(
                    new TooManyTemplateParams(
                        $this->value . ' has too many template params, expecting '
                            . $template_type_count,
                        $code_location
                    ),
                    $suppressed_issues
                )) {
                    // fall through
                }
            }

            foreach ($this->type_params as $i => $type_param) {
                if ($type_param->check(
                    $source,
                    $code_location,
                    $suppressed_issues,
                    $phantom_classes,
                    $inferred
                ) === false) {
                    return false;
                }

                if (isset(array_values($expected_type_params)[$i])) {
                    $expected_type_param = reset(array_values($expected_type_params)[$i])[0];
                    $template_name = array_keys($expected_type_params)[$i];

                    $type_param = ExpressionAnalyzer::fleshOutType(
                        $codebase,
                        $type_param,
                        $source->getFQCLN(),
                        $source->getFQCLN()
                    );

                    if (!TypeAnalyzer::isContainedBy($codebase, $type_param, $expected_type_param)) {
                        if (IssueBuffer::accepts(
                            new InvalidTemplateParam(
                                'Extended template param ' . $template_name . ' expects type '
                                    . $expected_type_param->getId()
                                    . ', type ' . $type_param->getId() . ' given',
                                $code_location
                            ),
                            $suppressed_issues
                        )) {
                            // fall through
                        }
                    }
                }
            }
        }

        $this->checked = true;
    }
1359556
public static function analyzeStatic(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr\StaticPropertyFetch $stmt,
        Context $context
    ) {
        if ($stmt->class instanceof PhpParser\Node\Expr\Variable ||
            $stmt->class instanceof PhpParser\Node\Expr\ArrayDimFetch
        ) {
            // @todo check this
            return null;
        }

        $fq_class_name = null;

        $codebase = $statements_analyzer->getCodebase();

        if ($stmt->class instanceof PhpParser\Node\Name) {
            if (count($stmt->class->parts) === 1
                && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true)
            ) {
                if ($stmt->class->parts[0] === 'parent') {
                    $fq_class_name = $statements_analyzer->getParentFQCLN();

                    if ($fq_class_name === null) {
                        if (IssueBuffer::accepts(
                            new ParentNotFound(
                                'Cannot check property fetch on parent as this class does not extend another',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            return false;
                        }

                        return;
                    }
                } else {
                    $fq_class_name = (string)$context->self;
                }

                if ($context->isPhantomClass($fq_class_name)) {
                    return null;
                }
            } else {
                $aliases = $statements_analyzer->getAliases();

                if ($context->calling_method_id
                    && !$stmt->class instanceof PhpParser\Node\Name\FullyQualified
                ) {
                    $codebase->file_reference_provider->addMethodReferenceToClassMember(
                        $context->calling_method_id,
                        'use:' . $stmt->class->parts[0] . ':' . \md5($statements_analyzer->getFilePath())
                    );
                }

                $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject(
                    $stmt->class,
                    $aliases
                );

                if ($context->isPhantomClass($fq_class_name)) {
                    return null;
                }

                if ($context->check_classes) {
                    if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                        $statements_analyzer,
                        $fq_class_name,
                        new CodeLocation($statements_analyzer->getSource(), $stmt->class),
                        $statements_analyzer->getSuppressedIssues(),
                        false
                    ) !== true) {
                        return false;
                    }
                }
            }

            $stmt->class->inferredType = $fq_class_name ? new Type\Union([new TNamedObject($fq_class_name)]) : null;
        }

        if ($stmt->name instanceof PhpParser\Node\VarLikeIdentifier) {
            $prop_name = $stmt->name->name;
        } elseif (isset($stmt->name->inferredType)
            && $stmt->name->inferredType->isSingleStringLiteral()
        ) {
            $prop_name = $stmt->name->inferredType->getSingleStringLiteral()->value;
        } else {
            $prop_name = null;
        }

        if (!$prop_name) {
            if ($fq_class_name) {
                $codebase->analyzer->addMixedMemberName(
                    strtolower($fq_class_name) . '::$',
                    $context->calling_method_id ?: $statements_analyzer->getFileName()
                );
            }

            return null;
        }

        if (!$fq_class_name
            || !$context->check_classes
            || !$context->check_variables
            || ExpressionAnalyzer::isMock($fq_class_name)
        ) {
            return null;
        }

        $var_id = ExpressionAnalyzer::getVarId(
            $stmt,
            $context->self ?: $statements_analyzer->getFQCLN(),
            $statements_analyzer
        );

        $property_id = $fq_class_name . '::$' . $prop_name;

        if ($codebase->store_node_types) {
            $codebase->analyzer->addNodeReference(
                $statements_analyzer->getFilePath(),
                $stmt->name,
                $property_id
            );
        }

        if ($var_id && $context->hasVariable($var_id, $statements_analyzer)) {
            // we don't need to check anything
            $stmt->inferredType = $context->vars_in_scope[$var_id];

            if ($context->collect_references) {
                // log the appearance
                $codebase->properties->propertyExists(
                    $property_id,
                    false,
                    $statements_analyzer,
                    $context,
                    new CodeLocation($statements_analyzer->getSource(), $stmt)
                );
            }

            if ($codebase->store_node_types
                && (!$context->collect_initializations
                    && !$context->collect_mutations)
                && isset($stmt->inferredType)
            ) {
                $codebase->analyzer->addNodeType(
                    $statements_analyzer->getFilePath(),
                    $stmt->name,
                    (string) $stmt->inferredType
                );
            }

            return null;
        }

        if (!$codebase->properties->propertyExists(
            $property_id,
            false,
            $statements_analyzer,
            $context,
            $context->collect_references ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null
        )
        ) {
            if (IssueBuffer::accepts(
                new UndefinedPropertyFetch(
                    'Static property ' . $property_id . ' is not defined',
                    new CodeLocation($statements_analyzer->getSource(), $stmt),
                    $property_id
                ),
                $statements_analyzer->getSuppressedIssues()
            )) {
                // fall through
            }

            return;
        }

        if (ClassLikeAnalyzer::checkPropertyVisibility(
            $property_id,
            $context,
            $statements_analyzer,
            new CodeLocation($statements_analyzer->getSource(), $stmt),
            $statements_analyzer->getSuppressedIssues()
        ) === false) {
            return false;
        }

        $declaring_property_class = $codebase->properties->getDeclaringClassForProperty(
            $fq_class_name . '::$' . $prop_name,
            true
        );

        $class_storage = $codebase->classlike_storage_provider->get((string)$declaring_property_class);
        $property = $class_storage->properties[$prop_name];

        if ($var_id) {
            if ($property->type) {
                $context->vars_in_scope[$var_id] = ExpressionAnalyzer::fleshOutType(
                    $codebase,
                    clone $property->type,
                    $declaring_property_class,
                    $declaring_property_class
                );
            } else {
                $context->vars_in_scope[$var_id] = Type::getMixed();
            }

            $stmt->inferredType = clone $context->vars_in_scope[$var_id];

            if ($codebase->store_node_types
                && (!$context->collect_initializations
                    && !$context->collect_mutations)
            ) {
                $codebase->analyzer->addNodeType(
                    $statements_analyzer->getFilePath(),
                    $stmt->name,
                    (string) $stmt->inferredType
                );
            }
        } else {
            $stmt->inferredType = Type::getMixed();
        }

        return null;
    }
1150004
public static function afterStatementAnalysis(
        PhpParser\Node\Stmt $stmt,
        Context $context,
        StatementsSource $statements_source,
        Codebase $codebase,
        array &$file_replacements = []
    ) {
        if ($stmt instanceof PhpParser\Node\Stmt\Echo_) {
            foreach ($stmt->exprs as $expr) {
                if (!isset($expr->inferredType) || $expr->inferredType->hasMixed()) {
                    if (IssueBuffer::accepts(
                        new ArgumentTypeCoercion(
                            'Echo requires an unescaped string, ' . $expr->inferredType . ' provided',
                            new CodeLocation($statements_source, $expr),
                            'echo'
                        ),
                        $statements_source->getSuppressedIssues()
                    )) {
                        // keep soldiering on
                    }

                    continue;
                }

                $types = $expr->inferredType->getTypes();

                foreach ($types as $type) {
                    if ($type instanceof \Psalm\Type\Atomic\TString
                        && !$type instanceof \Psalm\Type\Atomic\TLiteralString
                        && !$type instanceof \Psalm\Type\Atomic\THtmlEscapedString
                    ) {
                        if (IssueBuffer::accepts(
                            new ArgumentTypeCoercion(
                                'Echo requires an unescaped string, ' . $expr->inferredType . ' provided',
                                new CodeLocation($statements_source, $expr),
                                'echo'
                            ),
                            $statements_source->getSuppressedIssues()
                        )) {
                            // keep soldiering on
                        }
                    }
                }
            }
        }
    }
57317
public static function afterExpressionAnalysis(
        PhpParser\Node\Expr $expr,
        Context $context,
        StatementsSource $statements_source,
        Codebase $codebase,
        array &$file_replacements = []
    ) {
        if ($expr instanceof PhpParser\Node\Expr\Assign
            && isset($expr->inferredType)
            && $expr->inferredType->hasFloat()
        ) {
            if (\Psalm\IssueBuffer::accepts(
                new NoFloatAssignment(
                    'Don’t assign to floats',
                    new CodeLocation($statements_source, $expr)
                ),
                $statements_source->getSuppressedIssues()
            )) {
                // fall through
            }
        }
    }
940517
public static function analyzeAssignmentOperation(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr\AssignOp $stmt,
        Context $context
    ) {
        if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->var, $context) === false) {
            return false;
        }

        if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->expr, $context) === false) {
            return false;
        }

        $array_var_id = ExpressionAnalyzer::getArrayVarId(
            $stmt->var,
            $statements_analyzer->getFQCLN(),
            $statements_analyzer
        );

        if ($array_var_id && $context->collect_references && $stmt->var instanceof PhpParser\Node\Expr\Variable) {
            $location = new CodeLocation($statements_analyzer, $stmt->var);
            $context->assigned_var_ids[$array_var_id] = true;
            $context->possibly_assigned_var_ids[$array_var_id] = true;
            $statements_analyzer->registerVariableAssignment(
                $array_var_id,
                $location
            );
            $context->unreferenced_vars[$array_var_id] = [$location->getHash() => $location];
        }

        $var_type = isset($stmt->var->inferredType) ? clone $stmt->var->inferredType : null;
        $expr_type = isset($stmt->expr->inferredType) ? $stmt->expr->inferredType : null;

        if ($stmt instanceof PhpParser\Node\Expr\AssignOp\Plus
            || $stmt instanceof PhpParser\Node\Expr\AssignOp\Minus
            || $stmt instanceof PhpParser\Node\Expr\AssignOp\Mod
            || $stmt instanceof PhpParser\Node\Expr\AssignOp\Mul
            || $stmt instanceof PhpParser\Node\Expr\AssignOp\Pow
        ) {
            BinaryOpAnalyzer::analyzeNonDivArithmeticOp(
                $statements_analyzer,
                $stmt->var,
                $stmt->expr,
                $stmt,
                $result_type,
                $context
            );

            if ($stmt->var instanceof PhpParser\Node\Expr\ArrayDimFetch) {
                ArrayAssignmentAnalyzer::analyze(
                    $statements_analyzer,
                    $stmt->var,
                    $context,
                    $stmt->expr,
                    $result_type ?: Type::getMixed($context->inside_loop)
                );
            } elseif ($result_type && $array_var_id) {
                $context->vars_in_scope[$array_var_id] = $result_type;
                $stmt->inferredType = clone $context->vars_in_scope[$array_var_id];
            }
        } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Div
            && $var_type
            && $expr_type
            && $var_type->hasDefinitelyNumericType()
            && $expr_type->hasDefinitelyNumericType()
            && $array_var_id
        ) {
            $context->vars_in_scope[$array_var_id] = Type::combineUnionTypes(Type::getFloat(), Type::getInt());
            $stmt->inferredType = clone $context->vars_in_scope[$array_var_id];
        } elseif ($stmt instanceof PhpParser\Node\Expr\AssignOp\Concat) {
            BinaryOpAnalyzer::analyzeConcatOp(
                $statements_analyzer,
                $stmt->var,
                $stmt->expr,
                $context,
                $result_type
            );

            if ($result_type && $array_var_id) {
                $context->vars_in_scope[$array_var_id] = $result_type;
                $stmt->inferredType = clone $context->vars_in_scope[$array_var_id];
            }
        } elseif (isset($stmt->var->inferredType)
            && isset($stmt->expr->inferredType)
            && ($stmt->var->inferredType->hasInt() || $stmt->expr->inferredType->hasInt())
            && ($stmt instanceof PhpParser\Node\Expr\AssignOp\BitwiseOr
                || $stmt instanceof PhpParser\Node\Expr\AssignOp\BitwiseXor
                || $stmt instanceof PhpParser\Node\Expr\AssignOp\BitwiseAnd
                || $stmt instanceof PhpParser\Node\Expr\AssignOp\ShiftLeft
                || $stmt instanceof PhpParser\Node\Expr\AssignOp\ShiftRight
            )
        ) {
            BinaryOpAnalyzer::analyzeNonDivArithmeticOp(
                $statements_analyzer,
                $stmt->var,
                $stmt->expr,
                $stmt,
                $result_type,
                $context
            );

            if ($result_type && $array_var_id) {
                $context->vars_in_scope[$array_var_id] = $result_type;
                $stmt->inferredType = clone $context->vars_in_scope[$array_var_id];
            }
        }

        return null;
    }
1250085
private function analyzeStatic(PhpParser\Node\Stmt\Static_ $stmt, Context $context)
    {
        $codebase = $this->getCodebase();

        foreach ($stmt->vars as $var) {
            if (!is_string($var->var->name)) {
                continue;
            }

            $var_id = '$' . $var->var->name;

            $doc_comment = $stmt->getDocComment();

            $comment_type = null;

            if ($doc_comment) {
                $var_comments = [];

                try {
                    $var_comments = CommentAnalyzer::getTypeFromComment(
                        (string) $doc_comment,
                        $this->getSource(),
                        $this->getAliases(),
                        $this->getTemplateTypeMap()
                    );
                } catch (\Psalm\Exception\IncorrectDocblockException $e) {
                    if (IssueBuffer::accepts(
                        new \Psalm\Issue\MissingDocblockType(
                            (string)$e->getMessage(),
                            new CodeLocation($this, $var)
                        )
                    )) {
                        // fall through
                    }
                } catch (DocblockParseException $e) {
                    if (IssueBuffer::accepts(
                        new InvalidDocblock(
                            (string)$e->getMessage(),
                            new CodeLocation($this->getSource(), $var)
                        )
                    )) {
                        // fall through
                    }
                }

                foreach ($var_comments as $var_comment) {
                    try {
                        $var_comment_type = ExpressionAnalyzer::fleshOutType(
                            $codebase,
                            $var_comment->type,
                            $context->self,
                            $context->self
                        );

                        $var_comment_type->setFromDocblock();

                        $var_comment_type->check(
                            $this,
                            new CodeLocation($this->getSource(), $var),
                            $this->getSuppressedIssues()
                        );

                        if (!$var_comment->var_id || $var_comment->var_id === $var_id) {
                            $comment_type = $var_comment_type;
                            continue;
                        }

                        $context->vars_in_scope[$var_comment->var_id] = $var_comment_type;
                    } catch (\UnexpectedValueException $e) {
                        if (IssueBuffer::accepts(
                            new InvalidDocblock(
                                (string)$e->getMessage(),
                                new CodeLocation($this, $var)
                            )
                        )) {
                            // fall through
                        }
                    }
                }

                if ($comment_type) {
                    $context->byref_constraints[$var_id] = new \Psalm\Internal\ReferenceConstraint($comment_type);
                }
            }

            if ($var->default) {
                if (ExpressionAnalyzer::analyze($this, $var->default, $context) === false) {
                    return false;
                }

                if ($comment_type
                    && isset($var->default->inferredType)
                    && !TypeAnalyzer::isContainedBy(
                        $codebase,
                        $var->default->inferredType,
                        $comment_type
                    )
                ) {
                    if (IssueBuffer::accepts(
                        new \Psalm\Issue\ReferenceConstraintViolation(
                            $var_id . ' of type ' . $comment_type->getId() . ' cannot be assigned type '
                                . $var->default->inferredType->getId(),
                            new CodeLocation($this, $var)
                        )
                    )) {
                        // fall through
                    }
                }
            }

            if ($context->check_variables) {
                $context->vars_in_scope[$var_id] = $comment_type ? clone $comment_type : Type::getMixed();
                $context->vars_possibly_in_scope[$var_id] = true;
                $context->assigned_var_ids[$var_id] = true;
                $this->byref_uses[$var_id] = true;

                $location = new CodeLocation($this, $var);

                if ($context->collect_references) {
                    $context->unreferenced_vars[$var_id] = [$location->getHash() => $location];
                }

                $this->registerVariable(
                    $var_id,
                    $location,
                    $context->branch_point
                );
            }
        }

        return null;
    }
1045945
private static function checkArrayFunctionClosureType(
        StatementsAnalyzer $statements_analyzer,
        $method_id,
        Type\Atomic $closure_type,
        PhpParser\Node\Arg $closure_arg,
        $min_closure_param_count,
        $max_closure_param_count,
        array $array_arg_types,
        bool $check_functions
    ) {
        $codebase = $statements_analyzer->getCodebase();

        if (!$closure_type instanceof Type\Atomic\Fn) {
            if (!$closure_arg->value instanceof PhpParser\Node\Scalar\String_
                && !$closure_arg->value instanceof PhpParser\Node\Expr\Array_
                && !$closure_arg->value instanceof PhpParser\Node\Expr\BinaryOp\Concat
            ) {
                return;
            }

            $function_ids = self::getFunctionIdsFromCallableArg(
                $statements_analyzer,
                $closure_arg->value
            );

            $closure_types = [];

            foreach ($function_ids as $function_id) {
                $function_id = strtolower($function_id);

                if (strpos($function_id, '::') !== false) {
                    $function_id_parts = explode('&', $function_id);

                    foreach ($function_id_parts as $function_id_part) {
                        list($callable_fq_class_name, $method_name) = explode('::', $function_id_part);

                        switch ($callable_fq_class_name) {
                            case 'self':
                            case 'static':
                            case 'parent':
                                $container_class = $statements_analyzer->getFQCLN();

                                if ($callable_fq_class_name === 'parent') {
                                    $container_class = $statements_analyzer->getParentFQCLN();
                                }

                                if (!$container_class) {
                                    continue 2;
                                }

                                $callable_fq_class_name = $container_class;
                        }

                        if (!$codebase->classOrInterfaceExists($callable_fq_class_name)) {
                            return;
                        }

                        $function_id_part = $callable_fq_class_name . '::' . $method_name;

                        try {
                            $method_storage = $codebase->methods->getStorage($function_id_part);
                        } catch (\UnexpectedValueException $e) {
                            // the method may not exist, but we're suppressing that issue
                            continue;
                        }

                        $closure_types[] = new Type\Atomic\Fn(
                            'Closure',
                            $method_storage->params,
                            $method_storage->return_type ?: Type::getMixed()
                        );
                    }
                } else {
                    if (!$check_functions) {
                        continue;
                    }

                    if (!$codebase->functions->functionExists($statements_analyzer, $function_id)) {
                        continue;
                    }

                    $function_storage = $codebase->functions->getStorage(
                        $statements_analyzer,
                        $function_id
                    );

                    if (CallMap::inCallMap($function_id)) {
                        $callmap_params_options = CallMap::getParamsFromCallMap($function_id);

                        if ($callmap_params_options === null) {
                            throw new \UnexpectedValueException('This should not happen');
                        }

                        $passing_callmap_params_options = [];

                        foreach ($callmap_params_options as $callmap_params_option) {
                            $required_param_count = 0;

                            foreach ($callmap_params_option as $i => $param) {
                                if (!$param->is_optional && !$param->is_variadic) {
                                    $required_param_count = $i + 1;
                                }
                            }

                            if ($required_param_count <= $max_closure_param_count) {
                                $passing_callmap_params_options[] = $callmap_params_option;
                            }
                        }

                        if ($passing_callmap_params_options) {
                            foreach ($passing_callmap_params_options as $passing_callmap_params_option) {
                                $closure_types[] = new Type\Atomic\Fn(
                                    'Closure',
                                    $passing_callmap_params_option,
                                    $function_storage->return_type ?: Type::getMixed()
                                );
                            }
                        } else {
                            $closure_types[] = new Type\Atomic\Fn(
                                'Closure',
                                $callmap_params_options[0],
                                $function_storage->return_type ?: Type::getMixed()
                            );
                        }
                    } else {
                        $closure_types[] = new Type\Atomic\Fn(
                            'Closure',
                            $function_storage->params,
                            $function_storage->return_type ?: Type::getMixed()
                        );
                    }
                }
            }
        } else {
            $closure_types = [$closure_type];
        }

        foreach ($closure_types as $closure_type) {
            if ($closure_type->params === null) {
                continue;
            }

            if (self::checkArrayFunctionClosureTypeArgs(
                $statements_analyzer,
                $method_id,
                $closure_type,
                $closure_arg,
                $min_closure_param_count,
                $max_closure_param_count,
                $array_arg_types
            ) === false) {
                return false;
            }
        }
    }
1279235
public function collectAnalyzableClassLike(PhpParser\Node\Stmt\ClassLike $stmt)
    {
        if (!$stmt->name) {
            throw new \UnexpectedValueException('Did not expect anonymous class here');
        }

        $fq_class_name = Type::getFQCLNFromString($stmt->name->name, $this->getAliases());

        if ($stmt instanceof PhpParser\Node\Stmt\Class_) {
            $this->source->addNamespacedClassAnalyzer(
                $fq_class_name,
                new ClassAnalyzer($stmt, $this, $fq_class_name)
            );
        } elseif ($stmt instanceof PhpParser\Node\Stmt\Interface_) {
            $this->source->addNamespacedInterfaceAnalyzer(
                $fq_class_name,
                new InterfaceAnalyzer($stmt, $this, $fq_class_name)
            );
        }
    }
425513
void analyze(JCStatement statement, Env<AttrContext> env) {
        AnalysisContext context = new AnalysisContext();
        StatementScanner statementScanner = new StatementScanner(context);
        statementScanner.scan(statement);

        if (!context.treesToAnalyzer.isEmpty()) {

            //add a block to hoist potential dangling variable declarations
            JCBlock fakeBlock = make.Block(SYNTHETIC, List.of(statement));

            TreeMapper treeMapper = new TreeMapper(context);
            //TODO: to further refine the analysis, try all rewriting combinations
            deferredAttr.attribSpeculative(fakeBlock, env, attr.statInfo, treeMapper,
                    t -> new AnalyzeDeferredDiagHandler(context),
                    argumentAttr.withLocalCacheContext());
            context.treeMap.entrySet().forEach(e -> {
                context.treesToAnalyzer.get(e.getKey())
                        .process(e.getKey(), e.getValue(), context.errors.nonEmpty());
            });
        }
    }
1173361
public static function analyze(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr\New_ $stmt,
        Context $context
    ) {
        $fq_class_name = null;

        $codebase = $statements_analyzer->getCodebase();
        $config = $codebase->config;

        $can_extend = false;

        if ($stmt->class instanceof PhpParser\Node\Name) {
            if (!in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true)) {
                $aliases = $statements_analyzer->getAliases();

                if ($context->calling_method_id
                    && !$stmt->class instanceof PhpParser\Node\Name\FullyQualified
                ) {
                    $codebase->file_reference_provider->addMethodReferenceToClassMember(
                        $context->calling_method_id,
                        'use:' . $stmt->class->parts[0] . ':' . \md5($statements_analyzer->getFilePath())
                    );
                }

                $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject(
                    $stmt->class,
                    $aliases
                );

                $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name);
            } else {
                switch ($stmt->class->parts[0]) {
                    case 'self':
                        $fq_class_name = $context->self;
                        break;

                    case 'parent':
                        $fq_class_name = $context->parent;
                        break;

                    case 'static':
                        // @todo maybe we can do better here
                        $fq_class_name = $context->self;
                        $can_extend = true;
                        break;
                }
            }

            if ($codebase->store_node_types && $fq_class_name) {
                $codebase->analyzer->addNodeReference(
                    $statements_analyzer->getFilePath(),
                    $stmt->class,
                    $fq_class_name
                );
            }
        } elseif ($stmt->class instanceof PhpParser\Node\Stmt\Class_) {
            $statements_analyzer->analyze([$stmt->class], $context);
            $fq_class_name = ClassAnalyzer::getAnonymousClassName($stmt->class, $statements_analyzer->getFilePath());
        } else {
            ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context);

            if (isset($stmt->class->inferredType)) {
                $has_single_class = $stmt->class->inferredType->isSingleStringLiteral();

                if ($has_single_class) {
                    $fq_class_name = $stmt->class->inferredType->getSingleStringLiteral()->value;
                } else {
                    $generic_params = null;

                    if (self::checkMethodArgs(
                        null,
                        $stmt->args,
                        $generic_params,
                        $context,
                        new CodeLocation($statements_analyzer->getSource(), $stmt),
                        $statements_analyzer
                    ) === false) {
                        return false;
                    }
                }

                $new_type = null;

                foreach ($stmt->class->inferredType->getTypes() as $lhs_type_part) {
                    if ($lhs_type_part instanceof Type\Atomic\TTemplateParamClass) {
                        if (!isset($stmt->inferredType)) {
                            $new_type_part = new Type\Atomic\TTemplateParam(
                                $lhs_type_part->param_name,
                                $lhs_type_part->as_type
                                    ? new Type\Union([$lhs_type_part->as_type])
                                    : Type::parseString($lhs_type_part->as)
                            );

                            if ($new_type) {
                                $new_type = Type::combineUnionTypes(
                                    $new_type,
                                    new Type\Union([$new_type_part])
                                );
                            } else {
                                $new_type = new Type\Union([$new_type_part]);
                            }
                        }

                        continue;
                    }

                    if ($lhs_type_part instanceof Type\Atomic\TLiteralClassString
                        || $lhs_type_part instanceof Type\Atomic\TClassString
                    ) {
                        if (!isset($stmt->inferredType)) {
                            $class_name = $lhs_type_part instanceof Type\Atomic\TClassString
                                ? $lhs_type_part->as
                                : $lhs_type_part->value;

                            if ($lhs_type_part instanceof Type\Atomic\TClassString) {
                                $can_extend = true;
                            }

                            if ($class_name === 'object') {
                                if (IssueBuffer::accepts(
                                    new MixedMethodCall(
                                        'Cannot call constructor on an unknown class',
                                        new CodeLocation($statements_analyzer->getSource(), $stmt)
                                    ),
                                    $statements_analyzer->getSuppressedIssues()
                                )) {
                                    // fall through
                                }
                            }

                            if ($new_type) {
                                $new_type = Type::combineUnionTypes(
                                    $new_type,
                                    Type::parseString($class_name)
                                );
                            } else {
                                $new_type = Type::parseString($class_name);
                            }
                        }

                        continue;
                    }

                    if ($lhs_type_part instanceof Type\Atomic\TString) {
                        if ($config->allow_string_standin_for_class
                            && !$lhs_type_part instanceof Type\Atomic\TNumericString
                        ) {
                            // do nothing
                        } elseif (IssueBuffer::accepts(
                            new InvalidStringClass(
                                'String cannot be used as a class',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }
                    } elseif ($lhs_type_part instanceof Type\Atomic\TMixed
                        || $lhs_type_part instanceof Type\Atomic\TTemplateParam
                    ) {
                        if (IssueBuffer::accepts(
                            new MixedMethodCall(
                                'Cannot call constructor on an unknown class',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }
                    } elseif ($lhs_type_part instanceof Type\Atomic\TFalse
                        && $stmt->class->inferredType->ignore_falsable_issues
                    ) {
                        // do nothing
                    } elseif ($lhs_type_part instanceof Type\Atomic\TNull
                        && $stmt->class->inferredType->ignore_nullable_issues
                    ) {
                        // do nothing
                    } elseif (IssueBuffer::accepts(
                        new UndefinedClass(
                            'Type ' . $lhs_type_part . ' cannot be called as a class',
                            new CodeLocation($statements_analyzer->getSource(), $stmt),
                            (string)$lhs_type_part
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }

                    if ($new_type) {
                        $new_type = Type::combineUnionTypes(
                            $new_type,
                            Type::getObject()
                        );
                    } else {
                        $new_type = Type::getObject();
                    }
                }

                if (!$has_single_class) {
                    if ($new_type) {
                        $stmt->inferredType = $new_type;
                    }

                    return null;
                }
            } else {
                return null;
            }
        }

        if ($fq_class_name) {
            if ($context->check_classes) {
                if ($context->isPhantomClass($fq_class_name)) {
                    return null;
                }

                if (ClassLikeAnalyzer::checkFullyQualifiedClassLikeName(
                    $statements_analyzer,
                    $fq_class_name,
                    new CodeLocation($statements_analyzer->getSource(), $stmt->class),
                    $statements_analyzer->getSuppressedIssues(),
                    false
                ) === false) {
                    return false;
                }

                if ($codebase->interfaceExists($fq_class_name)) {
                    if (IssueBuffer::accepts(
                        new InterfaceInstantiation(
                            'Interface ' . $fq_class_name . ' cannot be instantiated',
                            new CodeLocation($statements_analyzer->getSource(), $stmt->class)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        return false;
                    }

                    return null;
                }
            }

            $stmt->inferredType = new Type\Union([new TNamedObject($fq_class_name)]);

            if (strtolower($fq_class_name) !== 'stdclass' &&
                $context->check_classes &&
                $codebase->classlikes->classExists($fq_class_name)
            ) {
                $storage = $codebase->classlike_storage_provider->get($fq_class_name);

                // if we're not calling this constructor via new static()
                if ($storage->abstract && !$can_extend) {
                    if (IssueBuffer::accepts(
                        new AbstractInstantiation(
                            'Unable to instantiate a abstract class ' . $fq_class_name,
                            new CodeLocation($statements_analyzer->getSource(), $stmt)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        return false;
                    }
                }

                if ($storage->deprecated) {
                    if (IssueBuffer::accepts(
                        new DeprecatedClass(
                            $fq_class_name . ' is marked deprecated',
                            new CodeLocation($statements_analyzer->getSource(), $stmt)
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }

                if ($storage->internal && $context->self) {
                    $self_root = preg_replace('/^([^\\\]+).*/', '$1', $context->self);
                    $declaring_root = preg_replace('/^([^\\\]+).*/', '$1', $fq_class_name);

                    if (strtolower($self_root) !== strtolower($declaring_root)) {
                        if (IssueBuffer::accepts(
                            new InternalClass(
                                $fq_class_name . ' is marked internal',
                                new CodeLocation($statements_analyzer->getSource(), $stmt)
                            ),
                            $statements_analyzer->getSuppressedIssues()
                        )) {
                            // fall through
                        }
                    }
                }

                if ($codebase->methods->methodExists(
                    $fq_class_name . '::__construct',
                    $context->calling_method_id,
                    $context->collect_references ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null,
                    null,
                    $statements_analyzer->getFilePath()
                )) {
                    $method_id = $fq_class_name . '::__construct';

                    if (self::checkMethodArgs(
                        $method_id,
                        $stmt->args,
                        $found_generic_params,
                        $context,
                        new CodeLocation($statements_analyzer->getSource(), $stmt),
                        $statements_analyzer
                    ) === false) {
                        return false;
                    }

                    if (MethodAnalyzer::checkMethodVisibility(
                        $method_id,
                        $context,
                        $statements_analyzer->getSource(),
                        new CodeLocation($statements_analyzer->getSource(), $stmt),
                        $statements_analyzer->getSuppressedIssues()
                    ) === false) {
                        return false;
                    }

                    $generic_param_types = null;

                    if ($storage->template_types) {
                        $declaring_method_id = $codebase->methods->getDeclaringMethodId($method_id);

                        $declaring_fq_class_name = $declaring_method_id
                            ? explode('::', $declaring_method_id)[0]
                            : $fq_class_name;

                        foreach ($storage->template_types as $template_name => $base_type) {
                            if (isset($found_generic_params[$template_name][$fq_class_name])) {
                                $generic_param_types[] = $found_generic_params[$template_name][$fq_class_name][0];
                            } elseif ($storage->template_type_extends && $found_generic_params) {
                                $generic_param_types[] = self::getGenericParamForOffset(
                                    $declaring_fq_class_name,
                                    $template_name,
                                    $storage->template_type_extends,
                                    $found_generic_params
                                );
                            } else {
                                $generic_param_types[] = array_values($base_type)[0][0];
                            }
                        }
                    }

                    if ($generic_param_types) {
                        $stmt->inferredType = new Type\Union([
                            new Type\Atomic\TGenericObject(
                                $fq_class_name,
                                $generic_param_types
                            ),
                        ]);
                    }
                } elseif ($stmt->args) {
                    if (IssueBuffer::accepts(
                        new TooManyArguments(
                            'Class ' . $fq_class_name . ' has no __construct, but arguments were passed',
                            new CodeLocation($statements_analyzer->getSource(), $stmt),
                            $fq_class_name . '::__construct'
                        ),
                        $statements_analyzer->getSuppressedIssues()
                    )) {
                        // fall through
                    }
                }
            }
        }

        if (!$config->remember_property_assignments_after_call && !$context->collect_initializations) {
            $context->removeAllObjectVars();
        }

        return null;
    }
717368
protected static function analyzeEmpty(
        StatementsAnalyzer $statements_analyzer,
        PhpParser\Node\Expr\Empty_ $stmt,
        Context $context
    ) {
        self::analyzeIssetVar($statements_analyzer, $stmt->expr, $context);
        $stmt->inferredType = Type::getBool();
    }