aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-08-09 18:43:00 +0000
committerAnna Zaks <ganna@apple.com>2012-08-09 18:43:00 +0000
commit5960f4aeac9760198c80e05d70d8dadb1db0ff0e (patch)
treec1a32c7620114c12cbf6e0e45f69f363db92ac21
parent9cdd157912cf9987f1f4d1994e4a5bc44d8996d7 (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.h20
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp10
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp43
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