[analyzer] Make CFRefBug and CFRefReportVisitor not dependent on CFRefCount. Unfortunately, CFRefReport still is. No functionality change.

llvm-svn: 138388
This commit is contained in:
Jordy Rose 2011-08-23 21:47:17 +00:00
parent 4eb0433672
commit 908426aae4
1 changed files with 69 additions and 89 deletions

View File

@ -1742,8 +1742,6 @@ void CFRefCount::BindingsPrinter::Print(raw_ostream &Out,
//===----------------------------------------------------------------------===//
// Error reporting.
//===----------------------------------------------------------------------===//
static void addExtraTextToCFReport(BugReport &R);
namespace {
typedef llvm::DenseMap<const ExplodedNode *, const RetainSummary *>
SummaryLogTy;
@ -1754,35 +1752,30 @@ namespace {
class CFRefBug : public BugType {
protected:
CFRefCount& TF;
CFRefBug(CFRefCount* tf, StringRef name)
: BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {}
CFRefBug(StringRef name)
: BugType(name, "Memory (Core Foundation/Objective-C)") {}
public:
CFRefCount& getTF() { return TF; }
// FIXME: Eventually remove.
virtual const char* getDescription() const = 0;
virtual const char *getDescription() const = 0;
virtual bool isLeak() const { return false; }
};
class UseAfterRelease : public CFRefBug {
public:
UseAfterRelease(CFRefCount* tf)
: CFRefBug(tf, "Use-after-release") {}
UseAfterRelease() : CFRefBug("Use-after-release") {}
const char* getDescription() const {
const char *getDescription() const {
return "Reference-counted object is used after it is released";
}
};
class BadRelease : public CFRefBug {
public:
BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {}
BadRelease() : CFRefBug("Bad release") {}
const char* getDescription() const {
const char *getDescription() const {
return "Incorrect decrement of the reference count of an object that is "
"not owned at this point by the caller";
}
@ -1790,8 +1783,8 @@ namespace {
class DeallocGC : public CFRefBug {
public:
DeallocGC(CFRefCount *tf)
: CFRefBug(tf, "-dealloc called while using garbage collection") {}
DeallocGC()
: CFRefBug("-dealloc called while using garbage collection") {}
const char *getDescription() const {
return "-dealloc called while using garbage collection";
@ -1800,8 +1793,8 @@ namespace {
class DeallocNotOwned : public CFRefBug {
public:
DeallocNotOwned(CFRefCount *tf)
: CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {}
DeallocNotOwned()
: CFRefBug("-dealloc sent to non-exclusively owned object") {}
const char *getDescription() const {
return "-dealloc sent to object that may be referenced elsewhere";
@ -1810,8 +1803,8 @@ namespace {
class OverAutorelease : public CFRefBug {
public:
OverAutorelease(CFRefCount *tf) :
CFRefBug(tf, "Object sent -autorelease too many times") {}
OverAutorelease()
: CFRefBug("Object sent -autorelease too many times") {}
const char *getDescription() const {
return "Object sent -autorelease too many times";
@ -1820,8 +1813,8 @@ namespace {
class ReturnedNotOwnedForOwned : public CFRefBug {
public:
ReturnedNotOwnedForOwned(CFRefCount *tf) :
CFRefBug(tf, "Method should return an owned object") {}
ReturnedNotOwnedForOwned()
: CFRefBug("Method should return an owned object") {}
const char *getDescription() const {
return "Object with a +0 retain count returned to caller where a +1 "
@ -1832,25 +1825,25 @@ namespace {
class Leak : public CFRefBug {
const bool isReturn;
protected:
Leak(CFRefCount* tf, StringRef name, bool isRet)
: CFRefBug(tf, name), isReturn(isRet) {}
Leak(StringRef name, bool isRet)
: CFRefBug(name), isReturn(isRet) {}
public:
const char* getDescription() const { return ""; }
const char *getDescription() const { return ""; }
bool isLeak() const { return true; }
};
class LeakAtReturn : public Leak {
public:
LeakAtReturn(CFRefCount* tf, StringRef name)
: Leak(tf, name, true) {}
LeakAtReturn(StringRef name)
: Leak(name, true) {}
};
class LeakWithinFunction : public Leak {
public:
LeakWithinFunction(CFRefCount* tf, StringRef name)
: Leak(tf, name, false) {}
LeakWithinFunction(StringRef name)
: Leak(name, false) {}
};
//===---------===//
@ -1860,13 +1853,12 @@ namespace {
class CFRefReportVisitor : public BugReporterVisitor {
protected:
SymbolRef Sym;
const CFRefCount &TF;
const SummaryLogTy &SummaryLog;
bool GCEnabled;
public:
CFRefReportVisitor(SymbolRef sym, const CFRefCount &tf,
const SummaryLogTy &log)
: Sym(sym), TF(tf), SummaryLog(log) {}
CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log)
: Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {}
virtual void Profile(llvm::FoldingSetNodeID &ID) const {
static int x = 0;
@ -1886,9 +1878,9 @@ namespace {
class CFRefLeakReportVisitor : public CFRefReportVisitor {
public:
CFRefLeakReportVisitor(SymbolRef sym, const CFRefCount &tf,
CFRefLeakReportVisitor(SymbolRef sym, bool GCEnabled,
const SummaryLogTy &log)
: CFRefReportVisitor(sym, tf, log) {}
: CFRefReportVisitor(sym, GCEnabled, log) {}
PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
@ -1896,24 +1888,24 @@ namespace {
};
class CFRefReport : public BugReport {
void addGCModeDescription(const CFRefCount &TF);
public:
CFRefReport(CFRefBug &D, const CFRefCount &tf, const SummaryLogTy &log,
ExplodedNode *n, SymbolRef sym, bool registerVisitor = true)
: BugReport(D, D.getDescription(), n) {
if (registerVisitor)
addVisitor(new CFRefReportVisitor(sym, tf, log));
addExtraTextToCFReport(*this);
addVisitor(new CFRefReportVisitor(sym, tf.isGCEnabled(), log));
addGCModeDescription(tf);
}
CFRefReport(CFRefBug &D, const CFRefCount &tf, const SummaryLogTy &log,
ExplodedNode *n, SymbolRef sym, StringRef endText)
: BugReport(D, D.getDescription(), endText, n) {
addVisitor(new CFRefReportVisitor(sym, tf, log));
addExtraTextToCFReport(*this);
addVisitor(new CFRefReportVisitor(sym, tf.isGCEnabled(), log));
addGCModeDescription(tf);
}
virtual ~CFRefReport() {}
virtual std::pair<ranges_iterator, ranges_iterator> getRanges() {
const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType());
if (!BugTy.isLeak())
@ -1928,54 +1920,42 @@ namespace {
const MemRegion* AllocBinding;
public:
CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, const SummaryLogTy &log,
CFRefLeakReport(CFRefBug &D, const CFRefCount &tf, const SummaryLogTy &log,
ExplodedNode *n, SymbolRef sym, ExprEngine& Eng);
SourceLocation getLocation() const { return AllocSite; }
};
} // end anonymous namespace
static const char* Msgs[] = {
// GC only
"Code is compiled to only use garbage collection",
// No GC.
"Code is compiled to use reference counts",
// Hybrid, with GC.
"Code is compiled to use either garbage collection (GC) or reference counts"
" (non-GC). The bug occurs with GC enabled",
// Hybrid, without GC
"Code is compiled to use either garbage collection (GC) or reference counts"
" (non-GC). The bug occurs in non-GC mode"
};
// Add the metadata text.
static void addExtraTextToCFReport(BugReport &R) {
CFRefCount& TF = static_cast<CFRefBug&>(R.getBugType()).getTF();
void CFRefReport::addGCModeDescription(const CFRefCount &TF) {
const char *GCModeDescription;
switch (TF.getLangOptions().getGCMode()) {
default:
assert(false);
case LangOptions::GCOnly:
assert (TF.isGCEnabled());
R.addExtraText(Msgs[0]);
return;
assert(TF.isGCEnabled());
GCModeDescription = "Code is compiled to only use garbage collection";
break;
case LangOptions::NonGC:
assert (!TF.isGCEnabled());
R.addExtraText(Msgs[1]);
return;
assert(!TF.isGCEnabled());
GCModeDescription = "Code is compiled to use reference counts";
break;
case LangOptions::HybridGC:
if (TF.isGCEnabled()) {
R.addExtraText(Msgs[2]);
return;
}
else {
R.addExtraText(Msgs[3]);
return;
GCModeDescription = "Code is compiled to use either garbage collection "
"(GC) or reference counts (non-GC). The bug occurs "
"with GC enabled";
break;
} else {
GCModeDescription = "Code is compiled to use either garbage collection "
"(GC) or reference counts (non-GC). The bug occurs "
"in non-GC mode";
break;
}
}
addExtraText(GCModeDescription);
}
static inline bool contains(const SmallVectorImpl<ArgEffect>& V,
@ -2040,7 +2020,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (CurrV.isOwned()) {
os << "+1 retain count";
if (TF.isGCEnabled()) {
if (GCEnabled) {
assert(CurrV.getObjKind() == RetEffect::CF);
os << ". "
"Core Foundation objects are not automatically garbage collected.";
@ -2096,7 +2076,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
RefVal PrevV = *PrevT;
// Specially handle -dealloc.
if (!TF.isGCEnabled() && contains(AEffects, Dealloc)) {
if (!GCEnabled && contains(AEffects, Dealloc)) {
// Determine if the object's reference count was pushed to zero.
assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
// We may not have transitioned to 'release' if we hit an error.
@ -2115,7 +2095,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee());
const FunctionDecl *FD = X.getAsFunctionDecl();
if (TF.isGCEnabled()) {
if (GCEnabled) {
// Determine if the object's reference count was pushed to zero.
assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
@ -2166,7 +2146,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
os << " The object now has a +" << Count << " retain count.";
if (PrevV.getKind() == RefVal::Released) {
assert(TF.isGCEnabled() && CurrV.getCount() > 0);
assert(GCEnabled && CurrV.getCount() > 0);
os << " The object is not eligible for garbage collection until the "
"retain count reaches 0 again.";
}
@ -2195,7 +2175,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
E=AEffects.end(); I != E; ++I) {
// A bunch of things have alternate behavior under GC.
if (TF.isGCEnabled())
if (GCEnabled)
switch (*I) {
default: break;
case Autorelease:
@ -2399,7 +2379,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
return new PathDiagnosticEventPiece(L, os.str());
}
CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const CFRefCount &tf,
const SummaryLogTy &log, ExplodedNode *n,
SymbolRef sym, ExprEngine& Eng)
: CFRefReport(D, tf, log, n, sym, false) {
@ -2436,7 +2416,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
if (AllocBinding)
os << " and stored into '" << AllocBinding->getString() << '\'';
addVisitor(new CFRefLeakReportVisitor(sym, tf, log));
addVisitor(new CFRefLeakReportVisitor(sym, tf.isGCEnabled(), log));
}
//===----------------------------------------------------------------------===//
@ -3723,26 +3703,26 @@ void RetainReleaseChecker::checkDeadSymbols(SymbolReaper &SymReaper,
void CFRefCount::RegisterChecks(ExprEngine& Eng) {
BugReporter &BR = Eng.getBugReporter();
useAfterRelease = new UseAfterRelease(this);
useAfterRelease = new UseAfterRelease();
BR.Register(useAfterRelease);
releaseNotOwned = new BadRelease(this);
releaseNotOwned = new BadRelease();
BR.Register(releaseNotOwned);
deallocGC = new DeallocGC(this);
deallocGC = new DeallocGC();
BR.Register(deallocGC);
deallocNotOwned = new DeallocNotOwned(this);
deallocNotOwned = new DeallocNotOwned();
BR.Register(deallocNotOwned);
overAutorelease = new OverAutorelease(this);
overAutorelease = new OverAutorelease();
BR.Register(overAutorelease);
returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
returnNotOwnedForOwned = new ReturnedNotOwnedForOwned();
BR.Register(returnNotOwnedForOwned);
// First register "return" leaks.
const char* name = 0;
const char *name = 0;
if (isGCEnabled())
name = "Leak of returned object when using garbage collection";
@ -3755,7 +3735,7 @@ void CFRefCount::RegisterChecks(ExprEngine& Eng) {
}
// Leaks should not be reported if they are post-dominated by a sink.
leakAtReturn = new LeakAtReturn(this, name);
leakAtReturn = new LeakAtReturn(name);
leakAtReturn->setSuppressOnSink(true);
BR.Register(leakAtReturn);
@ -3771,7 +3751,7 @@ void CFRefCount::RegisterChecks(ExprEngine& Eng) {
}
// Leaks should not be reported if they are post-dominated by sinks.
leakWithinFunction = new LeakWithinFunction(this, name);
leakWithinFunction = new LeakWithinFunction(name);
leakWithinFunction->setSuppressOnSink(true);
BR.Register(leakWithinFunction);