From: Ted Kremenek Date: Thu, 24 Jan 2008 02:02:54 +0000 (+0000) Subject: Added passing "ASTContext" to both GREngine and GRConstants. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=874d63fc63387365a21775a14c01963b10fde689;p=clang Added passing "ASTContext" to both GREngine and GRConstants. Added initial support for integer casting operations to GRConstants. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46298 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Analysis/GRConstants.cpp b/Analysis/GRConstants.cpp index e1e664edb1..0a9c68a7fe 100644 --- a/Analysis/GRConstants.cpp +++ b/Analysis/GRConstants.cpp @@ -17,6 +17,7 @@ #include "clang/Analysis/PathSensitive/GREngine.h" #include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "llvm/Support/Casting.h" @@ -114,14 +115,16 @@ namespace { typedef llvm::ImmutableSet APSIntSetTy; class VISIBILITY_HIDDEN ValueManager { - - APSIntSetTy::Factory APSIntSetFactory; + ASTContext* Ctx; public: ValueManager() {} ~ValueManager() {} + void setContext(ASTContext* ctx) { Ctx = ctx; } + ASTContext* getContext() const { return Ctx; } + APSIntSetTy GetEmptyAPSIntSet() { return APSIntSetFactory.GetEmptySet(); } @@ -164,6 +167,8 @@ protected: public: ~ExprValue() {}; + ExprValue EvalCast(ValueManager& ValMgr, Expr* CastExpr) const; + void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned) getKind()); ID.AddPointer(Data); @@ -204,9 +209,9 @@ protected: RValue(Kind k, void* d) : ExprValue(k,d) {} public: - RValue Add(ValueManager& ValMgr, const RValue& RHS) const; - RValue Sub(ValueManager& ValMgr, const RValue& RHS) const; - RValue Mul(ValueManager& ValMgr, const RValue& RHS) const; + RValue EvalAdd(ValueManager& ValMgr, const RValue& RHS) const; + RValue EvalSub(ValueManager& ValMgr, const RValue& RHS) const; + RValue EvalMul(ValueManager& ValMgr, const RValue& RHS) const; static RValue GetRValue(ValueManager& ValMgr, IntegerLiteral* S); @@ -225,9 +230,16 @@ public: return APSIntSetTy(reinterpret_cast(getRawPtr())); } - RValueMayEqualSet Add(ValueManager& ValMgr, const RValueMayEqualSet& V) const; - RValueMayEqualSet Sub(ValueManager& ValMgr, const RValueMayEqualSet& V) const; - RValueMayEqualSet Mul(ValueManager& ValMgr, const RValueMayEqualSet& V) const; + RValueMayEqualSet EvalAdd(ValueManager& ValMgr, + const RValueMayEqualSet& V) const; + + RValueMayEqualSet EvalSub(ValueManager& ValMgr, + const RValueMayEqualSet& V) const; + + RValueMayEqualSet EvalMul(ValueManager& ValMgr, + const RValueMayEqualSet& V) const; + + RValueMayEqualSet EvalCast(ValueManager& ValMgr, Expr* CastExpr) const; // Implement isa support. static inline bool classof(const ExprValue* V) { @@ -237,12 +249,43 @@ public: } // end anonymous namespace //===----------------------------------------------------------------------===// -// "R-Values": Implementation. +// Transfer functions: Casts. +//===----------------------------------------------------------------------===// + +ExprValue ExprValue::EvalCast(ValueManager& ValMgr, Expr* CastExpr) const { + switch (getKind()) { + case RValueMayEqualSetKind: + return cast(this)->EvalCast(ValMgr, CastExpr); + default: + return InvalidValue(); + } +} + +RValueMayEqualSet +RValueMayEqualSet::EvalCast(ValueManager& ValMgr, Expr* CastExpr) const { + QualType T = CastExpr->getType(); + assert (T->isIntegerType()); + + APSIntSetTy S1 = GetValues(); + APSIntSetTy S2 = ValMgr.GetEmptyAPSIntSet(); + + for (APSIntSetTy::iterator I=S1.begin(), E=S1.end(); I!=E; ++I) { + llvm::APSInt X = *I; + X.setIsSigned(T->isSignedIntegerType()); + X.extOrTrunc(ValMgr.getContext()->getTypeSize(T,CastExpr->getLocStart())); + S2 = ValMgr.AddToSet(S2, X); + } + + return S2; +} + +//===----------------------------------------------------------------------===// +// Transfer functions: Binary Operations over R-Values. //===----------------------------------------------------------------------===// #define RVALUE_DISPATCH_CASE(k1,k2,Op)\ case ((k1##Kind+(MaxRValueKind-MinRValueKind))+(k2##Kind - MinRValueKind)):\ - return cast(*this).Op(ValMgr,cast(RHS)); + return cast(*this).Eval##Op(ValMgr,cast(RHS)); #define RVALUE_DISPATCH(Op)\ switch (getKind()+(MaxRValueKind-MinRValueKind)+(RHS.getKind()-MinRValueKind)){\ @@ -253,15 +296,15 @@ switch (getKind()+(MaxRValueKind-MinRValueKind)+(RHS.getKind()-MinRValueKind)){\ }\ return cast(InvalidValue()); -RValue RValue::Add(ValueManager& ValMgr, const RValue& RHS) const { +RValue RValue::EvalAdd(ValueManager& ValMgr, const RValue& RHS) const { RVALUE_DISPATCH(Add) } -RValue RValue::Sub(ValueManager& ValMgr, const RValue& RHS) const { +RValue RValue::EvalSub(ValueManager& ValMgr, const RValue& RHS) const { RVALUE_DISPATCH(Sub) } -RValue RValue::Mul(ValueManager& ValMgr, const RValue& RHS) const { +RValue RValue::EvalMul(ValueManager& ValMgr, const RValue& RHS) const { RVALUE_DISPATCH(Mul) } @@ -269,8 +312,8 @@ RValue RValue::Mul(ValueManager& ValMgr, const RValue& RHS) const { #undef RVALUE_DISPATCH RValueMayEqualSet -RValueMayEqualSet::Add(ValueManager& ValMgr, - const RValueMayEqualSet& RHS) const { +RValueMayEqualSet::EvalAdd(ValueManager& ValMgr, + const RValueMayEqualSet& RHS) const { APSIntSetTy S1 = GetValues(); APSIntSetTy S2 = RHS.GetValues(); @@ -285,8 +328,8 @@ RValueMayEqualSet::Add(ValueManager& ValMgr, } RValueMayEqualSet -RValueMayEqualSet::Sub(ValueManager& ValMgr, - const RValueMayEqualSet& RHS) const { +RValueMayEqualSet::EvalSub(ValueManager& ValMgr, + const RValueMayEqualSet& RHS) const { APSIntSetTy S1 = GetValues(); APSIntSetTy S2 = RHS.GetValues(); @@ -301,8 +344,8 @@ RValueMayEqualSet::Sub(ValueManager& ValMgr, } RValueMayEqualSet -RValueMayEqualSet::Mul(ValueManager& ValMgr, - const RValueMayEqualSet& RHS) const { +RValueMayEqualSet::EvalMul(ValueManager& ValMgr, + const RValueMayEqualSet& RHS) const { APSIntSetTy S1 = GetValues(); APSIntSetTy S2 = RHS.GetValues(); @@ -473,8 +516,9 @@ public: /// Initialize - Initialize the checker's state based on the specified /// CFG. This results in liveness information being computed for /// each block-level statement in the CFG. - void Initialize(CFG& c) { - cfg = &c; + void Initialize(CFG& c, ASTContext& ctx) { + cfg = &c; + ValMgr.setContext(&ctx); Liveness = new LiveVariables(c); Liveness->runOnCFG(c); Liveness->runOnAllBlocks(c, NULL, true); @@ -510,6 +554,9 @@ public: /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst); + + /// VisitCast - Transfer function logic for all casts (implicit and explicit). + void VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst); /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); @@ -566,6 +613,24 @@ ExprValue GRConstants::GetValue(const StateTy& St, Stmt* S) { case Stmt::IntegerLiteralClass: return RValue::GetRValue(ValMgr, cast(S)); + + case Stmt::ImplicitCastExprClass: { + ImplicitCastExpr* C = cast(S); + if (C->getType() == C->getSubExpr()->getType()) { + S = C->getSubExpr(); + continue; + } + break; + } + + case Stmt::CastExprClass: { + CastExpr* C = cast(S); + if (C->getType() == C->getSubExpr()->getType()) { + S = C->getSubExpr(); + continue; + } + break; + } default: break; @@ -575,6 +640,7 @@ ExprValue GRConstants::GetValue(const StateTy& St, Stmt* S) { } StateTy::TreeTy* T = St.SlimFind(ValueKey(S, getCFG().isBlkExpr(S))); + return T ? T->getValue().second : InvalidValue(); } @@ -654,6 +720,28 @@ void GRConstants::Nodify(NodeSet& Dst, Stmt* S, GRConstants::NodeTy* Pred, Dst.Add(Builder->generateNode(S, St, Pred)); } +void GRConstants::VisitCast(Expr* CastE, Expr* E, GRConstants::NodeTy* Pred, + GRConstants::NodeSet& Dst) { + + QualType T = CastE->getType(); + + // Check for redundant casts. + if (E->getType() == T) { + Dst.Add(Pred); + return; + } + + NodeSet S1; + Visit(E, Pred, S1); + + for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { + NodeTy* N = *I1; + StateTy St = N->getState(); + const ExprValue& V = GetValue(St, E); + Nodify(Dst, CastE, N, SetValue(St, CastE, V.EvalCast(ValMgr, CastE))); + } + } + void GRConstants::VisitBinaryOperator(BinaryOperator* B, GRConstants::NodeTy* Pred, GRConstants::NodeSet& Dst) { @@ -684,21 +772,21 @@ void GRConstants::VisitBinaryOperator(BinaryOperator* B, const RValue& R1 = cast(V1); const RValue& R2 = cast(V2); - Nodify(Dst, B, N2, SetValue(St, B, R1.Add(ValMgr, R2))); + Nodify(Dst, B, N2, SetValue(St, B, R1.EvalAdd(ValMgr, R2))); break; } case BinaryOperator::Sub: { const RValue& R1 = cast(V1); const RValue& R2 = cast(V2); - Nodify(Dst, B, N2, SetValue(St, B, R1.Sub(ValMgr, R2))); + Nodify(Dst, B, N2, SetValue(St, B, R1.EvalSub(ValMgr, R2))); break; } case BinaryOperator::Mul: { const RValue& R1 = cast(V1); const RValue& R2 = cast(V2); - Nodify(Dst, B, N2, SetValue(St, B, R1.Mul(ValMgr, R2))); + Nodify(Dst, B, N2, SetValue(St, B, R1.EvalMul(ValMgr, R2))); break; } @@ -712,7 +800,7 @@ void GRConstants::VisitBinaryOperator(BinaryOperator* B, case BinaryOperator::AddAssign: { const LValue& L1 = cast(V1); RValue R1 = cast(GetValue(N1->getState(), L1)); - RValue Result = R1.Add(ValMgr, cast(V2)); + RValue Result = R1.EvalAdd(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } @@ -720,7 +808,7 @@ void GRConstants::VisitBinaryOperator(BinaryOperator* B, case BinaryOperator::SubAssign: { const LValue& L1 = cast(V1); RValue R1 = cast(GetValue(N1->getState(), L1)); - RValue Result = R1.Sub(ValMgr, cast(V2)); + RValue Result = R1.EvalSub(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } @@ -728,7 +816,7 @@ void GRConstants::VisitBinaryOperator(BinaryOperator* B, case BinaryOperator::MulAssign: { const LValue& L1 = cast(V1); RValue R1 = cast(GetValue(N1->getState(), L1)); - RValue Result = R1.Mul(ValMgr, cast(V2)); + RValue Result = R1.EvalMul(ValMgr, cast(V2)); Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); break; } @@ -764,6 +852,18 @@ void GRConstants::Visit(Stmt* S, GRConstants::NodeTy* Pred, Visit(cast(S)->getSubExpr(), Pred, Dst); break; + case Stmt::ImplicitCastExprClass: { + ImplicitCastExpr* C = cast(S); + VisitCast(C, C->getSubExpr(), Pred, Dst); + break; + } + + case Stmt::CastExprClass: { + CastExpr* C = cast(S); + VisitCast(C, C->getSubExpr(), Pred, Dst); + break; + } + default: Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; @@ -867,8 +967,8 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : #endif namespace clang { -void RunGRConstants(CFG& cfg) { - GREngine Engine(cfg); +void RunGRConstants(CFG& cfg, ASTContext& Ctx) { + GREngine Engine(cfg, Ctx); Engine.ExecuteWorkList(); #ifndef NDEBUG llvm::ViewGraph(*Engine.getGraph().roots_begin(),"GRConstants"); diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp index 5a5a039223..30c717fa50 100644 --- a/Driver/ASTConsumers.cpp +++ b/Driver/ASTConsumers.cpp @@ -567,16 +567,17 @@ ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) { namespace { class GRConstantsVisitor : public CFGVisitor { + ASTContext* Ctx; public: - virtual void Initialize(ASTContext &Context) {} + virtual void Initialize(ASTContext &Context) { Ctx = &Context; } virtual void VisitCFG(CFG& C) { - RunGRConstants(C); + RunGRConstants(C, *Ctx); } }; } // end anonymous namespace -ASTConsumer *clang::CreateGRConstants() { +ASTConsumer* clang::CreateGRConstants() { return new GRConstantsVisitor(); } diff --git a/include/clang/Analysis/Analyses/GRConstants.h b/include/clang/Analysis/Analyses/GRConstants.h index 7192bdc0b4..8da44b743d 100644 --- a/include/clang/Analysis/Analyses/GRConstants.h +++ b/include/clang/Analysis/Analyses/GRConstants.h @@ -23,7 +23,7 @@ namespace clang { /// on a provided CFG. This interface will eventually be replaced with /// something more elaborate as the requirements on the interface become /// clearer. - void RunGRConstants(CFG& cfg); + void RunGRConstants(CFG& cfg, ASTContext& Ctx); } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GREngine.h b/include/clang/Analysis/PathSensitive/GREngine.h index ad7f8824d2..5dcf6d7d0e 100644 --- a/include/clang/Analysis/PathSensitive/GREngine.h +++ b/include/clang/Analysis/PathSensitive/GREngine.h @@ -22,6 +22,7 @@ namespace clang { class CFG; +class ASTContext; class GRNodeBuilderImpl; class GRWorkList; @@ -195,10 +196,10 @@ protected: public: /// Construct a GREngine object to analyze the provided CFG using /// a DFS exploration of the exploded graph. - GREngine(CFG& cfg) + GREngine(CFG& cfg, ASTContext& Ctx) : GREngineImpl(cfg, new GraphTy(), GRWorkList::MakeDFS()), Checker(static_cast(G.get())->getCheckerState()) { - Checker->Initialize(cfg); + Checker->Initialize(cfg, Ctx); } /// Construct a GREngine object to analyze the provided CFG and to