const char* sep);
};
- RetainSummaryManager Summaries;
const LangOptions& LOpts;
+ const bool GCEnabled;
BugType *useAfterRelease, *releaseNotOwned;
BugType *deallocGC, *deallocNotOwned;
public:
CFRefCount(ASTContext &Ctx, bool gcenabled, const LangOptions& lopts)
- : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount),
- LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
- deallocGC(0), deallocNotOwned(0),
+ : LOpts(lopts), GCEnabled(gcenabled),
+ useAfterRelease(0), releaseNotOwned(0), deallocGC(0), deallocNotOwned(0),
leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
returnNotOwnedForOwned(0) {}
virtual void RegisterPrinters(std::vector<ProgramState::Printer*>& Printers) {
Printers.push_back(new BindingsPrinter());
}
-
- bool isGCEnabled() const { return Summaries.isGCEnabled(); }
- bool isARCorGCEnabled() const { return Summaries.isARCorGCEnabled(); }
const LangOptions& getLangOptions() const { return LOpts; }
// This map is only used to ensure proper deletion of any allocated tags.
mutable SymbolTagMap DeadSymbolTags;
+ mutable llvm::OwningPtr<RetainSummaryManager> Summaries;
+ mutable llvm::OwningPtr<RetainSummaryManager> SummariesGC;
+
mutable ARCounts::Factory ARCountFactory;
mutable SummaryLogTy SummaryLog;
return isGCEnabled() || Ctx.getLangOptions().ObjCAutoRefCount;
}
+ RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
+ if (isGCEnabled()) {
+ if (!SummariesGC) {
+ bool ARCEnabled = (bool)Ctx.getLangOptions().ObjCAutoRefCount;
+ SummariesGC.reset(new RetainSummaryManager(Ctx, true, ARCEnabled));
+ }
+ return *SummariesGC;
+ } else {
+ if (!Summaries) {
+ bool ARCEnabled = (bool)Ctx.getLangOptions().ObjCAutoRefCount;
+ Summaries.reset(new RetainSummaryManager(Ctx, false, ARCEnabled));
+ }
+ return *Summaries;
+ }
+ }
+
void checkBind(SVal loc, SVal val, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
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);
+ RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext());
RetainSummary *Summ = 0;
// FIXME: Better support for blocks. For now we stop tracking anything
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();
+ RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext());
+
RetainSummary *Summ;
if (Msg.isInstanceMessage()) {
const LocationContext *LC = Pred->getLocationContext();
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
- if (ReceiverIsTracked) {
- // FIXME: This goes away if the RetainSummaryManager moves to the checker.
- CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
- RE = TF.Summaries.getObjAllocRetEffect();
- } else {
+ if (ReceiverIsTracked)
+ RE = getSummaryManager(C.getASTContext()).getObjAllocRetEffect();
+ else
RE = RetEffect::MakeNoRet();
- }
}
switch (RE.getKind()) {
X = *T;
// Consult the summary of the enclosing method.
+ RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext());
const Decl *CD = &Pred->getCodeDecl();
- // FIXME: This goes away once the RetainSummariesManager moves to the checker.
- CFRefCount &TF = static_cast<CFRefCount&>(C.getEngine().getTF());
-
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
// Unlike regular functions, /all/ ObjC methods are assumed to always
// follow Cocoa retain-count conventions, not just those with special
// names or attributes.
- const RetainSummary *Summ = TF.Summaries.getMethodSummary(MD);
+ const RetainSummary *Summ = Summaries.getMethodSummary(MD);
RetEffect RE = Summ ? Summ->getRetEffect() : RetEffect::MakeNoRet();
checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
if (!isa<CXXMethodDecl>(FD))
- if (const RetainSummary *Summ = TF.Summaries.getSummary(FD))
+ if (const RetainSummary *Summ = Summaries.getSummary(FD))
checkReturnWithRetEffect(S, C, Pred, Summ->getRetEffect(), X,
Sym, state);
}
// First register "return" leaks.
const char *name = 0;
- if (isGCEnabled())
+ if (GCEnabled)
name = "Leak of returned object when using garbage collection";
else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
name = "Leak of returned object when not using garbage collection (GC) in "
BR.Register(leakAtReturn);
// Second, register leaks within a function/method.
- if (isGCEnabled())
+ if (GCEnabled)
name = "Leak of object when using garbage collection";
else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
name = "Leak of object when not using garbage collection (GC) in "
RetainReleaseChecker *checker =
Eng.getCheckerManager().registerChecker<RetainReleaseChecker>();
assert(checker);
- checker->setGCMode(isGCEnabled() ? LangOptions::GCOnly : LangOptions::NonGC);
+ checker->setGCMode(GCEnabled ? LangOptions::GCOnly : LangOptions::NonGC);
}
TransferFuncs* ento::MakeCFRefCountTF(ASTContext &Ctx, bool GCEnabled,