aboutsummaryrefslogtreecommitdiff
path: root/lib/Checker/IdempotentOperationChecker.cpp
diff options
context:
space:
mode:
authorTom Care <tcare@apple.com>2010-07-16 20:41:41 +0000
committerTom Care <tcare@apple.com>2010-07-16 20:41:41 +0000
commitdf4ca423ec7d9b62842e112d1b824faa08b64810 (patch)
treeebe74672aed0a760164184326524521e32b8ac3f /lib/Checker/IdempotentOperationChecker.cpp
parent35dda71933d2e71b7a865b6ba41cf703e8b99c56 (diff)
Improved false positive rate for the idempotent operations checker and moved it into the default path-sensitive analysis options.
- Added checks for static local variables, self assigned parameters, and truncating/extending self assignments - Removed command line option (now default with --analyze) - Updated test cases to pass with idempotent operation warnings git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108550 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker/IdempotentOperationChecker.cpp')
-rw-r--r--lib/Checker/IdempotentOperationChecker.cpp83
1 files changed, 80 insertions, 3 deletions
diff --git a/lib/Checker/IdempotentOperationChecker.cpp b/lib/Checker/IdempotentOperationChecker.cpp
index 6ed18417a2..744fe2ba99 100644
--- a/lib/Checker/IdempotentOperationChecker.cpp
+++ b/lib/Checker/IdempotentOperationChecker.cpp
@@ -48,7 +48,7 @@
// - Handle mixed assumptions (which assumptions can belong together?)
// - Finer grained false positive control (levels)
-#include "GRExprEngineExperimentalChecks.h"
+#include "GRExprEngineInternalChecks.h"
#include "clang/Checker/BugReporter/BugType.h"
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
#include "clang/Checker/PathSensitive/SVals.h"
@@ -78,6 +78,10 @@ class IdempotentOperationChecker
/// element somewhere. Used in static analysis to reduce false positives.
static bool containsMacro(const Stmt *S);
static bool containsEnum(const Stmt *S);
+ static bool containsStaticLocal(const Stmt *S);
+ static bool isParameterSelfAssign(const Expr *LHS, const Expr *RHS);
+ static bool isTruncationExtensionAssignment(const Expr *LHS,
+ const Expr *RHS);
static bool containsBuiltinOffsetOf(const Stmt *S);
static bool containsZeroConstant(const Stmt *S);
static bool containsOneConstant(const Stmt *S);
@@ -128,7 +132,7 @@ void IdempotentOperationChecker::PreVisitBinaryOperator(
// Skip binary operators containing common false positives
if (containsMacro(B) || containsEnum(B) || containsStmt<SizeOfAlignOfExpr>(B)
|| containsZeroConstant(B) || containsOneConstant(B)
- || containsBuiltinOffsetOf(B)) {
+ || containsBuiltinOffsetOf(B) || containsStaticLocal(B)) {
A = Impossible;
return;
}
@@ -181,12 +185,19 @@ void IdempotentOperationChecker::PreVisitBinaryOperator(
break; // We don't care about any other operators.
// Fall through intentional
+ case BinaryOperator::Assign:
+ // x Assign x has a few more false positives we can check for
+ if (isParameterSelfAssign(RHS, LHS)
+ || isTruncationExtensionAssignment(RHS, LHS)) {
+ A = Impossible;
+ return;
+ }
+
case BinaryOperator::SubAssign:
case BinaryOperator::DivAssign:
case BinaryOperator::AndAssign:
case BinaryOperator::OrAssign:
case BinaryOperator::XorAssign:
- case BinaryOperator::Assign:
case BinaryOperator::Sub:
case BinaryOperator::Div:
case BinaryOperator::And:
@@ -399,6 +410,70 @@ bool IdempotentOperationChecker::containsEnum(const Stmt *S) {
return false;
}
+// Recursively find any substatements containing static vars
+bool IdempotentOperationChecker::containsStaticLocal(const Stmt *S) {
+ const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
+
+ if (DR)
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ if (VD->isStaticLocal())
+ return true;
+
+ for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
+ ++I)
+ if (const Stmt *child = *I)
+ if (containsStaticLocal(child))
+ return true;
+
+ return false;
+}
+
+// Check for a statement were a parameter is self assigned (to avoid an unused
+// variable warning)
+bool IdempotentOperationChecker::isParameterSelfAssign(const Expr *LHS,
+ const Expr *RHS) {
+ LHS = LHS->IgnoreParenCasts();
+ RHS = RHS->IgnoreParenCasts();
+
+ const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS);
+ if (!LHS_DR)
+ return false;
+
+ const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(LHS_DR->getDecl());
+ if (!PD)
+ return false;
+
+ const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS);
+ if (!RHS_DR)
+ return false;
+
+ return PD == RHS_DR->getDecl();
+}
+
+// Check for self casts truncating/extending a variable
+bool IdempotentOperationChecker::isTruncationExtensionAssignment(
+ const Expr *LHS,
+ const Expr *RHS) {
+
+ const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts());
+ if (!LHS_DR)
+ return false;
+
+ const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
+ if (!VD)
+ return false;
+
+ const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts());
+ if (!RHS_DR)
+ return false;
+
+ if (VD != RHS_DR->getDecl())
+ return false;
+
+ return dyn_cast<DeclRefExpr>(RHS->IgnoreParens()) == NULL;
+}
+
+
// Recursively find any substatements containing __builtin_offset_of
bool IdempotentOperationChecker::containsBuiltinOffsetOf(const Stmt *S) {
const UnaryOperator *UO = dyn_cast<UnaryOperator>(S);
@@ -415,6 +490,7 @@ bool IdempotentOperationChecker::containsBuiltinOffsetOf(const Stmt *S) {
return false;
}
+// Check for a integer or float constant of 0
bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) {
const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
if (IL && IL->getValue() == 0)
@@ -433,6 +509,7 @@ bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) {
return false;
}
+// Check for an integer or float constant of 1
bool IdempotentOperationChecker::containsOneConstant(const Stmt *S) {
const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
if (IL && IL->getValue() == 1)