/* Calculate whether an assertion is a standard GObject type check. * .e.g. NSPACE_IS_OBJ(x). * * This is complicated by the fact that type checking is done by macros, which * expand to something like: * (((__extension__ ({ * GTypeInstance *__inst = (GTypeInstance *)((x)); * GType __t = ((nspace_obj_get_type())); * gboolean __r; * if (!__inst) * __r = (0); * else if (__inst->g_class && __inst->g_class->g_type == __t) * __r = (!(0)); * else * __r = g_type_check_instance_is_a(__inst, __t); * __r; * })))) * * Insert the ValueDecls of the variables being checked into the provided * unordered_set, and return the number of such insertions (this will be 0 if no * variables are type checked). The returned number may be an over-estimate * of the number of elements in the set, as it doesn’t account for * duplicates. */ static unsigned int _assertion_is_gobject_type_check (Expr& assertion_expr, const ASTContext& context, std::unordered_set<const ValueDecl*>& ret) { DEBUG_EXPR (__func__ << ": ", assertion_expr); switch ((int) assertion_expr.getStmtClass ()) { case Expr::StmtExprClass: { /* Parse all the way through the statement expression, checking * if the first statement is an assignment to the __inst * variable, as in the macro expansion given above. * * This is a particularly shoddy way of checking for a GObject * type check (we should really check for a * g_type_check_instance_is_a() call) but this will do for * now. */ StmtExpr& stmt_expr = cast<StmtExpr> (assertion_expr); CompoundStmt* compound_stmt = stmt_expr.getSubStmt (); const Stmt* first_stmt = *(compound_stmt->body_begin ()); if (first_stmt->getStmtClass () != Expr::DeclStmtClass) return 0; const DeclStmt& decl_stmt = cast<DeclStmt> (*first_stmt); const VarDecl* decl = dyn_cast<VarDecl> (decl_stmt.getSingleDecl ()); if (decl == NULL) return 0; if (decl->getNameAsString () != "__inst") return 0; const Expr* init = decl->getAnyInitializer ()->IgnoreParenCasts (); const DeclRefExpr* decl_expr = dyn_cast<DeclRefExpr> (init); if (decl_expr != NULL) { ret.insert (decl_expr->getDecl ()); return 1; } return 0; } case Expr::IntegerLiteralClass: case Expr::BinaryOperatorClass: case Expr::UnaryOperatorClass: case Expr::ConditionalOperatorClass: case Expr::CallExprClass: case Expr::ImplicitCastExprClass: { /* These can’t be type checks. */ return 0; } case Stmt::StmtClass::NoStmtClass: default: WARN_EXPR (__func__ << "() can’t handle expressions of type " << assertion_expr.getStmtClassName (), assertion_expr); return 0; } }
/* Calculate whether an assertion is a standard non-NULL check. * e.g. (x != NULL), (x), (x != NULL && …) or (x && …). * * Insert the ValueDecls of the variables being checked into the provided * unordered_set, and return the number of such insertions (this will be 0 if no * variables are non-NULL checked). The returned number may be an over-estimate * of the number of elements in the set, as it doesn’t account for * duplicates. */ static unsigned int _assertion_is_explicit_nonnull_check (Expr& assertion_expr, const ASTContext& context, std::unordered_set<const ValueDecl*>& ret) { DEBUG_EXPR (__func__ << ": ", assertion_expr); switch ((int) assertion_expr.getStmtClass ()) { case Expr::BinaryOperatorClass: { BinaryOperator& bin_expr = cast<BinaryOperator> (assertion_expr); BinaryOperatorKind opcode = bin_expr.getOpcode (); if (opcode == BinaryOperatorKind::BO_LAnd) { /* LHS && RHS */ unsigned int lhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getLHS ()), context, ret); unsigned int rhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getRHS ()), context, ret); return lhs_count + rhs_count; } else if (opcode == BinaryOperatorKind::BO_LOr) { /* LHS || RHS */ std::unordered_set<const ValueDecl*> lhs_vars, rhs_vars; unsigned int lhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getLHS ()), context, lhs_vars); unsigned int rhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getRHS ()), context, rhs_vars); std::set_intersection (lhs_vars.begin (), lhs_vars.end (), rhs_vars.begin (), rhs_vars.end (), std::inserter (ret, ret.end ())); return lhs_count + rhs_count; } else if (opcode == BinaryOperatorKind::BO_NE) { /* LHS != RHS */ Expr* rhs = bin_expr.getRHS (); Expr::NullPointerConstantKind k = rhs->isNullPointerConstant (const_cast<ASTContext&> (context), Expr::NullPointerConstantValueDependence::NPC_ValueDependentIsNotNull); if (k != Expr::NullPointerConstantKind::NPCK_NotNull && bin_expr.getLHS ()->IgnoreParenCasts ()->getStmtClass () == Expr::DeclRefExprClass) { DEBUG ("Found non-NULL check."); ret.insert (cast<DeclRefExpr> (bin_expr.getLHS ()->IgnoreParenCasts ())->getDecl ()); return 1; } /* Either not a comparison to NULL, or the expr being * compared is not a DeclRefExpr. */ return 0; } return 0; } case Expr::UnaryOperatorClass: { /* A unary operator. For the moment, assume this isn't a * non-null check. * * FIXME: In the future, define a proper program transformation * to check for non-null checks, since we could have expressions * like: * !(my_var == NULL) * or (more weirdly): * ~(my_var == NULL) */ return 0; } case Expr::ConditionalOperatorClass: { /* A conditional operator. For the moment, assume this isn’t a * non-null check. * * FIXME: In the future, define a proper program transformation * to check for non-null checks, since we could have expressions * like: * (x == NULL) ? TRUE : FALSE */ return 0; } case Expr::CStyleCastExprClass: case Expr::ImplicitCastExprClass: { /* A (explicit or implicit) cast. This can either be: * (void*)0 * or * (bool)my_var */ CastExpr& cast_expr = cast<CastExpr> (assertion_expr); Expr* sub_expr = cast_expr.getSubExpr ()->IgnoreParenCasts (); if (sub_expr->getStmtClass () == Expr::DeclRefExprClass) { DEBUG ("Found non-NULL check."); ret.insert (cast<DeclRefExpr> (sub_expr)->getDecl ()); return 1; } /* Not a cast to NULL, or the expr being casted is not a * DeclRefExpr. */ return 0; } case Expr::DeclRefExprClass: { /* A variable reference, which will implicitly become a non-NULL * check. */ DEBUG ("Found non-NULL check."); DeclRefExpr& decl_ref_expr = cast<DeclRefExpr> (assertion_expr); ret.insert (decl_ref_expr.getDecl ()); return 1; } case Expr::StmtExprClass: /* FIXME: Statement expressions can be nonnull checks, but * detecting them requires a formal program transformation which * has not been implemented yet. */ case Expr::CallExprClass: /* Function calls can’t be nonnull checks. */ case Expr::IntegerLiteralClass: { /* Integer literals can’t be nonnull checks. */ return 0; } case Stmt::StmtClass::NoStmtClass: default: WARN_EXPR (__func__ << "() can’t handle expressions of type " << assertion_expr.getStmtClassName (), assertion_expr); return 0; } }