[cfe-commits] r107706 - in /cfe/trunk: include/clang/AST/Stmt.h include/clang/Checker/PathSensitive/SVals.h include/clang/Driver/CC1Options.td include/clang/Frontend/AnalyzerOptions.h lib/AST/Stmt.cpp lib/Checker/AnalysisConsumer.cpp lib/Checker/
Chandler Carruth
chandlerc at google.com
Tue Jul 6 17:39:17 PDT 2010
On Tue, Jul 6, 2010 at 2:43 PM, Tom Care <tcare at apple.com> wrote:
> Author: tcare
> Date: Tue Jul 6 16:43:29 2010
> New Revision: 107706
>
> URL: http://llvm.org/viewvc/llvm-project?rev=107706&view=rev
> Log:
> Added a path-sensitive idempotent operation checker
> (-analyzer-idempotent-operation). Finds idempotent and/or tautological
> operations in a path sensitive context, flagging operations that have no
> effect or a predictable effect.
>
> Example:
> {
> int a = 1;
> int b = 5;
> int c = b / a; // a is 1 on all paths
> }
>
> - New IdempotentOperationChecker class
> - Moved recursive Stmt functions in r107675 to IdempotentOperationChecker
> - Minor refactoring of SVal to allow checking for any integer
> - Added command line option for check
> - Added basic test cases
>
> Added:
> cfe/trunk/lib/Checker/IdempotentOperationChecker.cpp
> cfe/trunk/test/Analysis/idempotent-operations.c
> Modified:
> cfe/trunk/include/clang/AST/Stmt.h
> cfe/trunk/include/clang/Checker/PathSensitive/SVals.h
> cfe/trunk/include/clang/Driver/CC1Options.td
> cfe/trunk/include/clang/Frontend/AnalyzerOptions.h
> cfe/trunk/lib/AST/Stmt.cpp
> cfe/trunk/lib/Checker/AnalysisConsumer.cpp
> cfe/trunk/lib/Checker/CMakeLists.txt
> cfe/trunk/lib/Checker/GRExprEngineExperimentalChecks.h
> cfe/trunk/lib/Checker/SVals.cpp
> cfe/trunk/lib/Frontend/CompilerInvocation.cpp
>
> Modified: cfe/trunk/include/clang/AST/Stmt.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Stmt.h (original)
> +++ cfe/trunk/include/clang/AST/Stmt.h Tue Jul 6 16:43:29 2010
> @@ -253,25 +253,6 @@
> /// within CFGs.
> bool hasImplicitControlFlow() const;
>
> - /// contains* - Useful recursive methods to see if a statement contains
> an
> - /// element somewhere. Used in static analysis to reduce false
> positives.
> - static bool containsMacro(const Stmt *S);
> - static bool containsEnum(const Stmt *S);
> - static bool containsZeroConstant(const Stmt *S);
> - static bool containsOneConstant(const Stmt *S);
> - template <class T> static bool containsStmt(const Stmt *S) {
> - if (isa<T>(S))
> - return true;
> -
> - for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end(); ++I)
> - if (const Stmt *child = *I)
> - if (containsStmt<T>(child))
> - return true;
> -
> - return false;
> - }
> -
> -
> /// Child Iterators: All subclasses must implement child_begin and
> child_end
> /// to permit easy iteration over the substatements/subexpessions of an
> /// AST node. This permits easy iteration over all nodes in the AST.
>
> Modified: cfe/trunk/include/clang/Checker/PathSensitive/SVals.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/SVals.h?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Checker/PathSensitive/SVals.h (original)
> +++ cfe/trunk/include/clang/Checker/PathSensitive/SVals.h Tue Jul 6
> 16:43:29 2010
> @@ -98,6 +98,8 @@
>
> bool isConstant() const;
>
> + bool isConstant(int I) const;
> +
> bool isZeroConstant() const;
>
> /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return
> true;
>
> Modified: cfe/trunk/include/clang/Driver/CC1Options.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Driver/CC1Options.td (original)
> +++ cfe/trunk/include/clang/Driver/CC1Options.td Tue Jul 6 16:43:29 2010
> @@ -81,6 +81,8 @@
> HelpText<"Emit verbose output about the analyzer's progress">;
> def analyzer_experimental_checks : Flag<"-analyzer-experimental-checks">,
> HelpText<"Use experimental path-sensitive checks">;
> +def analyzer_idempotent_operation :
> Flag<"-analyzer-idempotent-operation">,
> + HelpText<"Use experimental path-sensitive idempotent operation
> checker">;
> def analyzer_experimental_internal_checks :
> Flag<"-analyzer-experimental-internal-checks">,
> HelpText<"Use new default path-sensitive checks currently in testing">;
>
> Modified: cfe/trunk/include/clang/Frontend/AnalyzerOptions.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/AnalyzerOptions.h?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Frontend/AnalyzerOptions.h (original)
> +++ cfe/trunk/include/clang/Frontend/AnalyzerOptions.h Tue Jul 6 16:43:29
> 2010
> @@ -72,6 +72,7 @@
> unsigned VisualizeEGUbi : 1;
> unsigned EnableExperimentalChecks : 1;
> unsigned EnableExperimentalInternalChecks : 1;
> + unsigned EnableIdempotentOperationChecker : 1;
> unsigned InlineCall : 1;
>
> public:
>
> Modified: cfe/trunk/lib/AST/Stmt.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Stmt.cpp (original)
> +++ cfe/trunk/lib/AST/Stmt.cpp Tue Jul 6 16:43:29 2010
> @@ -127,72 +127,6 @@
> }
> }
>
> -// Recursively find any substatements containing macros
> -bool Stmt::containsMacro(const Stmt *S) {
> - if (S->getLocStart().isMacroID())
> - return true;
> -
> - if (S->getLocEnd().isMacroID())
> - return true;
> -
> - for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end(); ++I)
> - if (const Stmt *child = *I)
> - if (containsMacro(child))
> - return true;
> -
> - return false;
> -}
> -
> -// Recursively find any substatements containing enum constants
> -bool Stmt::containsEnum(const Stmt *S) {
> - const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
> -
> - if (DR && isa<EnumConstantDecl>(DR->getDecl()))
> - return true;
> -
> - for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end(); ++I)
> - if (const Stmt *child = *I)
> - if (containsEnum(child))
> - return true;
> -
> - return false;
> -}
> -
> -bool Stmt::containsZeroConstant(const Stmt *S) {
> - const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
> - if (IL && IL->getValue() == 0)
> - return true;
> -
> - const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S);
> - if (FL && FL->getValue().isZero())
> - return true;
> -
> - for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end(); ++I)
> - if (const Stmt *child = *I)
> - if (containsZeroConstant(child))
> - return true;
> -
> - return false;
> -}
> -
> -bool Stmt::containsOneConstant(const Stmt *S) {
> - const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
> - if (IL && IL->getValue() == 1)
> - return true;
> -
> - const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S);
> - const llvm::APFloat one(1.0);
> - if (FL && FL->getValue().compare(one) == llvm::APFloat::cmpEqual)
> - return true;
> -
> - for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end(); ++I)
> - if (const Stmt *child = *I)
> - if (containsOneConstant(child))
> - return true;
> -
> - return false;
> -}
> -
> Expr *AsmStmt::getOutputExpr(unsigned i) {
> return cast<Expr>(Exprs[i]);
> }
>
> Modified: cfe/trunk/lib/Checker/AnalysisConsumer.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/AnalysisConsumer.cpp?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Checker/AnalysisConsumer.cpp (original)
> +++ cfe/trunk/lib/Checker/AnalysisConsumer.cpp Tue Jul 6 16:43:29 2010
> @@ -28,6 +28,7 @@
> #include "clang/Checker/PathSensitive/GRExprEngine.h"
> #include "clang/Checker/PathSensitive/GRTransferFuncs.h"
> #include "clang/Checker/PathDiagnosticClients.h"
> +#include "GRExprEngineExperimentalChecks.h"
> #include "clang/Basic/FileManager.h"
> #include "clang/Basic/SourceManager.h"
> #include "clang/Frontend/AnalyzerOptions.h"
> @@ -340,6 +341,9 @@
> if (C.Opts.EnableExperimentalChecks)
> RegisterExperimentalChecks(Eng);
>
> + if (C.Opts.EnableIdempotentOperationChecker)
> + RegisterIdempotentOperationChecker(Eng);
> +
> // Set the graph auditor.
> llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
> if (mgr.shouldVisualizeUbigraph()) {
>
> Modified: cfe/trunk/lib/Checker/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CMakeLists.txt?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Checker/CMakeLists.txt (original)
> +++ cfe/trunk/lib/Checker/CMakeLists.txt Tue Jul 6 16:43:29 2010
> @@ -39,6 +39,7 @@
> GRExprEngineExperimentalChecks.cpp
> GRState.cpp
> HTMLDiagnostics.cpp
> + IdempotentOperationChecker.cpp
> LLVMConventionsChecker.cpp
> MacOSXAPIChecker.cpp
> MallocChecker.cpp
>
> Modified: cfe/trunk/lib/Checker/GRExprEngineExperimentalChecks.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngineExperimentalChecks.h?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Checker/GRExprEngineExperimentalChecks.h (original)
> +++ cfe/trunk/lib/Checker/GRExprEngineExperimentalChecks.h Tue Jul 6
> 16:43:29 2010
> @@ -22,6 +22,7 @@
> void RegisterPthreadLockChecker(GRExprEngine &Eng);
> void RegisterMallocChecker(GRExprEngine &Eng);
> void RegisterStreamChecker(GRExprEngine &Eng);
> +void RegisterIdempotentOperationChecker(GRExprEngine &Eng);
>
> } // end clang namespace
> #endif
>
> Added: cfe/trunk/lib/Checker/IdempotentOperationChecker.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/IdempotentOperationChecker.cpp?rev=107706&view=auto
>
> ==============================================================================
> --- cfe/trunk/lib/Checker/IdempotentOperationChecker.cpp (added)
> +++ cfe/trunk/lib/Checker/IdempotentOperationChecker.cpp Tue Jul 6
> 16:43:29 2010
> @@ -0,0 +1,453 @@
> +//==- IdempotentOperationChecker.cpp - Idempotent Operations ----*- C++
> -*-==//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines a set of path-sensitive checks for idempotent and/or
> +// tautological operations. Each potential operation is checked along all
> paths
> +// to see if every path results in a pointless operation.
> +// +-------------------------------------------+
> +// |Table of idempotent/tautological operations|
> +// +-------------------------------------------+
>
> +//+--------------------------------------------------------------------------+
> +//|Operator | x op x | x op 1 | 1 op x | x op 0 | 0 op x | x op ~0 | ~0 op
> x |
>
> +//+--------------------------------------------------------------------------+
> +// +, += | | | | x | x | |
> +// -, -= | | | | x | -x | |
> +// *, *= | | x | x | 0 | 0 | |
> +// /, /= | 1 | x | | N/A | 0 | |
> +// &, &= | x | | | 0 | 0 | x | x
> +// |, |= | x | | | x | x | ~0 | ~0
> +// ^, ^= | 0 | | | x | x | |
> +// <<, <<= | | | | x | 0 | |
> +// >>, >>= | | | | x | 0 | |
> +// || | 1 | 1 | 1 | x | x | 1 | 1
> +// && | 1 | x | x | 0 | 0 | x | x
> +// = | x | | | | | |
> +// == | 1 | | | | | |
> +// >= | 1 | | | | | |
> +// <= | 1 | | | | | |
> +// > | 0 | | | | | |
> +// < | 0 | | | | | |
> +// != | 0 | | | | | |
>
> +//===----------------------------------------------------------------------===//
> +//
> +// Ways to reduce false positives (that need to be implemented):
> +// - Don't flag downsizing casts
> +// - Improved handling of static/global variables
> +// - Per-block marking of incomplete analysis
> +// - Handling ~0 values
> +// - False positives involving silencing unused variable warnings
> +//
> +// Other things TODO:
> +// - Improved error messages
> +// - Handle mixed assumptions (which assumptions can belong together?)
> +// - Finer grained false positive control (levels)
> +
> +#include "GRExprEngineExperimentalChecks.h"
> +#include "clang/Checker/BugReporter/BugType.h"
> +#include "clang/Checker/PathSensitive/CheckerVisitor.h"
> +#include "clang/Checker/PathSensitive/SVals.h"
> +#include "clang/AST/Stmt.h"
> +#include "llvm/ADT/DenseMap.h"
> +
> +using namespace clang;
> +
> +namespace {
> +class IdempotentOperationChecker
> + : public CheckerVisitor<IdempotentOperationChecker> {
> + public:
> + static void *getTag();
> + void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator
> *B);
> + void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
> + bool hasWorkRemaining);
> +
> + private:
> + // Our assumption about a particular operation.
> + enum Assumption { Possible, Impossible, Equal, LHSis1, RHSis1, LHSis0,
> + RHSis0 };
> +
> + void UpdateAssumption(Assumption &A, const Assumption &New);
> +
> + /// contains* - Useful recursive methods to see if a statement
> contains an
> + /// element somewhere. Used in static analysis to reduce false
> positives.
> + static bool containsMacro(const Stmt *S);
> + static bool containsEnum(const Stmt *S);
> + static bool containsBuiltinOffsetOf(const Stmt *S);
> + static bool containsZeroConstant(const Stmt *S);
> + static bool containsOneConstant(const Stmt *S);
> + template <class T> static bool containsStmt(const Stmt *S) {
> + if (isa<T>(S))
> + return true;
> +
> + for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end();
> + ++I)
> + if (const Stmt *child = *I)
> + if (containsStmt<T>(child))
> + return true;
> +
> + return false;
> + }
> +
> + // Hash table
> + typedef llvm::DenseMap<const BinaryOperator *, Assumption>
> AssumptionMap;
> + AssumptionMap hash;
> +};
> +}
> +
> +void *IdempotentOperationChecker::getTag() {
> + static int x = 0;
> + return &x;
> +}
> +
> +void clang::RegisterIdempotentOperationChecker(GRExprEngine &Eng) {
> + Eng.registerCheck(new IdempotentOperationChecker());
> +}
> +
> +void IdempotentOperationChecker::PreVisitBinaryOperator(
> + CheckerContext &C,
> + const BinaryOperator
> *B) {
> + // Find or create an entry in the hash for this BinaryOperator instance
> + AssumptionMap::iterator i = hash.find(B);
> + Assumption &A = i == hash.end() ? hash[B] : i->second;
> +
> + // If we had to create an entry, initialise the value to Possible
> + if (i == hash.end())
> + A = Possible;
> +
> + // If we already have visited this node on a path that does not contain
> an
> + // idempotent operation, return immediately.
> + if (A == Impossible)
> + return;
> +
> + // Skip binary operators containing common false positives
> + if (containsMacro(B) || containsEnum(B) ||
> containsStmt<SizeOfAlignOfExpr>(B)
> + || containsZeroConstant(B) || containsOneConstant(B)
> + || containsBuiltinOffsetOf(B)) {
> + A = Impossible;
> + return;
> + }
> +
> + const Expr *LHS = B->getLHS();
> + const Expr *RHS = B->getRHS();
> +
> + const GRState *state = C.getState();
> +
> + SVal LHSVal = state->getSVal(LHS);
> + SVal RHSVal = state->getSVal(RHS);
> +
> + // If either value is unknown, we can't be 100% sure of all paths.
> + if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
> + A = Impossible;
> + return;
> + }
> + BinaryOperator::Opcode Op = B->getOpcode();
> +
> + // Dereference the LHS SVal if this is an assign operation
> + switch (Op) {
> + default:
> + break;
> +
> + // Fall through intentional
> + case BinaryOperator::AddAssign:
> + case BinaryOperator::SubAssign:
> + case BinaryOperator::MulAssign:
> + case BinaryOperator::DivAssign:
> + case BinaryOperator::AndAssign:
> + case BinaryOperator::OrAssign:
> + case BinaryOperator::XorAssign:
> + case BinaryOperator::ShlAssign:
> + case BinaryOperator::ShrAssign:
> + case BinaryOperator::Assign:
> + // Assign statements have one extra level of indirection
> + if (!isa<Loc>(LHSVal)) {
> + A = Impossible;
> + return;
> + }
> + LHSVal = state->getSVal(cast<Loc>(LHSVal));
> + }
> +
> +
> + // We now check for various cases which result in an idempotent
> operation.
> +
> + // x op x
> + switch (Op) {
> + default:
> + break; // We don't care about any other operators.
> +
> + // Fall through intentional
> + 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:
> + case BinaryOperator::Or:
> + case BinaryOperator::Xor:
> + case BinaryOperator::LOr:
> + case BinaryOperator::LAnd:
> + if (LHSVal != RHSVal)
> + break;
> + UpdateAssumption(A, Equal);
> + return;
> + }
> +
> + // x op 1
> + switch (Op) {
> + default:
> + break; // We don't care about any other operators.
> +
> + // Fall through intentional
> + case BinaryOperator::MulAssign:
> + case BinaryOperator::DivAssign:
> + case BinaryOperator::Mul:
> + case BinaryOperator::Div:
> + case BinaryOperator::LOr:
> + case BinaryOperator::LAnd:
> + if (!RHSVal.isConstant(1))
> + break;
> + UpdateAssumption(A, RHSis1);
> + return;
> + }
> +
> + // 1 op x
> + switch (Op) {
> + default:
> + break; // We don't care about any other operators.
> +
> + // Fall through intentional
> + case BinaryOperator::MulAssign:
> + case BinaryOperator::Mul:
> + case BinaryOperator::LOr:
> + case BinaryOperator::LAnd:
> + if (!LHSVal.isConstant(1))
> + break;
> + UpdateAssumption(A, LHSis1);
> + return;
> + }
> +
> + // x op 0
> + switch (Op) {
> + default:
> + break; // We don't care about any other operators.
> +
> + // Fall through intentional
> + case BinaryOperator::AddAssign:
> + case BinaryOperator::SubAssign:
> + case BinaryOperator::MulAssign:
> + case BinaryOperator::AndAssign:
> + case BinaryOperator::OrAssign:
> + case BinaryOperator::XorAssign:
> + case BinaryOperator::Add:
> + case BinaryOperator::Sub:
> + case BinaryOperator::Mul:
> + case BinaryOperator::And:
> + case BinaryOperator::Or:
> + case BinaryOperator::Xor:
> + case BinaryOperator::Shl:
> + case BinaryOperator::Shr:
> + case BinaryOperator::LOr:
> + case BinaryOperator::LAnd:
> + if (!RHSVal.isConstant(0))
> + break;
> + UpdateAssumption(A, RHSis0);
> + return;
> + }
> +
> + // 0 op x
> + switch (Op) {
> + default:
> + break; // We don't care about any other operators.
> +
> + // Fall through intentional
> + //case BinaryOperator::AddAssign: // Common false positive
> + case BinaryOperator::SubAssign: // Check only if unsigned
> + case BinaryOperator::MulAssign:
> + case BinaryOperator::DivAssign:
> + case BinaryOperator::AndAssign:
> + //case BinaryOperator::OrAssign: // Common false positive
> + //case BinaryOperator::XorAssign: // Common false positive
> + case BinaryOperator::ShlAssign:
> + case BinaryOperator::ShrAssign:
> + case BinaryOperator::Add:
> + case BinaryOperator::Sub:
> + case BinaryOperator::Mul:
> + case BinaryOperator::Div:
> + case BinaryOperator::And:
> + case BinaryOperator::Or:
> + case BinaryOperator::Xor:
> + case BinaryOperator::Shl:
> + case BinaryOperator::Shr:
> + case BinaryOperator::LOr:
> + case BinaryOperator::LAnd:
> + if (!LHSVal.isConstant(0))
> + break;
> + UpdateAssumption(A, LHSis0);
> + return;
> + }
> +
> + // If we get to this point, there has been a valid use of this
> operation.
> + A = Impossible;
> +}
> +
> +void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
> + BugReporter &B,
> + bool hasWorkRemaining) {
> + // If there is any work remaining we cannot be 100% sure about our
> warnings
> + if (hasWorkRemaining)
> + return;
> +
> + // Iterate over the hash to see if we have any paths with definite
> + // idempotent operations.
> + for (AssumptionMap::const_iterator i =
> + hash.begin(); i != hash.end(); ++i) {
> + if (i->second != Impossible) {
>
Any reason not to just 'continue' in the case below? At the very least
'break' there seems strange, llvm_unreachable would make more sense.
Also, I tweaked this code a bit in r107741 and 107745 to make GCC happier
about the msg variable. Check and see if that looks OK?
> + // Select the error message.
> + const char *msg;
> + switch (i->second) {
> + case Equal:
> + msg = "idempotent operation; both operands are always equal in
> value";
> + break;
> + case LHSis1:
> + msg = "idempotent operation; the left operand is always 1";
> + break;
> + case RHSis1:
> + msg = "idempotent operation; the right operand is always 1";
> + break;
> + case LHSis0:
> + msg = "idempotent operation; the left operand is always 0";
> + break;
> + case RHSis0:
> + msg = "idempotent operation; the right operand is always 0";
> + break;
> + case Impossible:
> + break;
> + case Possible:
> + assert(0 && "Operation was never marked with an assumption");
> + }
> +
> + // Create the SourceRange Arrays
> + SourceRange S[2] = { i->first->getLHS()->getSourceRange(),
> + i->first->getRHS()->getSourceRange() };
> + B.EmitBasicReport("Idempotent operation", msg,
> i->first->getOperatorLoc(),
> + S, 2);
> + }
> + }
> +}
> +
> +// Updates the current assumption given the new assumption
> +inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A,
> + const Assumption
> &New) {
> + switch (A) {
> + // If we don't currently have an assumption, set it
> + case Possible:
> + A = New;
> + return;
> +
> + // If we have determined that a valid state happened, ignore the new
> + // assumption.
> + case Impossible:
> + return;
> +
> + // Any other case means that we had a different assumption last time. We
> don't
> + // currently support mixing assumptions for diagnostic reasons, so we
> set
> + // our assumption to be impossible.
> + default:
> + A = Impossible;
> + return;
> + }
> +}
> +
> +// Recursively find any substatements containing macros
> +bool IdempotentOperationChecker::containsMacro(const Stmt *S) {
> + if (S->getLocStart().isMacroID())
> + return true;
> +
> + if (S->getLocEnd().isMacroID())
> + return true;
> +
> + for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end();
> + ++I)
> + if (const Stmt *child = *I)
> + if (containsMacro(child))
> + return true;
> +
> + return false;
> +}
> +
> +// Recursively find any substatements containing enum constants
> +bool IdempotentOperationChecker::containsEnum(const Stmt *S) {
> + const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
> +
> + if (DR && isa<EnumConstantDecl>(DR->getDecl()))
> + return true;
> +
> + for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end();
> + ++I)
> + if (const Stmt *child = *I)
> + if (containsEnum(child))
> + return true;
> +
> + return false;
> +}
> +
> +// Recursively find any substatements containing __builtin_offset_of
> +bool IdempotentOperationChecker::containsBuiltinOffsetOf(const Stmt *S) {
> + const UnaryOperator *UO = dyn_cast<UnaryOperator>(S);
> +
> + if (UO && UO->getOpcode() == UnaryOperator::OffsetOf)
> + return true;
> +
> + for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end();
> + ++I)
> + if (const Stmt *child = *I)
> + if (containsBuiltinOffsetOf(child))
> + return true;
> +
> + return false;
> +}
> +
> +bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) {
> + const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
> + if (IL && IL->getValue() == 0)
> + return true;
> +
> + const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S);
> + if (FL && FL->getValue().isZero())
> + return true;
> +
> + for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end();
> + ++I)
> + if (const Stmt *child = *I)
> + if (containsZeroConstant(child))
> + return true;
> +
> + return false;
> +}
> +
> +bool IdempotentOperationChecker::containsOneConstant(const Stmt *S) {
> + const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(S);
> + if (IL && IL->getValue() == 1)
> + return true;
> +
> + const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(S);
> + const llvm::APFloat one(1.0);
> + if (FL && FL->getValue().compare(one) == llvm::APFloat::cmpEqual)
> + return true;
> +
> + for (Stmt::const_child_iterator I = S->child_begin(); I !=
> S->child_end();
> + ++I)
> + if (const Stmt *child = *I)
> + if (containsOneConstant(child))
> + return true;
> +
> + return false;
> +}
> +
>
> Modified: cfe/trunk/lib/Checker/SVals.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/SVals.cpp?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Checker/SVals.cpp (original)
> +++ cfe/trunk/lib/Checker/SVals.cpp Tue Jul 6 16:43:29 2010
> @@ -200,15 +200,19 @@
> return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
> }
>
> -bool SVal::isZeroConstant() const {
> +bool SVal::isConstant(int I) const {
> if (isa<loc::ConcreteInt>(*this))
> - return cast<loc::ConcreteInt>(*this).getValue() == 0;
> + return cast<loc::ConcreteInt>(*this).getValue() == I;
> else if (isa<nonloc::ConcreteInt>(*this))
> - return cast<nonloc::ConcreteInt>(*this).getValue() == 0;
> + return cast<nonloc::ConcreteInt>(*this).getValue() == I;
> else
> return false;
> }
>
> +bool SVal::isZeroConstant() const {
> + return isConstant(0);
> +}
> +
>
>
> //===----------------------------------------------------------------------===//
> // Transfer function dispatch for Non-Locs.
>
> Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=107706&r1=107705&r2=107706&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
> +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Jul 6 16:43:29 2010
> @@ -112,6 +112,8 @@
> Res.push_back("-analyzer-experimental-checks");
> if (Opts.EnableExperimentalInternalChecks)
> Res.push_back("-analyzer-experimental-internal-checks");
> + if (Opts.EnableIdempotentOperationChecker)
> + Res.push_back("-analyzer-idempotent-operation");
> }
>
> static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
> @@ -788,6 +790,8 @@
> Opts.EnableExperimentalChecks =
> Args.hasArg(OPT_analyzer_experimental_checks);
> Opts.EnableExperimentalInternalChecks =
> Args.hasArg(OPT_analyzer_experimental_internal_checks);
> + Opts.EnableIdempotentOperationChecker =
> + Args.hasArg(OPT_analyzer_idempotent_operation);
> Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
> Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes,
> 150000,Diags);
> Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags);
>
> Added: cfe/trunk/test/Analysis/idempotent-operations.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/idempotent-operations.c?rev=107706&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Analysis/idempotent-operations.c (added)
> +++ cfe/trunk/test/Analysis/idempotent-operations.c Tue Jul 6 16:43:29
> 2010
> @@ -0,0 +1,52 @@
> +// RUN: %clang_cc1 -Wunused-variable -analyze
> -analyzer-idempotent-operation -analyzer-store=basic
> -analyzer-constraints=range
> +
> +// Basic tests
> +
> +extern void test(int i);
> +
> +void basic() {
> + int x = 10, zero = 0, one = 1;
> +
> + // x op x
> + x = x; // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + test(x - x); // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + x -= x; // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + x = 10; // no-warning
> + test(x / x); // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + x /= x; // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + x = 10; // no-warning
> + test(x & x); // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + x &= x; // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + test(x | x); // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> + x |= x; // expected-warning {{idempotent operation; both operands
> are always equal in value}}
> +
> + // x op 1
> + test(x * one); // expected-warning {{idempotent operation; the right
> operand is always 1}}
> + x *= one; // expected-warning {{idempotent operation; the right
> operand is always 1}}
> + test(x / one); // expected-warning {{idempotent operation; the right
> operand is always 1}}
> + x /= one; // expected-warning {{idempotent operation; the right
> operand is always 1}}
> +
> + // 1 op x
> + test(one * x); // expected-warning {{idempotent operation; the left
> operand is always 1}}
> +
> + // x op 0
> + test(x + zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> + test(x - zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> + test(x * zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> + test(x & zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> + test(x | zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> + test(x ^ zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> + test(x << zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> + test(x >> zero); // expected-warning {{idempotent operation; the right
> operand is always 0}}
> +
> + // 0 op x
> + test(zero + x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero - x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero / x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero * x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero & x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero | x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero ^ x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero << x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> + test(zero >> x); // expected-warning {{idempotent operation; the left
> operand is always 0}}
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100706/b18d80e2/attachment.html>
More information about the cfe-commits
mailing list