diff options
author | Anna Zaks <ganna@apple.com> | 2012-08-09 18:43:00 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-08-09 18:43:00 +0000 |
commit | 5960f4aeac9760198c80e05d70d8dadb1db0ff0e (patch) | |
tree | c1a32c7620114c12cbf6e0e45f69f363db92ac21 | |
parent | 9cdd157912cf9987f1f4d1994e4a5bc44d8996d7 (diff) |
[analyzer] Improve readability of the dyn. dispatch bifurcation patch
r161552.
As per Jordan's feedback.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161603 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h | 20 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CallEvent.cpp | 10 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 43 |
3 files changed, 40 insertions, 33 deletions
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 67bc1423db..5e008bd976 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -68,15 +68,24 @@ public: } }; +/// \brief Defines the runtime definition of the called function. class RuntimeDefinition { + /// The Declaration of the function which will be called at runtime. + /// 0 if not available. const Decl *D; + + /// The region representing an object (ObjC/C++) on which the method is + /// called. With dynamic dispatch, the method definition depends on the + /// runtime type of this object. 0 when there is no dynamic dispatch. const MemRegion *R; + public: RuntimeDefinition(): D(0), R(0) {} RuntimeDefinition(const Decl *InD): D(InD), R(0) {} RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {} - const Decl *getDecl() { return D;} - const MemRegion *getReg() {return R;} + const Decl *getDecl() { return D; } + const MemRegion *getDispatchRegion() { return R; } + bool mayHaveOtherDefinitions() { return R != 0; } }; /// \brief Represents an abstract call to a function or method along a @@ -170,8 +179,7 @@ public: } /// \brief Returns the definition of the function or method that will be - /// called. Returns NULL if the definition cannot be found; ex: due to - /// dynamic dispatch in ObjC methods. + /// called. virtual RuntimeDefinition getRuntimeDefinition() const = 0; /// \brief Returns the expression whose value will be the result of this call. @@ -351,7 +359,7 @@ public: const FunctionDecl *FD = getDecl(); // Note that hasBody() will fill FD with the definition FunctionDecl. if (FD && FD->hasBody(FD)) - return RuntimeDefinition(FD, 0); + return RuntimeDefinition(FD); return RuntimeDefinition(); } @@ -557,7 +565,7 @@ public: } virtual RuntimeDefinition getRuntimeDefinition() const { - return RuntimeDefinition(getBlockDecl(), 0); + return RuntimeDefinition(getBlockDecl()); } virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 8b96035aa4..13bdaa729b 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -389,7 +389,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); if (!MD->isVirtual()) - return RuntimeDefinition(MD, 0); + return RuntimeDefinition(MD); // If the method is virtual, see if we can find the actual implementation // based on context-sensitivity. @@ -398,7 +398,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // because a /partially/ constructed object can be referred to through a // base pointer. We'll eventually want to use DynamicTypeInfo here. if (const CXXMethodDecl *Devirtualized = devirtualize(MD, getCXXThisVal())) - return RuntimeDefinition(Devirtualized, 0); + return RuntimeDefinition(Devirtualized); return RuntimeDefinition(); } @@ -519,7 +519,7 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); if (!MD->isVirtual()) - return RuntimeDefinition(MD, 0); + return RuntimeDefinition(MD); // If the method is virtual, see if we can find the actual implementation // based on context-sensitivity. @@ -528,7 +528,7 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { // because a /partially/ constructed object can be referred to through a // base pointer. We'll eventually want to use DynamicTypeInfo here. if (const CXXMethodDecl *Devirtualized = devirtualize(MD, getCXXThisVal())) - return RuntimeDefinition(Devirtualized, 0); + return RuntimeDefinition(Devirtualized); return RuntimeDefinition(); } @@ -695,7 +695,7 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { // class name. if (ObjCInterfaceDecl *IDecl = E->getReceiverInterface()) { // Find/Return the method implementation. - return RuntimeDefinition(IDecl->lookupPrivateClassMethod(Sel), 0); + return RuntimeDefinition(IDecl->lookupPrivateClassMethod(Sel)); } } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index d3d097c53f..2b0ac1d967 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -534,6 +534,10 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State = Pred->getState(); CallEventRef<> Call = CallTemplate.cloneWithState(State); + if (!getAnalysisManager().shouldInlineCall()) { + conservativeEvalCall(*Call, Bldr, Pred, State); + return; + } // Try to inline the call. // The origin expression here is just used as a kind of checksum; // this should still be safe even for CallEvents that don't come from exprs. @@ -543,21 +547,19 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, if (InlinedFailedState) { // If we already tried once and failed, make sure we don't retry later. State = InlinedFailedState; - } else if (getAnalysisManager().shouldInlineCall()) { + } else { RuntimeDefinition RD = Call->getRuntimeDefinition(); const Decl *D = RD.getDecl(); if (D) { // Explore with and without inlining the call. - const MemRegion *BifurReg = RD.getReg(); - if (BifurReg && + if (RD.mayHaveOtherDefinitions() && getAnalysisManager().IPAMode == DynamicDispatchBifurcate) { - BifurcateCall(BifurReg, *Call, D, Bldr, Pred); + BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred); return; - } else { - // We are not bifurcating and we do have a Decl, so just inline. - if (inlineCall(*Call, D, Bldr, Pred, State)) - return; } + // We are not bifurcating and we do have a Decl, so just inline. + if (inlineCall(*Call, D, Bldr, Pred, State)) + return; } } @@ -573,20 +575,17 @@ void ExprEngine::BifurcateCall(const MemRegion *BifurReg, // Check if we've performed the split already - note, we only want // to split the path once per memory region. ProgramStateRef State = Pred->getState(); - DynamicDispatchBifur BM = State->get<DynamicDispatchBifurcationMap>(); - for (DynamicDispatchBifur::iterator I = BM.begin(), - E = BM.end(); I != E; ++I) { - if (I->first == BifurReg) { - // If we are on "inline path", keep inlining if possible. - if (I->second == true) - if (inlineCall(Call, D, Bldr, Pred, State)) - return; - // If inline failed, or we are on the path where we assume we - // don't have enough info about the receiver to inline, conjure the - // return value and invalidate the regions. - conservativeEvalCall(Call, Bldr, Pred, State); - return; - } + const int *BState = State->get<DynamicDispatchBifurcationMap>(BifurReg); + if (BState) { + // If we are on "inline path", keep inlining if possible. + if (*BState == true) + if (inlineCall(Call, D, Bldr, Pred, State)) + return; + // If inline failed, or we are on the path where we assume we + // don't have enough info about the receiver to inline, conjure the + // return value and invalidate the regions. + conservativeEvalCall(Call, Bldr, Pred, State); + return; } // If we got here, this is the first time we process a message to this |