From b9ce295b0a65a4278fe5d8bd6b13a11254529462 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Thu, 27 Sep 2007 18:20:22 +0000 Subject: [PATCH] Created new "ExprDeclBitVector" type bundle for dataflow analyses that need boolean values associated with ScopedDecls and CFGBlock-level Exprs. This is the common boilerplate needed by UninitializedValues and LiveVariables. Refactored UninitializedValues to use ExprDeclBitVector. Shortened the string diagnostic for UninitializedValues. llvm-svn: 42408 --- clang/Analysis/UninitializedValues.cpp | 68 ++++---- .../clang/Analysis/ExprDeclBitVector.h | 149 ++++++++++++++++++ .../clang/Analysis/UninitializedValues.h | 71 +-------- clang/include/clang/Basic/DiagnosticKinds.def | 2 +- 4 files changed, 185 insertions(+), 105 deletions(-) create mode 100644 clang/include/clang/Analysis/ExprDeclBitVector.h diff --git a/clang/Analysis/UninitializedValues.cpp b/clang/Analysis/UninitializedValues.cpp index c885b91046f5..7598a0e16818 100644 --- a/clang/Analysis/UninitializedValues.cpp +++ b/clang/Analysis/UninitializedValues.cpp @@ -33,13 +33,8 @@ class RegisterDeclsExprs : public CFGRecStmtDeclVisitor { public: RegisterDeclsExprs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} - void VisitBlockVarDecl(BlockVarDecl* VD) { - if (!AD.isTracked(VD)) AD[VD] = AD.NumDecls++; - } - - void BlockStmt_VisitExpr(Expr* E) { - if (!AD.isTracked(E)) AD[E] = AD.NumBlockExprs++; - } + void VisitBlockVarDecl(BlockVarDecl* VD) { AD.Register(VD); } + void BlockStmt_VisitExpr(Expr* E) { AD.Register(E); } }; } // end anonymous namespace @@ -77,19 +72,19 @@ public: bool VisitDeclStmt(DeclStmt* D); BlockVarDecl* FindBlockVarDecl(Stmt* S); - - static inline bool Initialized() { return true; } - static inline bool Uninitialized() { return false; } }; + +static const bool Initialized = true; +static const bool Uninitialized = false; bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { if (BlockVarDecl* VD = dyn_cast(DR->getDecl())) { if (AD.Observer) AD.Observer->ObserveDeclRefExpr(V,AD,DR,VD); - return V.getBitRef(VD,AD); + return V(VD,AD); } - else return Initialized(); + else return Initialized; } BlockVarDecl* TransferFuncs::FindBlockVarDecl(Stmt *S) { @@ -109,7 +104,7 @@ BlockVarDecl* TransferFuncs::FindBlockVarDecl(Stmt *S) { bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { if (CFG::hasImplicitControlFlow(B)) - return V.getBitRef(B,AD); + return V(B,AD); if (B->isAssignmentOp()) // Get the Decl for the LHS (if any). @@ -122,30 +117,33 @@ bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { // just adding extra messages that don't // contribute to diagnosing the bug. In InitWithAssigns mode // we unconditionally set the assigned variable to Initialized to - // prevent Uninitialized propogation. - return V.getBitRef(VD,AD) = Initialized(); + // prevent Uninitialized propagation. + return V(VD,AD) = Initialized; } - else return V.getBitRef(VD,AD) = Visit(B->getRHS()); + else return V(VD,AD) = Visit(B->getRHS()); return VisitStmt(B); } bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { - bool x = Initialized(); + bool x = Initialized; for (ScopedDecl* D = S->getDecl(); D != NULL; D = D->getNextDeclarator()) - if (BlockVarDecl* VD = dyn_cast(D)) - if (Stmt* I = VD->getInit()) { - x = V.getBitRef(cast(I),AD); - V.getBitRef(VD,AD) = x; - } + if (BlockVarDecl* VD = dyn_cast(D)) { + if (Stmt* I = VD->getInit()) + x = InitWithAssigns ? Initialized : V(cast(I),AD); + else + x = Uninitialized; + + V(VD,AD) = x; + } return x; } bool TransferFuncs::VisitCallExpr(CallExpr* C) { VisitChildren(C); - return Initialized(); + return Initialized; } bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { @@ -153,7 +151,7 @@ bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { case UnaryOperator::AddrOf: // For "&x", treat "x" as now being initialized. if (BlockVarDecl* VD = FindBlockVarDecl(U->getSubExpr())) - V.getBitRef(VD,AD) = Initialized(); + V(VD,AD) = Initialized; else return Visit(U->getSubExpr()); @@ -163,20 +161,20 @@ bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { } bool TransferFuncs::VisitStmt(Stmt* S) { - bool x = Initialized(); + bool x = Initialized; // We don't stop at the first subexpression that is Uninitialized because // evaluating some subexpressions may result in propogating "Uninitialized" // or "Initialized" to variables referenced in the other subexpressions. for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) - if (Visit(*I) == Uninitialized()) x = Uninitialized(); + if (Visit(*I) == Uninitialized) x = Uninitialized; return x; } bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { assert (AD.isTracked(E)); - return V.getBitRef(E,AD) = Visit(E); + return V(E,AD) = Visit(E); } } // end anonymous namespace @@ -196,15 +194,9 @@ bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { //===----------------------------------------------------------------------===// namespace { -struct Merge { - void operator()(UninitializedValues::ValTy& Dst, - UninitializedValues::ValTy& Src) { - assert (Src.sizesEqual(Dst) && "BV sizes do not match."); - Dst.DeclBV |= Src.DeclBV; - Dst.ExprBV |= Src.ExprBV; - } -}; -} // end anonymous namespace + typedef ExprDeclBitVector_Types::Union Merge; + typedef DataflowSolver Solver; +} //===----------------------------------------------------------------------===// // Unitialized values checker. Scan an AST and flag variable uses @@ -228,7 +220,7 @@ public: assert ( AD.isTracked(VD) && "Unknown VarDecl."); - if (V.getBitRef(VD,AD) == TransferFuncs::Uninitialized()) + if (V(VD,AD) == Uninitialized) if (AlreadyWarned.insert(VD)) Diags.Report(DR->getSourceRange().Begin(), diag::warn_uninit_val); } @@ -237,8 +229,6 @@ public: namespace clang { void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) { - - typedef DataflowSolver Solver; // Compute the unitialized values information. UninitializedValues U; diff --git a/clang/include/clang/Analysis/ExprDeclBitVector.h b/clang/include/clang/Analysis/ExprDeclBitVector.h new file mode 100644 index 000000000000..9a79bbe0b245 --- /dev/null +++ b/clang/include/clang/Analysis/ExprDeclBitVector.h @@ -0,0 +1,149 @@ +//=- ExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- C++ --*-// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Ted Kremenek and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides definition of dataflow types used by analyses such +// as LiveVariables and UninitializedValues. The underlying dataflow values +// are implemented as bitvectors, but the definitions in this file include +// the necessary boilerplate to use with our dataflow framework. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EXPRDECLBVDVAL_H +#define LLVM_CLANG_EXPRDECLBVDVAL_H + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + + class Expr; + class ScopedDecl; + +struct ExprDeclBitVector_Types { + + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data. + //===--------------------------------------------------------------------===// + + class AnalysisDataTy { + typedef llvm::DenseMap DMapTy; + typedef llvm::DenseMap EMapTy; + + EMapTy EMap; + DMapTy DMap; + unsigned NDecls; + unsigned NExprs; + + public: + + AnalysisDataTy() : NDecls(0), NExprs(0) {} + virtual ~AnalysisDataTy() {} + + bool isTracked(const ScopedDecl* SD) { return DMap.find(SD) != DMap.end(); } + bool isTracked(const Expr* E) { return EMap.find(E) != EMap.end(); } + + unsigned operator[](const ScopedDecl* SD) const { + DMapTy::const_iterator I = DMap.find(SD); + assert (I != DMap.end()); + return I->second; + } + + unsigned operator[](const Expr* E) const { + EMapTy::const_iterator I = EMap.find(E); + assert (I != EMap.end()); + return I->second; + } + + unsigned getNumDecls() const { return NDecls; } + unsigned getNumExprs() const { return NExprs; } + + void Register(const ScopedDecl* SD) { + if (!isTracked(SD)) DMap[SD] = NDecls++; + } + + void Register(const Expr* E) { + if (!isTracked(E)) EMap[E] = NExprs++; + } + }; + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + + class ValTy { + llvm::BitVector DeclBV; + llvm::BitVector ExprBV; + public: + + void resetValues(AnalysisDataTy& AD) { + DeclBV.resize(AD.getNumDecls()); + DeclBV.reset(); + ExprBV.resize(AD.getNumExprs()); + ExprBV.reset(); + } + + bool operator==(const ValTy& RHS) const { + assert (sizesEqual(RHS)); + return DeclBV == RHS.DeclBV && ExprBV == RHS.ExprBV; + } + + void copyValues(const ValTy& RHS) { + DeclBV = RHS.DeclBV; + ExprBV = RHS.ExprBV; + } + + llvm::BitVector::reference + operator()(const ScopedDecl* SD, const AnalysisDataTy& AD) { + return DeclBV[AD[SD]]; + } + const llvm::BitVector::reference + operator()(const ScopedDecl* SD, const AnalysisDataTy& AD) const { + return const_cast(*this)(SD,AD); + } + + llvm::BitVector::reference + operator()(const Expr* E, const AnalysisDataTy& AD) { + return ExprBV[AD[E]]; + } + const llvm::BitVector::reference + operator()(const Expr* E, const AnalysisDataTy& AD) const { + return const_cast(*this)(E,AD); + } + + ValTy& operator|=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV |= RHS.DeclBV; + ExprBV |= RHS.ExprBV; + return *this; + } + + ValTy& operator&=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV &= RHS.DeclBV; + ExprBV &= RHS.ExprBV; + return *this; + } + + bool sizesEqual(const ValTy& RHS) const { + return DeclBV.size() == RHS.DeclBV.size() + && ExprBV.size() == RHS.ExprBV.size(); + } + }; + + //===--------------------------------------------------------------------===// + // Some useful merge operations. + //===--------------------------------------------------------------------===// + + struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; + struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; + +}; +} // end namespace clang + +#endif diff --git a/clang/include/clang/Analysis/UninitializedValues.h b/clang/include/clang/Analysis/UninitializedValues.h index e5e92b452de8..571bf14f2b7d 100644 --- a/clang/include/clang/Analysis/UninitializedValues.h +++ b/clang/include/clang/Analysis/UninitializedValues.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_UNITVALS_H #define LLVM_CLANG_UNITVALS_H -#include "llvm/ADT/BitVector.h" +#include "clang/Analysis/ExprDeclBitVector.h" #include "clang/Analysis/FlowSensitive/DataflowValues.h" namespace clang { @@ -31,75 +31,16 @@ namespace clang { class UninitializedValues_ValueTypes { public: - //===--------------------------------------------------------------------===// - // AnalysisDataTy - Whole-function meta data used by the transfer function - // logic. - //===--------------------------------------------------------------------===// - struct ObserverTy; - struct AnalysisDataTy { - llvm::DenseMap VMap; - llvm::DenseMap EMap; - unsigned NumDecls; - unsigned NumBlockExprs; + struct AnalysisDataTy : public ExprDeclBitVector_Types::AnalysisDataTy { + AnalysisDataTy() : Observer(NULL) {} + virtual ~AnalysisDataTy() {}; + ObserverTy* Observer; - - AnalysisDataTy() : NumDecls(0), NumBlockExprs(0), Observer(NULL) {} - - bool isTracked(const BlockVarDecl* VD) { - return VMap.find(VD) != VMap.end(); - } - - bool isTracked(const Expr* E) { - return EMap.find(E) != EMap.end(); - } - - unsigned& operator[](const BlockVarDecl *VD) { return VMap[VD]; } - unsigned& operator[](const Expr* E) { return EMap[E]; } }; - - //===--------------------------------------------------------------------===// - // ValTy - Dataflow value. - //===--------------------------------------------------------------------===// - struct ValTy { - llvm::BitVector DeclBV; - llvm::BitVector ExprBV; - - void resetValues(AnalysisDataTy& AD) { - DeclBV.resize(AD.NumDecls); - DeclBV.reset(); - ExprBV.resize(AD.NumBlockExprs); - ExprBV.reset(); - } - - bool operator==(const ValTy& RHS) const { - return DeclBV == RHS.DeclBV && ExprBV == RHS.ExprBV; - } - - void copyValues(const ValTy& RHS) { - DeclBV = RHS.DeclBV; - ExprBV = RHS.ExprBV; - } - - llvm::BitVector::reference getBitRef(const BlockVarDecl* VD, - AnalysisDataTy& AD) { - assert (AD.isTracked(VD) && "BlockVarDecl not tracked."); - return DeclBV[AD.VMap[VD]]; - } - - llvm::BitVector::reference getBitRef(const Expr* E, - AnalysisDataTy& AD) { - assert (AD.isTracked(E) && "Expr not tracked."); - return ExprBV[AD.EMap[E]]; - } - - bool sizesEqual(ValTy& RHS) { - return DeclBV.size() == RHS.DeclBV.size() && - ExprBV.size() == RHS.ExprBV.size(); - } - }; + typedef ExprDeclBitVector_Types::ValTy ValTy; //===--------------------------------------------------------------------===// // ObserverTy - Observer for querying DeclRefExprs that use an uninitalized diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index d77e6b4d24ee..c394663dd9b7 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -785,7 +785,7 @@ DIAG(warn_floatingpoint_eq, WARNING, DIAG(warn_dead_store, WARNING, "value stored to variable is never used") // CHECK: use of uninitialized values -DIAG(warn_uninit_val, WARNING, "use of potentially uninitialized variable") +DIAG(warn_uninit_val, WARNING, "use of uninitialized variable") // CFString checking DIAG(err_cfstring_literal_not_string_constant, ERROR,