[cfe-commits] r138309 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h lib/StaticAnalyzer/Core/CFRefCount.cpp
Jordy Rose
jediknil at belkadan.com
Mon Aug 22 16:48:23 PDT 2011
Author: jrose
Date: Mon Aug 22 18:48:23 2011
New Revision: 138309
URL: http://llvm.org/viewvc/llvm-project?rev=138309&view=rev
Log:
[analyzer] Migrate the handling of retain-count-related RetEffects and ArgEffects from CFRefCount to RetainReleaseChecker. No intended functionality change.
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h?rev=138309&r1=138308&r2=138309&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h Mon Aug 22 18:48:23 2011
@@ -186,6 +186,12 @@
bool isCXXCall() const {
return CallE && isa<CXXMemberCallExpr>(CallE);
}
+
+ const Expr *getOriginExpr() const {
+ if (isFunctionCall())
+ return CallE;
+ return Msg.getOriginExpr();
+ }
SVal getFunctionCallee() const;
SVal getCXXCallee() const;
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp?rev=138309&r1=138308&r2=138309&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp Mon Aug 22 18:48:23 2011
@@ -1633,15 +1633,6 @@
ArgEffect E,
RefVal::Kind& hasErr);
- void ProcessNonLeakError(ExplodedNodeSet &Dst,
- StmtNodeBuilder& Builder,
- const Expr *NodeExpr,
- SourceRange ErrorRange,
- ExplodedNode *Pred,
- const ProgramState *St,
- RefVal::Kind hasErr,
- SymbolRef Sym);
-
const ProgramState *HandleSymbolDeath(const ProgramState * state,
SymbolRef sid,
RefVal V,
@@ -2547,11 +2538,6 @@
ExplodedNode *Pred,
const ProgramState *state) {
- // Evaluate the effect of the arguments.
- RefVal::Kind hasErr = (RefVal::Kind) 0;
- SourceRange ErrorRange;
- SymbolRef ErrorSym = 0;
-
SmallVector<const MemRegion*, 10> RegionsToInvalidate;
// Use RAII to make sure the whitelist is properly cleared.
@@ -2579,80 +2565,62 @@
for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx);
- SymbolRef Sym = V.getAsLocSymbol();
- if (Sym)
- if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) {
- WhitelistedSymbols.insert(Sym);
- state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
- if (hasErr) {
- ErrorRange = callOrMsg.getArgSourceRange(idx);
- ErrorSym = Sym;
- break;
- }
- }
+ // If we are passing a location wrapped as an integer, unwrap it and
+ // invalidate the values referred by the location.
+ if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
+ V = Wrapped->getLoc();
+ else if (!isa<Loc>(V))
+ continue;
- tryAgain:
- if (isa<Loc>(V)) {
- if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
- if (Summ.getArg(idx) == DoNothingByRef)
- continue;
+ if (SymbolRef Sym = V.getAsLocSymbol())
+ if (state->get<RefBindings>(Sym))
+ WhitelistedSymbols.insert(Sym);
- // Invalidate the value of the variable passed by reference.
- const MemRegion *R = MR->getRegion();
+ if (const MemRegion *R = V.getAsRegion()) {
+ // Invalidate the value of the variable passed by reference.
- // Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underying region
- // is a variable region then strip off the ElementRegion.
- // FIXME: We really need to think about this for the general case
- // as sometimes we are reasoning about arrays and other times
- // about (char*), etc., is just a form of passing raw bytes.
- // e.g., void *p = alloca(); foo((char*)p);
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // Checking for 'integral type' is probably too promiscuous, but
- // we'll leave it in for now until we have a systematic way of
- // handling all of these cases. Eventually we need to come up
- // with an interface to StoreManager so that this logic can be
- // approriately delegated to the respective StoreManagers while
- // still allowing us to do checker-specific logic (e.g.,
- // invalidating reference counts), probably via callbacks.
- if (ER->getElementType()->isIntegralOrEnumerationType()) {
- const MemRegion *superReg = ER->getSuperRegion();
- if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
- isa<ObjCIvarRegion>(superReg))
- R = cast<TypedRegion>(superReg);
- }
- // FIXME: What about layers of ElementRegions?
+ // Are we dealing with an ElementRegion? If the element type is
+ // a basic integer type (e.g., char, int) and the underying region
+ // is a variable region then strip off the ElementRegion.
+ // FIXME: We really need to think about this for the general case
+ // as sometimes we are reasoning about arrays and other times
+ // about (char*), etc., is just a form of passing raw bytes.
+ // e.g., void *p = alloca(); foo((char*)p);
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // Checking for 'integral type' is probably too promiscuous, but
+ // we'll leave it in for now until we have a systematic way of
+ // handling all of these cases. Eventually we need to come up
+ // with an interface to StoreManager so that this logic can be
+ // approriately delegated to the respective StoreManagers while
+ // still allowing us to do checker-specific logic (e.g.,
+ // invalidating reference counts), probably via callbacks.
+ if (ER->getElementType()->isIntegralOrEnumerationType()) {
+ const MemRegion *superReg = ER->getSuperRegion();
+ if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+ isa<ObjCIvarRegion>(superReg))
+ R = cast<TypedRegion>(superReg);
}
-
- // Mark this region for invalidation. We batch invalidate regions
- // below for efficiency.
- RegionsToInvalidate.push_back(R);
- continue;
- }
- else {
- // Nuke all other arguments passed by reference.
- // FIXME: is this necessary or correct? This handles the non-Region
- // cases. Is it ever valid to store to these?
- state = state->unbindLoc(cast<Loc>(V));
+ // FIXME: What about layers of ElementRegions?
}
- }
- else if (isa<nonloc::LocAsInteger>(V)) {
- // If we are passing a location wrapped as an integer, unwrap it and
- // invalidate the values referred by the location.
- V = cast<nonloc::LocAsInteger>(V).getLoc();
- goto tryAgain;
+
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
+ RegionsToInvalidate.push_back(R);
+ } else {
+ // Nuke all other arguments passed by reference.
+ // FIXME: is this necessary or correct? This handles the non-Region
+ // cases. Is it ever valid to store to these?
+ state = state->unbindLoc(cast<Loc>(V));
}
}
// Block calls result in all captured values passed-via-reference to be
// invalidated.
- if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) {
+ if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee))
RegionsToInvalidate.push_back(BR);
- }
- // Invalidate regions we designed for invalidation use the batch invalidation
- // API.
+ // Invalidate designated regions using the batch invalidation API.
// FIXME: We can have collisions on the conjured symbol if the
// expression *I also creates conjured symbols. We probably want
@@ -2673,92 +2641,7 @@
/* invalidateGlobals = */
Eng.doesInvalidateGlobals(callOrMsg));
- // Evaluate the effect on the message receiver.
- if (!ErrorRange.isValid() && Receiver) {
- SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol();
- if (Sym) {
- if (const RefVal* T = state->get<RefBindings>(Sym)) {
- state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
- if (hasErr) {
- ErrorRange = Receiver.getSourceRange();
- ErrorSym = Sym;
- }
- }
- }
- }
-
- // Process any errors.
- if (hasErr) {
- ProcessNonLeakError(Dst, Builder, Ex, ErrorRange, Pred, state,
- hasErr, ErrorSym);
- return;
- }
-
- // Consult the summary for the return value.
- RetEffect RE = Summ.getRetEffect();
-
- if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
- bool found = false;
- if (Receiver) {
- SVal V = Receiver.getSValAsScalarOrLoc(state);
- if (SymbolRef Sym = V.getAsLocSymbol())
- if (state->get<RefBindings>(Sym)) {
- found = true;
- RE = Summaries.getObjAllocRetEffect();
- }
- } // FIXME: Otherwise, this is a send-to-super instance message.
- if (!found)
- RE = RetEffect::MakeNoRet();
- }
-
- switch (RE.getKind()) {
- default:
- llvm_unreachable("Unhandled RetEffect."); break;
-
- case RetEffect::NoRet:
- // No work necessary.
- break;
-
- case RetEffect::OwnedAllocatedSymbol:
- case RetEffect::OwnedSymbol:
- if (SymbolRef Sym = state->getSVal(Ex).getAsSymbol()) {
- // Use the result type from callOrMsg as it automatically adjusts
- // for methods/functions that return references.
- QualType ResultTy = callOrMsg.getResultType(Eng.getContext());
- state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
- ResultTy));
- }
-
- // FIXME: Add a flag to the checker where allocations are assumed to
- // *not* fail. (The code below is out-of-date, though.)
-#if 0
- if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
- bool isFeasible;
- state = state.assume(loc::SymbolVal(Sym), true, isFeasible);
- assert(isFeasible && "Cannot assume fresh symbol is non-null.");
- }
-#endif
-
- break;
-
- case RetEffect::GCNotOwnedSymbol:
- case RetEffect::ARCNotOwnedSymbol:
- case RetEffect::NotOwnedSymbol: {
- if (SymbolRef Sym = state->getSVal(Ex).getAsSymbol()) {
- // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *.
- QualType ResultTy = GetReturnType(Ex, Eng.getContext());
- state =
- state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
- ResultTy));
- }
- break;
- }
- }
-
- ExplodedNode *NewNode = Builder.MakeNode(Dst, Ex, Pred, state);
-
- // Annotate the edge with summary we used.
- if (NewNode) SummaryLog[NewNode] = &Summ;
+ Builder.MakeNode(Dst, Ex, Pred, state);
}
@@ -3320,44 +3203,6 @@
Builder.MakeNode(Dst, S, Pred, state);
}
-void CFRefCount::ProcessNonLeakError(ExplodedNodeSet &Dst,
- StmtNodeBuilder& Builder,
- const Expr *NodeExpr,
- SourceRange ErrorRange,
- ExplodedNode *Pred,
- const ProgramState *St,
- RefVal::Kind hasErr, SymbolRef Sym) {
- Builder.BuildSinks = true;
- ExplodedNode *N = Builder.MakeNode(Dst, NodeExpr, Pred, St);
-
- if (!N)
- return;
-
- CFRefBug *BT = 0;
-
- switch (hasErr) {
- default:
- assert(false && "Unhandled error.");
- return;
- case RefVal::ErrorUseAfterRelease:
- BT = static_cast<CFRefBug*>(useAfterRelease);
- break;
- case RefVal::ErrorReleaseNotOwned:
- BT = static_cast<CFRefBug*>(releaseNotOwned);
- break;
- case RefVal::ErrorDeallocGC:
- BT = static_cast<CFRefBug*>(deallocGC);
- break;
- case RefVal::ErrorDeallocNotOwned:
- BT = static_cast<CFRefBug*>(deallocNotOwned);
- break;
- }
-
- CFRefReport *report = new CFRefReport(*BT, *this, N, Sym);
- report->addRange(ErrorRange);
- BR->EmitReport(report);
-}
-
//===----------------------------------------------------------------------===//
// Pieces of the retain/release checker implemented using a CheckerVisitor.
// More pieces of the retain/release checker will be migrated to this interface
@@ -3369,6 +3214,8 @@
: public Checker< check::Bind,
check::PostStmt<BlockExpr>,
check::PostStmt<CastExpr>,
+ check::PostStmt<CallExpr>,
+ check::PostObjCMessage,
check::RegionChanges,
eval::Assume,
eval::Call > {
@@ -3377,6 +3224,11 @@
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
+ void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
+ InstanceReceiver Receiver, CheckerContext &C) const;
+
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
@@ -3390,6 +3242,11 @@
bool wantsRegionChangeUpdate(const ProgramState *state) const {
return true;
}
+
+ void processNonLeakError(const ProgramState *St, SourceRange ErrorRange,
+ RefVal::Kind ErrorKind, SymbolRef Sym,
+ CheckerContext &C) const;
+
};
} // end anonymous namespace
@@ -3579,6 +3436,224 @@
C.generateNode(state);
}
+void RetainReleaseChecker::checkPostStmt(const CallExpr *CE,
+ CheckerContext &C) const {
+ // FIXME: This goes away once the RetainSummaryManager moves to the checker.
+ CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
+ RetainSummaryManager &Summaries = TF.Summaries;
+
+ // Get the callee.
+ const ProgramState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ SVal L = state->getSVal(Callee);
+
+ RetainSummary *Summ = 0;
+
+ // FIXME: Better support for blocks. For now we stop tracking anything
+ // that is passed to blocks.
+ // FIXME: Need to handle variables that are "captured" by the block.
+ if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
+ Summ = Summaries.getPersistentStopSummary();
+ } else if (const FunctionDecl *FD = L.getAsFunctionDecl()) {
+ Summ = Summaries.getSummary(FD);
+ } else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
+ if (const CXXMethodDecl *MD = me->getMethodDecl())
+ Summ = Summaries.getSummary(MD);
+ }
+
+ // If we didn't get a summary, this function doesn't affect retain counts.
+ if (!Summ)
+ return;
+
+ checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C);
+}
+
+void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg,
+ CheckerContext &C) const {
+ // FIXME: This goes away once the RetainSummaryManager moves to the checker.
+ CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
+ RetainSummaryManager &Summaries = TF.Summaries;
+
+ const ProgramState *state = C.getState();
+ ExplodedNode *Pred = C.getPredecessor();
+
+ RetainSummary *Summ;
+ if (Msg.isInstanceMessage()) {
+ const LocationContext *LC = Pred->getLocationContext();
+ Summ = Summaries.getInstanceMethodSummary(Msg, state, LC);
+ } else {
+ Summ = Summaries.getClassMethodSummary(Msg);
+ }
+
+ // If we didn't get a summary, this message doesn't affect retain counts.
+ if (!Summ)
+ return;
+
+ checkSummary(*Summ, CallOrObjCMessage(Msg, state),
+ InstanceReceiver(Msg, Pred->getLocationContext()), C);
+}
+
+void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
+ const CallOrObjCMessage &CallOrMsg,
+ InstanceReceiver Receiver,
+ CheckerContext &C) const {
+ // FIXME: This goes away once the Update() method moves to the checker.
+ CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
+
+ const ProgramState *state = C.getState();
+
+ // Evaluate the effect of the arguments.
+ RefVal::Kind hasErr = (RefVal::Kind) 0;
+ SourceRange ErrorRange;
+ SymbolRef ErrorSym = 0;
+
+ for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
+ SVal V = CallOrMsg.getArgSValAsScalarOrLoc(idx);
+
+ if (SymbolRef Sym = V.getAsLocSymbol()) {
+ if (RefBindings::data_type *T = state->get<RefBindings>(Sym)) {
+ state = TF.Update(state, Sym, *T, Summ.getArg(idx), hasErr);
+ if (hasErr) {
+ ErrorRange = CallOrMsg.getArgSourceRange(idx);
+ ErrorSym = Sym;
+ break;
+ }
+ }
+ }
+ }
+
+ // Evaluate the effect on the message receiver.
+ bool ReceiverIsTracked = false;
+ if (!hasErr && Receiver) {
+ if (SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol()) {
+ if (const RefVal *T = state->get<RefBindings>(Sym)) {
+ ReceiverIsTracked = true;
+ state = TF.Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
+ if (hasErr) {
+ ErrorRange = Receiver.getSourceRange();
+ ErrorSym = Sym;
+ }
+ }
+ }
+ }
+
+ // Process any errors.
+ if (hasErr) {
+ processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
+ return;
+ }
+
+ // Consult the summary for the return value.
+ RetEffect RE = Summ.getRetEffect();
+
+ if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
+ if (ReceiverIsTracked)
+ RE = TF.Summaries.getObjAllocRetEffect();
+ else
+ RE = RetEffect::MakeNoRet();
+ }
+
+ switch (RE.getKind()) {
+ default:
+ llvm_unreachable("Unhandled RetEffect."); break;
+
+ case RetEffect::NoRet:
+ // No work necessary.
+ break;
+
+ case RetEffect::OwnedAllocatedSymbol:
+ case RetEffect::OwnedSymbol: {
+ SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr()).getAsSymbol();
+ if (!Sym)
+ break;
+
+ // Use the result type from callOrMsg as it automatically adjusts
+ // for methods/functions that return references.
+ QualType ResultTy = CallOrMsg.getResultType(C.getASTContext());
+ state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
+ ResultTy));
+
+ // FIXME: Add a flag to the checker where allocations are assumed to
+ // *not* fail. (The code below is out-of-date, though.)
+#if 0
+ if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
+ bool isFeasible;
+ state = state.assume(loc::SymbolVal(Sym), true, isFeasible);
+ assert(isFeasible && "Cannot assume fresh symbol is non-null.");
+ }
+#endif
+
+ break;
+ }
+
+ case RetEffect::GCNotOwnedSymbol:
+ case RetEffect::ARCNotOwnedSymbol:
+ case RetEffect::NotOwnedSymbol: {
+ const Expr *Ex = CallOrMsg.getOriginExpr();
+ SymbolRef Sym = state->getSVal(Ex).getAsSymbol();
+ if (!Sym)
+ break;
+
+ // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *.
+ QualType ResultTy = GetReturnType(Ex, C.getASTContext());
+ state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
+ ResultTy));
+ break;
+ }
+ }
+
+ // This check is actually necessary; otherwise the statement builder thinks
+ // we've hit a previously-found path.
+ // Normally addTransition takes care of this, but we want the node pointer.
+ ExplodedNode *NewNode;
+ if (state == C.getState()) {
+ NewNode = C.getPredecessor();
+ } else {
+ NewNode = C.generateNode(state);
+ }
+
+ // Annotate the edge with summary we used.
+ // FIXME: The summary log should live on RetainReleaseChecker.
+ if (NewNode) TF.SummaryLog[NewNode] = &Summ;
+}
+
+void RetainReleaseChecker::processNonLeakError(const ProgramState *St,
+ SourceRange ErrorRange,
+ RefVal::Kind ErrorKind,
+ SymbolRef Sym,
+ CheckerContext &C) const {
+ ExplodedNode *N = C.generateSink(St);
+ if (!N)
+ return;
+
+ // FIXME: This goes away once the these bug types move to the checker,
+ // and CFRefReport no longer depends on CFRefCount.
+ CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
+
+ CFRefBug *BT;
+ switch (ErrorKind) {
+ default:
+ llvm_unreachable("Unhandled error.");
+ return;
+ case RefVal::ErrorUseAfterRelease:
+ BT = static_cast<CFRefBug*>(TF.useAfterRelease);
+ break;
+ case RefVal::ErrorReleaseNotOwned:
+ BT = static_cast<CFRefBug*>(TF.releaseNotOwned);
+ break;
+ case RefVal::ErrorDeallocGC:
+ BT = static_cast<CFRefBug*>(TF.deallocGC);
+ break;
+ case RefVal::ErrorDeallocNotOwned:
+ BT = static_cast<CFRefBug*>(TF.deallocNotOwned);
+ break;
+ }
+
+ CFRefReport *report = new CFRefReport(*BT, TF, N, Sym);
+ report->addRange(ErrorRange);
+ C.EmitReport(report);
+}
+
bool RetainReleaseChecker::evalCall(const CallExpr *CE,
CheckerContext &C) const {
// Get the callee. We're only interested in simple C functions.
@@ -3635,19 +3710,25 @@
}
state = state->BindExpr(CE, RetVal, false);
- // FIXME: This will improve when RetainSummariesManager moves to the checker.
- // Really we only want to handle ArgEffects and RetEffects; the arguments to
- // CFRetain and CFMakeCollectable don't need to be invalidated.
- // All of this can go away once the effects are handled in a post-call check.
- CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
- RetainSummary *Summ = TF.Summaries.getSummary(FD);
- assert(Summ);
+ // FIXME: This should not be necessary, but otherwise the argument seems to be
+ // considered alive during the next statement.
+ if (const MemRegion *ArgRegion = RetVal.getAsRegion()) {
+ // Save the refcount status of the argument.
+ SymbolRef Sym = RetVal.getAsLocSymbol();
+ RefBindings::data_type *Binding = 0;
+ if (Sym)
+ Binding = state->get<RefBindings>(Sym);
- TF.evalSummary(C.getNodeSet(), C.getEngine(), C.getNodeBuilder(), CE,
- CallOrObjCMessage(CE, C.getState()),
- InstanceReceiver(), *Summ, L.getAsRegion(),
- C.getPredecessor(), state);
+ // Invalidate the argument region.
+ unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ state = state->invalidateRegion(ArgRegion, CE, Count);
+ // Restore the refcount status of the argument.
+ if (Binding)
+ state = state->set<RefBindings>(Sym, *Binding);
+ }
+
+ C.addTransition(state);
return true;
}
More information about the cfe-commits
mailing list