Esempio n. 1
0
/* 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;
	}
}
Esempio n. 2
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;
	}
}