return AST->getPreprocessor();
}
+ virtual Diagnostic &getDiagnostic() {
+ return AST->getDiagnostics();
+ }
+
virtual DeclReferenceMap &getDeclReferenceMap() {
return DeclRefMap;
}
const Decl *D;
// TranslationUnit is NULL if we don't have multiple translation units.
- const idx::TranslationUnit *TU;
+ idx::TranslationUnit *TU;
// AnalysisContext owns the following data.
CFG *cfg;
llvm::BumpPtrAllocator A;
bool AddEHEdges;
public:
- AnalysisContext(const Decl *d, const idx::TranslationUnit *tu,
+ AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
bool addehedges = false)
: D(d), TU(tu), cfg(0), builtCFG(false), liveness(0), PM(0),
ReferencedBlockVars(0), AddEHEdges(addehedges) {}
ASTContext &getASTContext() { return D->getASTContext(); }
const Decl *getDecl() const { return D; }
- const idx::TranslationUnit *getTranslationUnit() const { return TU; }
+ idx::TranslationUnit *getTranslationUnit() const { return TU; }
/// getAddEHEdges - Return true iff we are adding exceptional edges from
/// callExprs. If this is false, then try/catch statements and blocks
public:
~AnalysisContextManager();
- AnalysisContext *getContext(const Decl *D,const idx::TranslationUnit *TU = 0);
+ AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
// Discard all previously created AnalysisContexts.
void clear();
AnalysisContext *getAnalysisContext() const { return Ctx; }
- const idx::TranslationUnit *getTranslationUnit() const {
+ idx::TranslationUnit *getTranslationUnit() const {
return Ctx->getTranslationUnit();
}
return CreateConstraintMgr;
}
+ idx::Indexer *getIndexer() const { return Idxer; }
+
virtual ASTContext &getASTContext() {
return Ctx;
}
return AnaCtxMgr.getContext(D)->getParentMap();
}
- const AnalysisContext *getAnalysisContext(const Decl *D) {
+ AnalysisContext *getAnalysisContext(const Decl *D) {
return AnaCtxMgr.getContext(D);
}
+ AnalysisContext *getAnalysisContext(const Decl *D, idx::TranslationUnit *TU) {
+ return AnaCtxMgr.getContext(D, TU);
+ }
+
const StackFrameContext *getStackFrame(AnalysisContext *Ctx,
LocationContext const *Parent,
Stmt const *S, const CFGBlock *Blk,
// Get the top level stack frame.
const StackFrameContext *getStackFrame(Decl const *D,
- const idx::TranslationUnit *TU) {
+ idx::TranslationUnit *TU) {
return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D, TU), 0, 0, 0, 0);
}
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of
/// steps. Returns true if there is still simulation state on the worklist.
- bool ExecuteWorkList(const LocationContext *L, unsigned Steps);
+ bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
+ const GRState *InitState);
+ void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+ const GRState *InitState,
+ ExplodedNodeSet &Dst);
};
class GRStmtNodeBuilder {
~GRExprEngine();
void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
- CoreEngine.ExecuteWorkList(L, Steps);
+ CoreEngine.ExecuteWorkList(L, Steps, 0);
+ }
+
+ /// Execute the work list with an initial state. Nodes that reaches the exit
+ /// of the function are added into the Dst set, which represent the exit
+ /// state of the function call.
+ void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+ const GRState *InitState,
+ ExplodedNodeSet &Dst) {
+ CoreEngine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
}
/// getContext - Return the ASTContext associated with this analysis.
ASTContext& getContext() const { return AMgr.getASTContext(); }
- AnalysisManager &getAnalysisManager() const { return AMgr; }
+ virtual AnalysisManager &getAnalysisManager() { return AMgr; }
SValuator &getSValuator() { return SVator; }
/// making assumptions about state values.
const GRState *ProcessAssume(const GRState *state, SVal cond,bool assumption);
- GRStateManager& getStateManager() { return StateMgr; }
- const GRStateManager& getStateManager() const { return StateMgr; }
+ virtual GRStateManager& getStateManager() { return StateMgr; }
StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
const StackFrameContext *LCtx,
SymbolReaper& SymReaper);
+ /// Marshal a new state for the callee in another translation unit.
+ /// 'state' is owned by the caller's engine.
+ const GRState *MarshalState(const GRState *state, const LocationContext *L);
+
public:
SVal ArrayToPointer(Loc Array) {
virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
- virtual GRStateManager& getStateManager() = 0;
+ virtual AnalysisManager &getAnalysisManager() = 0;
+
+ virtual GRStateManager &getStateManager() = 0;
/// Called by GRCoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
namespace clang {
class ASTContext;
+ class Diagnostic;
class Preprocessor;
namespace idx {
virtual ~TranslationUnit();
virtual ASTContext &getASTContext() = 0;
virtual Preprocessor &getPreprocessor() = 0;
+ virtual Diagnostic &getDiagnostic() = 0;
virtual DeclReferenceMap &getDeclReferenceMap() = 0;
virtual SelectorMap &getSelectorMap() = 0;
};
}
AnalysisContext *AnalysisContextManager::getContext(const Decl *D,
- const idx::TranslationUnit *TU) {
+ idx::TranslationUnit *TU) {
AnalysisContext *&AC = Contexts[D];
if (!AC)
AC = new AnalysisContext(D, TU);
//
//===----------------------------------------------------------------------===//
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
#include "clang/Checker/PathSensitive/GRCoreEngine.h"
#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Index/TranslationUnit.h"
#include "clang/AST/Expr.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
using llvm::isa;
using namespace clang;
+// This should be removed in the future.
+namespace clang {
+GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+ const LangOptions& lopts);
+}
+
//===----------------------------------------------------------------------===//
// Worklist classes for exploration of reachable states.
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
-bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
+bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
+ const GRState *InitState) {
if (G->num_roots() == 0) { // Initialize the analysis by constructing
// the root if none exists.
// Set the current block counter to being empty.
WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
- // Generate the root.
- GenerateNode(StartLoc, getInitialState(L), 0);
+ if (!InitState)
+ // Generate the root.
+ GenerateNode(StartLoc, getInitialState(L), 0);
+ else
+ GenerateNode(StartLoc, InitState, 0);
}
while (Steps && WList->hasWork()) {
return WList->hasWork();
}
+void GRCoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
+ unsigned Steps,
+ const GRState *InitState,
+ ExplodedNodeSet &Dst) {
+ ExecuteWorkList(L, Steps, InitState);
+ for (llvm::SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(),
+ E = G->EndNodes.end(); I != E; ++I) {
+ Dst.Add(*I);
+ }
+}
+
void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
unsigned Index, ExplodedNode *Pred) {
GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(),
// Check if the callee is in the same translation unit.
if (CalleeCtx->getTranslationUnit() !=
Pred->getLocationContext()->getTranslationUnit()) {
- assert(0 && "to be implemented");
+ // Create a new engine. We must be careful that the new engine should not
+ // reference data structures owned by the old engine.
+
+ AnalysisManager &OldMgr = Eng.SubEngine.getAnalysisManager();
+
+ // Get the callee's translation unit.
+ idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit();
+
+ // Create a new AnalysisManager with components of the callee's
+ // TranslationUnit.
+ // The Diagnostic is actually shared when we create ASTUnits from PCH files.
+ AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(),
+ OldMgr.getLangOptions(),
+ OldMgr.getPathDiagnosticClient(),
+ OldMgr.getStoreManagerCreator(),
+ OldMgr.getConstraintManagerCreator(),
+ OldMgr.getIndexer(),
+ OldMgr.getMaxNodes(), OldMgr.getMaxLoop(),
+ OldMgr.shouldVisualizeGraphviz(),
+ OldMgr.shouldVisualizeUbigraph(),
+ OldMgr.shouldPurgeDead(),
+ OldMgr.shouldEagerlyAssume(),
+ OldMgr.shouldTrimGraph(),
+ OldMgr.shouldInlineCall());
+ llvm::OwningPtr<GRTransferFuncs> TF(MakeCFRefCountTF(AMgr.getASTContext(),
+ /* GCEnabled */ false,
+ AMgr.getLangOptions()));
+ // Create the new engine.
+ GRExprEngine NewEng(AMgr, TF.take());
+
+ // Create the new LocationContext.
+ AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(),
+ CalleeCtx->getTranslationUnit());
+ const StackFrameContext *OldLocCtx = cast<StackFrameContext>(LocCtx);
+ const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx,
+ OldLocCtx->getParent(),
+ OldLocCtx->getCallSite(),
+ OldLocCtx->getCallSiteBlock(),
+ OldLocCtx->getIndex());
+
+ // Now create an initial state for the new engine.
+ const GRState *NewState = NewEng.getStateManager().MarshalState(state,
+ NewLocCtx);
+ ExplodedNodeSet ReturnNodes;
+ NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(),
+ NewState, ReturnNodes);
+ return;
}
// Get the callee entry block.
return ConstraintMgr->RemoveDeadBindings(s, SymReaper);
}
+const GRState *GRStateManager::MarshalState(const GRState *state,
+ const LocationContext *InitLoc) {
+ // make up an empty state for now.
+ GRState State(this,
+ EnvMgr.getInitialEnvironment(),
+ StoreMgr->getInitialStore(InitLoc),
+ GDMFactory.GetEmptyMap());
+
+ return getPersistentState(State);
+}
+
const GRState *GRState::unbindLoc(Loc LV) const {
Store OldStore = getStore();
Store NewStore = getStateManager().StoreMgr->Remove(OldStore, LV);