summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang-plugin/assertion-extracter.cpp115
-rw-r--r--clang-plugin/assertion-extracter.h5
-rw-r--r--clang-plugin/gassert-attributes.cpp6
3 files changed, 61 insertions, 65 deletions
diff --git a/clang-plugin/assertion-extracter.cpp b/clang-plugin/assertion-extracter.cpp
index a8690f2..68a3100 100644
--- a/clang-plugin/assertion-extracter.cpp
+++ b/clang-plugin/assertion-extracter.cpp
@@ -617,14 +617,16 @@ _simplify_boolean_expr (Expr* expr, const ASTContext& context)
* __r;
* }))))
*
- * Return a set of the ValueDecls of the variables being checked. This will be
- * empty if no variables are type checked. */
-static std::unordered_set<const ValueDecl*>
+ * 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. */
+unsigned int
_assertion_is_gobject_type_check (Expr& assertion_expr,
- const ASTContext& context)
+ const ASTContext& context,
+ std::unordered_set<const ValueDecl*>& ret)
{
- std::unordered_set<const ValueDecl*> ret;
-
DEBUG_EXPR (__func__ << ": ", assertion_expr);
switch (assertion_expr.getStmtClass ()) {
@@ -642,25 +644,27 @@ _assertion_is_gobject_type_check (Expr& assertion_expr,
const Stmt* first_stmt = *(compound_stmt->body_begin ());
if (first_stmt->getStmtClass () != Expr::DeclStmtClass)
- return ret;
+ return 0;
const DeclStmt& decl_stmt = cast<DeclStmt> (*first_stmt);
const VarDecl* decl =
dyn_cast<VarDecl> (decl_stmt.getSingleDecl ());
if (decl == NULL)
- return ret;
+ return 0;
if (decl->getNameAsString () != "__inst")
- return ret;
+ return 0;
const Expr* init =
decl->getAnyInitializer ()->IgnoreParenCasts ();
const DeclRefExpr* decl_expr = dyn_cast<DeclRefExpr> (init);
- if (decl_expr != NULL)
+ if (decl_expr != NULL) {
ret.insert (decl_expr->getDecl ());
+ return 1;
+ }
- return ret;
+ return 0;
}
case Expr::IntegerLiteralClass:
case Expr::BinaryOperatorClass:
@@ -668,27 +672,29 @@ _assertion_is_gobject_type_check (Expr& assertion_expr,
case Expr::CallExprClass:
case Expr::ImplicitCastExprClass: {
/* These can’t be type checks. */
- return ret;
+ return 0;
}
case Stmt::StmtClass::NoStmtClass:
default:
WARN (__func__ << "() can’t handle expressions of type " <<
assertion_expr.getStmtClassName ());
- return ret;
+ return 0;
}
}
/* Calculate whether an assertion is a standard non-NULL check.
* e.g. (x != NULL), (x), (x != NULL && …) or (x && …).
*
- * Return a set of the ValueDecls of the variables being checked. This will be
- * empty if no variables are non-NULL checked. */
-static std::unordered_set<const ValueDecl*>
+ * 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. */
+unsigned int
_assertion_is_explicit_nonnull_check (Expr& assertion_expr,
- const ASTContext& context)
+ const ASTContext& context,
+ std::unordered_set<const ValueDecl*>& ret)
{
- std::unordered_set<const ValueDecl*> ret;
-
DEBUG_EXPR (__func__ << ": ", assertion_expr);
switch (assertion_expr.getStmtClass ()) {
@@ -699,24 +705,20 @@ _assertion_is_explicit_nonnull_check (Expr& assertion_expr,
if (opcode == BinaryOperatorKind::BO_LAnd) {
/* LHS && RHS */
- std::unordered_set<const ValueDecl*> lhs_vars =
- AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getLHS ()), context);
- std::unordered_set<const ValueDecl*> rhs_vars =
- AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getRHS ()), context);
-
- std::set_union (lhs_vars.begin (),
- lhs_vars.end (),
- rhs_vars.begin (),
- rhs_vars.end (),
- std::inserter (ret, ret.end ()));
-
- return ret;
+ 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 =
- AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getLHS ()), context);
- std::unordered_set<const ValueDecl*> rhs_vars =
- AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getRHS ()), context);
+ 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 (),
@@ -724,7 +726,7 @@ _assertion_is_explicit_nonnull_check (Expr& assertion_expr,
rhs_vars.end (),
std::inserter (ret, ret.end ()));
- return ret;
+ return lhs_count + rhs_count;
} else if (opcode == BinaryOperatorKind::BO_NE) {
/* LHS != RHS */
Expr* rhs = bin_expr.getRHS ();
@@ -734,15 +736,15 @@ _assertion_is_explicit_nonnull_check (Expr& assertion_expr,
if (k != Expr::NullPointerConstantKind::NPCK_NotNull &&
bin_expr.getLHS ()->IgnoreParenCasts ()->getStmtClass () == Expr::DeclRefExprClass) {
ret.insert (cast<DeclRefExpr> (bin_expr.getLHS ()->IgnoreParenCasts ())->getDecl ());
- return ret;
+ return 1;
}
/* Either not a comparison to NULL, or the expr being
* compared is not a DeclRefExpr. */
- return ret;
+ return 0;
}
- return ret;
+ return 0;
}
case Expr::UnaryOperatorClass: {
/* A unary operator. For the moment, assume this isn't a
@@ -755,7 +757,7 @@ _assertion_is_explicit_nonnull_check (Expr& assertion_expr,
* or (more weirdly):
* ~(my_var == NULL)
*/
- return ret;
+ return 0;
}
case Expr::CStyleCastExprClass:
case Expr::ImplicitCastExprClass: {
@@ -768,19 +770,19 @@ _assertion_is_explicit_nonnull_check (Expr& assertion_expr,
if (sub_expr->getStmtClass () == Expr::DeclRefExprClass) {
ret.insert (cast<DeclRefExpr> (sub_expr)->getDecl ());
- return ret;
+ return 1;
}
/* Not a cast to NULL, or the expr being casted is not a
* DeclRefExpr. */
- return ret;
+ return 0;
}
case Expr::DeclRefExprClass: {
/* A variable reference, which will implicitly become a non-NULL
* check. */
DeclRefExpr& decl_ref_expr = cast<DeclRefExpr> (assertion_expr);
ret.insert (decl_ref_expr.getDecl ());
- return ret;
+ return 1;
}
case Expr::StmtExprClass:
/* FIXME: Statement expressions can be nonnull checks, but
@@ -790,36 +792,29 @@ _assertion_is_explicit_nonnull_check (Expr& assertion_expr,
/* Function calls can’t be nonnull checks. */
case Expr::IntegerLiteralClass: {
/* Integer literals can’t be nonnull checks. */
- return ret;
+ return 0;
}
case Stmt::StmtClass::NoStmtClass:
default:
WARN (__func__ << "() can’t handle expressions of type " <<
assertion_expr.getStmtClassName ());
- return ret;
+ return 0;
}
}
-std::unordered_set<const ValueDecl*>
+unsigned int
AssertionExtracter::assertion_is_nonnull_check (Expr& assertion_expr,
- const ASTContext& context)
+ const ASTContext& context,
+ std::unordered_set<const ValueDecl*>& param_decls)
{
/* After this call, assume expr is in boolean disjunctive normal
* form. */
Expr* expr = _simplify_boolean_expr (&assertion_expr, context);
- std::unordered_set<const ValueDecl*> ret;
-
- std::unordered_set<const ValueDecl*> explicit_vars =
- _assertion_is_explicit_nonnull_check (*expr, context);
- std::unordered_set<const ValueDecl*> type_check_vars =
- _assertion_is_gobject_type_check (*expr, context);
-
- std::set_union (explicit_vars.begin (),
- explicit_vars.end (),
- type_check_vars.begin (),
- type_check_vars.end (),
- std::inserter (ret, ret.end ()));
+ unsigned int explicit_nonnull_count =
+ _assertion_is_explicit_nonnull_check (*expr, context, param_decls);
+ unsigned int type_check_count =
+ _assertion_is_gobject_type_check (*expr, context, param_decls);
- return ret;
+ return explicit_nonnull_count + type_check_count;
}
diff --git a/clang-plugin/assertion-extracter.h b/clang-plugin/assertion-extracter.h
index edd3294..c1c8093 100644
--- a/clang-plugin/assertion-extracter.h
+++ b/clang-plugin/assertion-extracter.h
@@ -30,6 +30,7 @@ using namespace clang;
namespace AssertionExtracter {
Expr* is_assertion_stmt (Stmt& stmt, const ASTContext& context);
- std::unordered_set<const ValueDecl*> assertion_is_nonnull_check (
- Expr& assertion_expr, const ASTContext& context);
+ unsigned int assertion_is_nonnull_check (
+ Expr& assertion_expr, const ASTContext& context,
+ std::unordered_set<const ValueDecl*>& param_decls);
}
diff --git a/clang-plugin/gassert-attributes.cpp b/clang-plugin/gassert-attributes.cpp
index cbcdf81..33bedd0 100644
--- a/clang-plugin/gassert-attributes.cpp
+++ b/clang-plugin/gassert-attributes.cpp
@@ -53,9 +53,9 @@ _handle_assertion (FunctionDecl& func, Expr& assertion_expr,
/* If the assertion is a non-NULL check, add nonnull attributes to the
* function’s parameters accordingly. */
- std::unordered_set<const ValueDecl*> ret =
- AssertionExtracter::assertion_is_nonnull_check (assertion_expr,
- context);
+ std::unordered_set<const ValueDecl*> ret;
+ AssertionExtracter::assertion_is_nonnull_check (assertion_expr,
+ context, ret);
if (ret.size () == 0)
return;