From c6238d2786cfd961b94580b3d3675a1b3ff0721c Mon Sep 17 00:00:00 2001 From: Zhongxing Xu Date: Mon, 19 Jul 2010 01:31:21 +0000 Subject: [PATCH] Reapply r108617. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108668 91177308-0d34-0410-b5e6-96231b3b80d8 --- examples/wpa/clang-wpa.cpp | 4 +- include/clang/Analysis/AnalysisContext.h | 21 ++++++-- include/clang/Analysis/ProgramPoint.h | 12 +++-- .../Checker/PathSensitive/AnalysisManager.h | 37 +++++++++++-- .../Checker/PathSensitive/GRCoreEngine.h | 10 ++-- lib/Analysis/AnalysisContext.cpp | 5 +- lib/Checker/AnalysisConsumer.cpp | 3 +- lib/Checker/AnalysisManager.cpp | 31 +++++++++++ lib/Checker/CMakeLists.txt | 2 +- lib/Checker/CallInliner.cpp | 54 ------------------- lib/Checker/GRCXXExprEngine.cpp | 4 +- lib/Checker/GRCoreEngine.cpp | 10 +++- lib/Checker/GRExprEngine.cpp | 39 +++++++++----- tools/driver/Makefile | 4 +- 14 files changed, 138 insertions(+), 98 deletions(-) create mode 100644 lib/Checker/AnalysisManager.cpp diff --git a/examples/wpa/clang-wpa.cpp b/examples/wpa/clang-wpa.cpp index 74ec368cfb..1caa3b9b68 100644 --- a/examples/wpa/clang-wpa.cpp +++ b/examples/wpa/clang-wpa.cpp @@ -129,7 +129,7 @@ int main(int argc, char **argv) { AnalysisManager AMgr(TU->getASTContext(), PP.getDiagnostics(), PP.getLangOptions(), /* PathDiagnostic */ 0, CreateRegionStoreManager, - CreateRangeConstraintManager, + CreateRangeConstraintManager, &Idxer, /* MaxNodes */ 300000, /* MaxLoop */ 3, /* VisualizeEG */ false, /* VisualizeEGUbi */ false, /* PurgeDead */ true, /* EagerlyAssume */ false, @@ -139,7 +139,7 @@ int main(int argc, char **argv) { AMgr.getLangOptions()); GRExprEngine Eng(AMgr, TF); - Eng.ExecuteWorkList(AMgr.getStackFrame(FD), AMgr.getMaxNodes()); + Eng.ExecuteWorkList(AMgr.getStackFrame(FD, TU), AMgr.getMaxNodes()); return 0; } diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index 9ebd93b75b..584173a33f 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -34,11 +34,16 @@ class ImplicitParamDecl; class LocationContextManager; class StackFrameContext; +namespace idx { class TranslationUnit; } + /// AnalysisContext contains the context data for the function or method under /// analysis. class AnalysisContext { const Decl *D; + // TranslationUnit is NULL if we don't have multiple translation units. + const idx::TranslationUnit *TU; + // AnalysisContext owns the following data. CFG *cfg; bool builtCFG; @@ -48,14 +53,18 @@ class AnalysisContext { llvm::BumpPtrAllocator A; bool AddEHEdges; public: - AnalysisContext(const Decl *d, bool addehedges = false) - : D(d), cfg(0), builtCFG(false), liveness(0), PM(0), + AnalysisContext(const Decl *d, const idx::TranslationUnit *tu, + bool addehedges = false) + : D(d), TU(tu), cfg(0), builtCFG(false), liveness(0), PM(0), ReferencedBlockVars(0), AddEHEdges(addehedges) {} ~AnalysisContext(); ASTContext &getASTContext() { return D->getASTContext(); } - const Decl *getDecl() { return D; } + const Decl *getDecl() const { return D; } + + const 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 /// reachable from them can appear to be dead in the CFG, analysis passes must @@ -82,7 +91,7 @@ class AnalysisContextManager { public: ~AnalysisContextManager(); - AnalysisContext *getContext(const Decl *D); + AnalysisContext *getContext(const Decl *D,const idx::TranslationUnit *TU = 0); // Discard all previously created AnalysisContexts. void clear(); @@ -109,6 +118,10 @@ public: AnalysisContext *getAnalysisContext() const { return Ctx; } + const idx::TranslationUnit *getTranslationUnit() const { + return Ctx->getTranslationUnit(); + } + const LocationContext *getParent() const { return Parent; } bool isParentOf(const LocationContext *LC) const; diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 075838d45e..24bbf22640 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT #define LLVM_CLANG_ANALYSIS_PROGRAM_POINT +#include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "llvm/System/DataTypes.h" #include "llvm/ADT/DenseMap.h" @@ -26,6 +27,7 @@ namespace clang { class LocationContext; +class AnalysisContext; class FunctionDecl; class ProgramPoint { @@ -313,16 +315,16 @@ public: class CallEnter : public StmtPoint { public: - // CallEnter uses the caller's location context. - CallEnter(const Stmt *S, const FunctionDecl *fd, const LocationContext *L) - : StmtPoint(S, fd, CallEnterKind, L, 0) {} + // L is caller's location context. AC is callee's AnalysisContext. + CallEnter(const Stmt *S, const AnalysisContext *AC, const LocationContext *L) + : StmtPoint(S, AC, CallEnterKind, L, 0) {} const Stmt *getCallExpr() const { return static_cast(getData1()); } - const FunctionDecl *getCallee() const { - return static_cast(getData2()); + const AnalysisContext *getCalleeContext() const { + return static_cast(getData2()); } static bool classof(const ProgramPoint *Location) { diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h index 3c7cb68c09..3f673618cf 100644 --- a/include/clang/Checker/PathSensitive/AnalysisManager.h +++ b/include/clang/Checker/PathSensitive/AnalysisManager.h @@ -21,6 +21,11 @@ namespace clang { +namespace idx { + class Indexer; + class TranslationUnit; +} + class AnalysisManager : public BugReporterData { AnalysisContextManager AnaCtxMgr; LocationContextManager LocCtxMgr; @@ -35,6 +40,11 @@ class AnalysisManager : public BugReporterData { StoreManagerCreator CreateStoreMgr; ConstraintManagerCreator CreateConstraintMgr; + /// \brief Provide function definitions in other translation units. This is + /// NULL if we don't have multiple translation units. AnalysisManager does + /// not own the Indexer. + idx::Indexer *Idxer; + enum AnalysisScope { ScopeTU, ScopeDecl } AScope; // The maximum number of exploded nodes the analyzer will generate. @@ -62,13 +72,14 @@ public: AnalysisManager(ASTContext &ctx, Diagnostic &diags, const LangOptions &lang, PathDiagnosticClient *pd, StoreManagerCreator storemgr, - ConstraintManagerCreator constraintmgr, unsigned maxnodes, - unsigned maxloop, + ConstraintManagerCreator constraintmgr, + idx::Indexer *idxer, + unsigned maxnodes, unsigned maxloop, bool vizdot, bool vizubi, bool purge, bool eager, bool trim, bool inlinecall) : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd), - CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),Idxer(idxer), AScope(ScopeDecl), MaxNodes(maxnodes), MaxLoop(maxloop), VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall) {} @@ -133,6 +144,10 @@ public: bool shouldInlineCall() const { return InlineCall; } + bool hasIndexer() const { return Idxer != 0; } + + const AnalysisContext *getAnalysisContextInAnotherTU(const Decl *D); + CFG *getCFG(Decl const *D) { return AnaCtxMgr.getContext(D)->getCFG(); } @@ -145,9 +160,21 @@ public: return AnaCtxMgr.getContext(D)->getParentMap(); } + const AnalysisContext *getAnalysisContext(const Decl *D) { + return AnaCtxMgr.getContext(D); + } + + const StackFrameContext *getStackFrame(AnalysisContext *Ctx, + LocationContext const *Parent, + Stmt const *S, const CFGBlock *Blk, + unsigned Idx) { + return LocCtxMgr.getStackFrame(Ctx, Parent, S, Blk, Idx); + } + // Get the top level stack frame. - const StackFrameContext *getStackFrame(Decl const *D) { - return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0, 0, 0); + const StackFrameContext *getStackFrame(Decl const *D, + const idx::TranslationUnit *TU) { + return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D, TU), 0, 0, 0, 0); } // Get a stack frame with parent. diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h index 7f101dca97..317558e962 100644 --- a/include/clang/Checker/PathSensitive/GRCoreEngine.h +++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h @@ -442,8 +442,8 @@ class GRCallEnterNodeBuilder { // The call site. const Stmt *CE; - // The definition of callee. - const FunctionDecl *FD; + // The AnalysisContext of the callee. + const AnalysisContext *CalleeCtx; // The parent block of the CallExpr. const CFGBlock *Block; @@ -453,9 +453,9 @@ class GRCallEnterNodeBuilder { public: GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred, - const Stmt *s, const FunctionDecl *fd, + const Stmt *s, const AnalysisContext *callee, const CFGBlock *blk, unsigned idx) - : Eng(eng), Pred(pred), CE(s), FD(fd), Block(blk), Index(idx) {} + : Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {} const GRState *getState() const { return Pred->getState(); } @@ -465,7 +465,7 @@ public: const Stmt *getCallExpr() const { return CE; } - const FunctionDecl *getCallee() const { return FD; } + const AnalysisContext *getCalleeContext() const { return CalleeCtx; } const CFGBlock *getBlock() const { return Block; } diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 06d8aec391..538d559c16 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -83,10 +83,11 @@ LiveVariables *AnalysisContext::getLiveVariables() { return liveness; } -AnalysisContext *AnalysisContextManager::getContext(const Decl *D) { +AnalysisContext *AnalysisContextManager::getContext(const Decl *D, + const idx::TranslationUnit *TU) { AnalysisContext *&AC = Contexts[D]; if (!AC) - AC = new AnalysisContext(D); + AC = new AnalysisContext(D, TU); return AC; } diff --git a/lib/Checker/AnalysisConsumer.cpp b/lib/Checker/AnalysisConsumer.cpp index 6c7a294b1d..bbeca312f0 100644 --- a/lib/Checker/AnalysisConsumer.cpp +++ b/lib/Checker/AnalysisConsumer.cpp @@ -173,6 +173,7 @@ public: Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, + /* Indexer */ 0, Opts.MaxNodes, Opts.MaxLoop, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.PurgeDead, Opts.EagerlyAssume, @@ -349,7 +350,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, } // Execute the worklist algorithm. - Eng.ExecuteWorkList(mgr.getStackFrame(D), mgr.getMaxNodes()); + Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes()); // Release the auditor (if any) so that it doesn't monitor the graph // created BugReporter. diff --git a/lib/Checker/AnalysisManager.cpp b/lib/Checker/AnalysisManager.cpp new file mode 100644 index 0000000000..339cdab80b --- /dev/null +++ b/lib/Checker/AnalysisManager.cpp @@ -0,0 +1,31 @@ +//===-- AnalysisManager.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Index/Entity.h" +#include "clang/Index/Indexer.h" + +using namespace clang; + +const AnalysisContext * +AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) { + idx::Entity Ent = idx::Entity::get(const_cast(D), + Idxer->getProgram()); + FunctionDecl *FuncDef; + idx::TranslationUnit *TU; + llvm::tie(FuncDef, TU) = Idxer->getDefinitionFor(Ent); + + if (FuncDef == 0) + return 0; + + // This AnalysisContext wraps function definition in another translation unit. + // But it is still owned by the AnalysisManager associated with the current + // translation unit. + return AnaCtxMgr.getContext(FuncDef, TU); +} diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index 259346a970..c3dab22870 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangChecker AdjustedReturnValueChecker.cpp AggExprVisitor.cpp AnalysisConsumer.cpp + AnalysisManager.cpp ArrayBoundChecker.cpp AttrNonNullChecker.cpp BasicConstraintManager.cpp @@ -15,7 +16,6 @@ add_clang_library(clangChecker BuiltinFunctionChecker.cpp CFRefCount.cpp CallAndMessageChecker.cpp - CallInliner.cpp CastSizeChecker.cpp CastToStructChecker.cpp CheckDeadStores.cpp diff --git a/lib/Checker/CallInliner.cpp b/lib/Checker/CallInliner.cpp index c47e06c78f..e69de29bb2 100644 --- a/lib/Checker/CallInliner.cpp +++ b/lib/Checker/CallInliner.cpp @@ -1,54 +0,0 @@ -//===--- CallInliner.cpp - Transfer function that inlines callee ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the callee inlining transfer function. -// -//===----------------------------------------------------------------------===// - -#include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/Checkers/LocalCheckers.h" - -using namespace clang; - -namespace { -class CallInliner : public Checker { -public: - static void *getTag() { - static int x; - return &x; - } - - virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); -}; -} - -void clang::RegisterCallInliner(GRExprEngine &Eng) { - Eng.registerCheck(new CallInliner()); -} - -bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); - const Expr *Callee = CE->getCallee(); - SVal L = state->getSVal(Callee); - - const FunctionDecl *FD = L.getAsFunctionDecl(); - if (!FD) - return false; - - if (!FD->hasBody(FD)) - return false; - - // Now we have the definition of the callee, create a CallEnter node. - CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext()); - C.addTransition(state, Loc); - - return true; -} - diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp index 18e112cc8d..5c313318c1 100644 --- a/lib/Checker/GRCXXExprEngine.cpp +++ b/lib/Checker/GRCXXExprEngine.cpp @@ -104,7 +104,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); - CallEnter Loc(E, CD, Pred->getLocationContext()); + CallEnter Loc(E, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), NE = ArgsEvaluated.end(); NI != NE; ++NI) { const GRState *state = GetState(*NI); @@ -157,7 +157,7 @@ void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, Builder->getBlock(), Builder->getIndex()); const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, MD, Pred->getLocationContext()); + CallEnter Loc(MCE, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), E = AllArgsEvaluated.end(); I != E; ++I) { // Set up 'this' region. diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index a816186a30..df790e304a 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -227,8 +227,8 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, unsigned Index, ExplodedNode *Pred) { - GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), - Block, Index); + GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), + L.getCalleeContext(), Block, Index); ProcessCallEnter(Builder); } @@ -692,6 +692,12 @@ void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { void GRCallEnterNodeBuilder::GenerateNode(const GRState *state, const LocationContext *LocCtx) { + // Check if the callee is in the same translation unit. + if (CalleeCtx->getTranslationUnit() != + Pred->getLocationContext()->getTranslationUnit()) { + assert(0 && "to be implemented"); + } + // Get the callee entry block. const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry()); assert(Entry->empty()); diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 26b5801068..ce7b9d8d8e 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -1441,12 +1441,12 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { } void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { - const FunctionDecl *FD = B.getCallee(); - const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, - B.getLocationContext(), - B.getCallExpr(), - B.getBlock(), - B.getIndex()); + const StackFrameContext *LocCtx + = AMgr.getStackFrame(const_cast(B.getCalleeContext()), + B.getLocationContext(), + B.getCallExpr(), + B.getBlock(), + B.getIndex()); const GRState *state = B.getState(); state = getStoreManager().EnterStackFrame(state, LocCtx); @@ -1886,16 +1886,29 @@ bool GRExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, if (!FD) return false; - if (!FD->hasBody(FD)) - return false; + // Check if the function definition is in the same translation unit. + if (FD->hasBody(FD)) { + // Now we have the definition of the callee, create a CallEnter node. + CallEnter Loc(CE, AMgr.getAnalysisContext(FD), Pred->getLocationContext()); + + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + Dst.Add(N); + return true; + } - // Now we have the definition of the callee, create a CallEnter node. - CallEnter Loc(CE, FD, Pred->getLocationContext()); + // Check if we can find the function definition in other translation units. + if (AMgr.hasIndexer()) { + const AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD); + if (C == 0) + return false; - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - if (N) + CallEnter Loc(CE, C, Pred->getLocationContext()); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); Dst.Add(N); - return true; + return true; + } + + return false; } void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, diff --git a/tools/driver/Makefile b/tools/driver/Makefile index b8c91e8873..260f53fec9 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -28,8 +28,8 @@ include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \ ipo selectiondag USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \ - clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \ - clangParse.a clangLex.a clangBasic.a + clangChecker.a clangAnalysis.a clangIndex.a clangRewrite.a \ + clangAST.a clangParse.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile -- 2.40.0