summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp385
1 files changed, 61 insertions, 324 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 1d773c31cd8..127f20bee71 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -83,14 +83,12 @@ public:
ReturnedNotOwned, // Return object does not pass ownership to caller.
ERROR_START,
ErrorDeallocNotOwned, // -dealloc called on non-owned object.
- ErrorDeallocGC, // Calling -dealloc with GC enabled.
ErrorUseAfterRelease, // Object used after released.
ErrorReleaseNotOwned, // Release of an object that was not owned.
ERROR_LEAK_START,
ErrorLeak, // A memory leak due to excessive reference counts.
ErrorLeakReturned, // A memory leak due to the returning method not having
// the correct naming conventions.
- ErrorGCLeakReturned,
ErrorOverAutorelease,
ErrorReturnedNotOwned
};
@@ -303,10 +301,6 @@ void RefVal::print(raw_ostream &Out) const {
Out << "Released";
break;
- case ErrorDeallocGC:
- Out << "-dealloc (GC)";
- break;
-
case ErrorDeallocNotOwned:
Out << "-dealloc (not-owned)";
break;
@@ -319,10 +313,6 @@ void RefVal::print(raw_ostream &Out) const {
Out << "Leaked (Bad naming)";
break;
- case ErrorGCLeakReturned:
- Out << "Leaked (GC-ed at return)";
- break;
-
case ErrorUseAfterRelease:
Out << "Use-After-Release [ERROR]";
break;
@@ -600,9 +590,6 @@ class RetainSummaryManager {
/// Ctx - The ASTContext object for the analyzed ASTs.
ASTContext &Ctx;
- /// GCEnabled - Records whether or not the analyzed code runs in GC mode.
- const bool GCEnabled;
-
/// Records whether or not the analyzed code runs in ARC mode.
const bool ARCEnabled;
@@ -646,7 +633,7 @@ class RetainSummaryManager {
/// data in ScratchArgs.
ArgEffects getArgEffects();
- enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
+ enum UnaryFuncKind { cfretain, cfrelease, cfautorelease };
const RetainSummary *getUnarySummary(const FunctionType* FT,
UnaryFuncKind func);
@@ -732,19 +719,14 @@ private:
public:
- RetainSummaryManager(ASTContext &ctx, bool gcenabled, bool usesARC)
+ RetainSummaryManager(ASTContext &ctx, bool usesARC)
: Ctx(ctx),
- GCEnabled(gcenabled),
ARCEnabled(usesARC),
AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
- ObjCAllocRetE(gcenabled
- ? RetEffect::MakeGCNotOwned()
- : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
- : RetEffect::MakeOwned(RetEffect::ObjC))),
- ObjCInitRetE(gcenabled
- ? RetEffect::MakeGCNotOwned()
- : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
- : RetEffect::MakeOwnedWhenTrackedReceiver())) {
+ ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
+ : RetEffect::MakeOwned(RetEffect::ObjC)),
+ ObjCInitRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
+ : RetEffect::MakeOwnedWhenTrackedReceiver()) {
InitializeClassMethodSummaries();
InitializeMethodSummaries();
}
@@ -802,12 +784,8 @@ public:
void updateSummaryForCall(const RetainSummary *&Summ,
const CallEvent &Call);
- bool isGCEnabled() const { return GCEnabled; }
-
bool isARCEnabled() const { return ARCEnabled; }
- bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
-
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
friend class RetainSummaryTemplate;
@@ -895,12 +873,6 @@ static bool isAutorelease(const FunctionDecl *FD, StringRef FName) {
FName.endswith_lower("autorelease");
}
-static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) {
- // FIXME: Remove FunctionDecl parameter.
- // FIXME: Is it really okay if MakeCollectable isn't a suffix?
- return FName.find_lower("MakeCollectable") != StringRef::npos;
-}
-
static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
switch (E) {
case DoNothing:
@@ -908,7 +880,6 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
case DecRefBridgedTransferred:
case IncRef:
case IncRefMsg:
- case MakeCollectable:
case UnretainedOutParameter:
case RetainedOutParameter:
case MayEscape:
@@ -1073,14 +1044,6 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
// Part of: <rdar://problem/7299394> and <rdar://problem/11282706>.
// This will be addressed better with IPA.
S = getPersistentStopSummary();
- } else if (FName == "NSMakeCollectable") {
- // Handle: id NSMakeCollectable(CFTypeRef)
- S = (RetTy->isObjCIdType())
- ? getUnarySummary(FT, cfmakecollectable)
- : getPersistentStopSummary();
- // The headers on OS X 10.8 use cf_consumed/ns_returns_retained,
- // but we can fully model NSMakeCollectable ourselves.
- AllowAnnotations = false;
} else if (FName == "CFPlugInInstanceCreate") {
S = getPersistentSummary(RetEffect::MakeNoRet());
} else if (FName == "IORegistryEntrySearchCFProperty"
@@ -1181,9 +1144,6 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
// The headers use cf_consumed, but we can fully model CFAutorelease
// ourselves.
AllowAnnotations = false;
- } else if (isMakeCollectable(FD, FName)) {
- S = getUnarySummary(FT, cfmakecollectable);
- AllowAnnotations = false;
} else {
S = getCFCreateGetRuleSummary(FD);
}
@@ -1294,7 +1254,6 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
case cfretain: Effect = IncRef; break;
case cfrelease: Effect = DecRef; break;
case cfautorelease: Effect = Autorelease; break;
- case cfmakecollectable: Effect = MakeCollectable; break;
}
ScratchArgs = AF.add(ScratchArgs, 0, Effect);
@@ -1732,16 +1691,6 @@ namespace {
}
};
- class DeallocGC : public CFRefBug {
- public:
- DeallocGC(const CheckerBase *checker)
- : CFRefBug(checker, "-dealloc called while using garbage collection") {}
-
- const char *getDescription() const override {
- return "-dealloc called while using garbage collection";
- }
- };
-
class DeallocNotOwned : public CFRefBug {
public:
DeallocNotOwned(const CheckerBase *checker)
@@ -1792,11 +1741,10 @@ namespace {
protected:
SymbolRef Sym;
const SummaryLogTy &SummaryLog;
- bool GCEnabled;
public:
- CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log)
- : Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {}
+ CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log)
+ : Sym(sym), SummaryLog(log) {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int x = 0;
@@ -1816,9 +1764,9 @@ namespace {
class CFRefLeakReportVisitor : public CFRefReportVisitor {
public:
- CFRefLeakReportVisitor(SymbolRef sym, bool GCEnabled,
+ CFRefLeakReportVisitor(SymbolRef sym,
const SummaryLogTy &log)
- : CFRefReportVisitor(sym, GCEnabled, log) {}
+ : CFRefReportVisitor(sym, log) {}
std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
@@ -1826,24 +1774,21 @@ namespace {
};
class CFRefReport : public BugReport {
- void addGCModeDescription(const LangOptions &LOpts, bool GCEnabled);
public:
- CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
+ CFRefReport(CFRefBug &D, const LangOptions &LOpts,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
bool registerVisitor = true)
: BugReport(D, D.getDescription(), n) {
if (registerVisitor)
- addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, GCEnabled, Log));
- addGCModeDescription(LOpts, GCEnabled);
+ addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
}
- CFRefReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
+ CFRefReport(CFRefBug &D, const LangOptions &LOpts,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
StringRef endText)
: BugReport(D, D.getDescription(), endText, n) {
- addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, GCEnabled, Log));
- addGCModeDescription(LOpts, GCEnabled);
+ addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
}
llvm::iterator_range<ranges_iterator> getRanges() override {
@@ -1863,10 +1808,10 @@ namespace {
// Finds the location where a leak warning for 'sym' should be raised.
void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym);
// Produces description of a leak warning which is printed on the console.
- void createDescription(CheckerContext &Ctx, bool GCEnabled, bool IncludeAllocationLine);
+ void createDescription(CheckerContext &Ctx, bool IncludeAllocationLine);
public:
- CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled,
+ CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
CheckerContext &Ctx,
bool IncludeAllocationLine);
@@ -1878,39 +1823,6 @@ namespace {
};
} // end anonymous namespace
-void CFRefReport::addGCModeDescription(const LangOptions &LOpts,
- bool GCEnabled) {
- const char *GCModeDescription = nullptr;
-
- switch (LOpts.getGC()) {
- case LangOptions::GCOnly:
- assert(GCEnabled);
- GCModeDescription = "Code is compiled to only use garbage collection";
- break;
-
- case LangOptions::NonGC:
- assert(!GCEnabled);
- GCModeDescription = "Code is compiled to use reference counts";
- break;
-
- case LangOptions::HybridGC:
- if (GCEnabled) {
- 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;
- }
- }
-
- assert(GCModeDescription && "invalid/unknown GC mode");
- addExtraText(GCModeDescription);
-}
-
static bool isNumericLiteralExpression(const Expr *E) {
// FIXME: This set of cases was copied from SemaExprObjC.
return isa<IntegerLiteral>(E) ||
@@ -2047,14 +1959,7 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
if (CurrV.isOwned()) {
os << "+1 retain count";
-
- if (GCEnabled) {
- assert(CurrV.getObjKind() == RetEffect::CF);
- os << ". "
- "Core Foundation objects are not automatically garbage collected.";
- }
- }
- else {
+ } else {
assert (CurrV.isNotOwned());
os << "+0 retain count";
}
@@ -2091,14 +1996,14 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
// We have an argument. Get the effect!
AEffects.push_back(Summ->getArg(i));
}
- }
- else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
- if (const Expr *receiver = ME->getInstanceReceiver())
+ } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
+ if (const Expr *receiver = ME->getInstanceReceiver()) {
if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
.getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
}
+ }
}
}
@@ -2107,7 +2012,7 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
RefVal PrevV = *PrevT;
// Specially handle -dealloc.
- if (!GCEnabled && std::find(AEffects.begin(), AEffects.end(), Dealloc) !=
+ if (std::find(AEffects.begin(), AEffects.end(), Dealloc) !=
AEffects.end()) {
// Determine if the object's reference count was pushed to zero.
assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
@@ -2120,41 +2025,6 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
}
}
- // Specially handle CFMakeCollectable and friends.
- if (std::find(AEffects.begin(), AEffects.end(), MakeCollectable) !=
- AEffects.end()) {
- // Get the name of the function.
- const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
- SVal X =
- CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee(), LCtx);
- const FunctionDecl *FD = X.getAsFunctionDecl();
-
- if (GCEnabled) {
- // Determine if the object's reference count was pushed to zero.
- assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
-
- os << "In GC mode a call to '" << *FD
- << "' decrements an object's retain count and registers the "
- "object with the garbage collector. ";
-
- if (CurrV.getKind() == RefVal::Released) {
- assert(CurrV.getCount() == 0);
- os << "Since it now has a 0 retain count the object can be "
- "automatically collected by the garbage collector.";
- }
- else
- os << "An object must have a 0 retain count to be garbage collected. "
- "After this call its retain count is +" << CurrV.getCount()
- << '.';
- }
- else
- os << "When GC is not enabled a call to '" << *FD
- << "' has no effect on its argument.";
-
- // Nothing more to say.
- break;
- }
-
// Determine if the typestate has changed.
if (!PrevV.hasSameState(CurrV))
switch (CurrV.getKind()) {
@@ -2178,12 +2048,6 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
if (unsigned Count = CurrV.getCount())
os << " The object now has a +" << Count << " retain count.";
- if (PrevV.getKind() == RefVal::Released) {
- assert(GCEnabled && CurrV.getCount() > 0);
- os << " The object is not eligible for garbage collection until "
- "the retain count reaches 0 again.";
- }
-
break;
case RefVal::Released:
@@ -2211,26 +2075,6 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN,
default:
return nullptr;
}
-
- // Emit any remaining diagnostics for the argument effects (if any).
- for (SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(),
- E=AEffects.end(); I != E; ++I) {
-
- // A bunch of things have alternate behavior under GC.
- if (GCEnabled)
- switch (*I) {
- default: break;
- case Autorelease:
- os << "In GC mode an 'autorelease' has no effect.";
- continue;
- case IncRefMsg:
- os << "In GC mode the 'retain' message has no effect.";
- continue;
- case DecRefMsg:
- os << "In GC mode the 'release' message has no effect.";
- continue;
- }
- }
} while (0);
if (os.str().empty())
@@ -2437,14 +2281,6 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
}
}
}
- else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
- const ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
- os << " and returned from method '" << MD.getSelector().getAsString()
- << "' is potentially leaked when using garbage collection. Callers "
- "of this method do not expect a returned object with a +1 retain "
- "count since they expect the object to be managed by the garbage "
- "collector";
- }
else
os << " is not referenced later in this execution path and has a retain "
"count of +" << RV->getCount();
@@ -2512,15 +2348,12 @@ void CFRefLeakReport::deriveAllocLocation(CheckerContext &Ctx,SymbolRef sym) {
UniqueingDecl = AllocNode->getLocationContext()->getDecl();
}
-void CFRefLeakReport::createDescription(CheckerContext &Ctx, bool GCEnabled,
+void CFRefLeakReport::createDescription(CheckerContext &Ctx,
bool IncludeAllocationLine) {
assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
Description.clear();
llvm::raw_string_ostream os(Description);
- os << "Potential leak ";
- if (GCEnabled)
- os << "(when using garbage collection) ";
- os << "of an object";
+ os << "Potential leak of an object";
Optional<std::string> RegionDescription = describeRegion(AllocBinding);
if (RegionDescription) {
@@ -2533,19 +2366,19 @@ void CFRefLeakReport::createDescription(CheckerContext &Ctx, bool GCEnabled,
}
CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
- bool GCEnabled, const SummaryLogTy &Log,
+ const SummaryLogTy &Log,
ExplodedNode *n, SymbolRef sym,
CheckerContext &Ctx,
bool IncludeAllocationLine)
- : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) {
+ : CFRefReport(D, LOpts, Log, n, sym, false) {
deriveAllocLocation(Ctx, sym);
if (!AllocBinding)
deriveParamLocation(Ctx, sym);
- createDescription(Ctx, GCEnabled, IncludeAllocationLine);
+ createDescription(Ctx, IncludeAllocationLine);
- addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, GCEnabled, Log));
+ addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, Log));
}
//===----------------------------------------------------------------------===//
@@ -2571,10 +2404,9 @@ class RetainCountChecker
eval::Assume,
eval::Call > {
mutable std::unique_ptr<CFRefBug> useAfterRelease, releaseNotOwned;
- mutable std::unique_ptr<CFRefBug> deallocGC, deallocNotOwned;
+ mutable std::unique_ptr<CFRefBug> deallocNotOwned;
mutable std::unique_ptr<CFRefBug> overAutorelease, returnNotOwnedForOwned;
mutable std::unique_ptr<CFRefBug> leakWithinFunction, leakAtReturn;
- mutable std::unique_ptr<CFRefBug> leakWithinFunctionGC, leakAtReturnGC;
typedef llvm::DenseMap<SymbolRef, const CheckerProgramPointTag *> SymbolTagMap;
@@ -2582,7 +2414,6 @@ class RetainCountChecker
mutable SymbolTagMap DeadSymbolTags;
mutable std::unique_ptr<RetainSummaryManager> Summaries;
- mutable std::unique_ptr<RetainSummaryManager> SummariesGC;
mutable SummaryLogTy SummaryLog;
mutable bool ShouldResetSummaryLog;
@@ -2633,72 +2464,31 @@ public:
ShouldResetSummaryLog = !SummaryLog.empty();
}
- CFRefBug *getLeakWithinFunctionBug(const LangOptions &LOpts,
- bool GCEnabled) const {
- if (GCEnabled) {
- if (!leakWithinFunctionGC)
- leakWithinFunctionGC.reset(new Leak(this, "Leak of object when using "
- "garbage collection"));
- return leakWithinFunctionGC.get();
- } else {
- if (!leakWithinFunction) {
- if (LOpts.getGC() == LangOptions::HybridGC) {
- leakWithinFunction.reset(new Leak(this,
- "Leak of object when not using "
- "garbage collection (GC) in "
- "dual GC/non-GC code"));
- } else {
- leakWithinFunction.reset(new Leak(this, "Leak"));
- }
- }
- return leakWithinFunction.get();
- }
+ CFRefBug *getLeakWithinFunctionBug(const LangOptions &LOpts) const {
+ if (!leakWithinFunction)
+ leakWithinFunction.reset(new Leak(this, "Leak"));
+ return leakWithinFunction.get();
}
- CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts, bool GCEnabled) const {
- if (GCEnabled) {
- if (!leakAtReturnGC)
- leakAtReturnGC.reset(new Leak(this,
- "Leak of returned object when using "
- "garbage collection"));
- return leakAtReturnGC.get();
- } else {
- if (!leakAtReturn) {
- if (LOpts.getGC() == LangOptions::HybridGC) {
- leakAtReturn.reset(new Leak(this,
- "Leak of returned object when not using "
- "garbage collection (GC) in dual "
- "GC/non-GC code"));
- } else {
- leakAtReturn.reset(new Leak(this, "Leak of returned object"));
- }
- }
+ CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts) const {
+ if (!leakAtReturn)
+ leakAtReturn.reset(new Leak(this, "Leak of returned object"));
return leakAtReturn.get();
- }
}
- RetainSummaryManager &getSummaryManager(ASTContext &Ctx,
- bool GCEnabled) const {
+ RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
// FIXME: We don't support ARC being turned on and off during one analysis.
// (nor, for that matter, do we support changing ASTContexts)
bool ARCEnabled = (bool)Ctx.getLangOpts().ObjCAutoRefCount;
- if (GCEnabled) {
- if (!SummariesGC)
- SummariesGC.reset(new RetainSummaryManager(Ctx, true, ARCEnabled));
- else
- assert(SummariesGC->isARCEnabled() == ARCEnabled);
- return *SummariesGC;
- } else {
- if (!Summaries)
- Summaries.reset(new RetainSummaryManager(Ctx, false, ARCEnabled));
- else
- assert(Summaries->isARCEnabled() == ARCEnabled);
- return *Summaries;
- }
+ if (!Summaries)
+ Summaries.reset(new RetainSummaryManager(Ctx, ARCEnabled));
+ else
+ assert(Summaries->isARCEnabled() == ARCEnabled);
+ return *Summaries;
}
RetainSummaryManager &getSummaryManager(CheckerContext &C) const {
- return getSummaryManager(C.getASTContext(), C.isObjCGCEnabled());
+ return getSummaryManager(C.getASTContext());
}
void printState(raw_ostream &Out, ProgramStateRef State,
@@ -3177,7 +2967,6 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
break;
}
- case RetEffect::GCNotOwnedSymbol:
case RetEffect::NotOwnedSymbol: {
const Expr *Ex = CallOrMsg.getOriginExpr();
SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
@@ -3217,12 +3006,7 @@ ProgramStateRef
RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
CheckerContext &C) const {
- // In GC mode [... release] and [... retain] do nothing.
- // In ARC mode they shouldn't exist at all, but we just ignore them.
- bool IgnoreRetainMsg = C.isObjCGCEnabled();
- if (!IgnoreRetainMsg)
- IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
-
+ bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
switch (E) {
default:
break;
@@ -3230,18 +3014,15 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
E = IgnoreRetainMsg ? DoNothing : IncRef;
break;
case DecRefMsg:
- E = IgnoreRetainMsg ? DoNothing : DecRef;
+ E = IgnoreRetainMsg ? DoNothing: DecRef;
break;
case DecRefMsgAndStopTrackingHard:
E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTrackingHard;
break;
- case MakeCollectable:
- E = C.isObjCGCEnabled() ? DecRef : DoNothing;
- break;
}
// Handle all use-after-releases.
- if (!C.isObjCGCEnabled() && V.getKind() == RefVal::Released) {
+ if (V.getKind() == RefVal::Released) {
V = V ^ RefVal::ErrorUseAfterRelease;
hasErr = V.getKind();
return setRefBinding(state, sym, V);
@@ -3250,9 +3031,8 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
switch (E) {
case DecRefMsg:
case IncRefMsg:
- case MakeCollectable:
case DecRefMsgAndStopTrackingHard:
- llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted");
+ llvm_unreachable("DecRefMsg/IncRefMsg already converted");
case UnretainedOutParameter:
case RetainedOutParameter:
@@ -3260,13 +3040,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
"not have ref state.");
case Dealloc:
- // Any use of -dealloc in GC is *bad*.
- if (C.isObjCGCEnabled()) {
- V = V ^ RefVal::ErrorDeallocGC;
- hasErr = V.getKind();
- break;
- }
-
switch (V.getKind()) {
default:
llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
@@ -3294,8 +3067,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
return state;
case Autorelease:
- if (C.isObjCGCEnabled())
- return state;
// Update the autorelease counts.
V = V.autorelease();
break;
@@ -3312,11 +3083,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case RefVal::NotOwned:
V = V + 1;
break;
- case RefVal::Released:
- // Non-GC cases are handled above.
- assert(C.isObjCGCEnabled());
- V = (V ^ RefVal::Owned) + 1;
- break;
}
break;
@@ -3361,13 +3127,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
hasErr = V.getKind();
}
break;
-
- case RefVal::Released:
- // Non-GC cases are handled above.
- assert(C.isObjCGCEnabled());
- V = V ^ RefVal::ErrorUseAfterRelease;
- hasErr = V.getKind();
- break;
}
break;
}
@@ -3407,11 +3166,6 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
releaseNotOwned.reset(new BadRelease(this));
BT = releaseNotOwned.get();
break;
- case RefVal::ErrorDeallocGC:
- if (!deallocGC)
- deallocGC.reset(new DeallocGC(this));
- BT = deallocGC.get();
- break;
case RefVal::ErrorDeallocNotOwned:
if (!deallocNotOwned)
deallocNotOwned.reset(new DeallocNotOwned(this));
@@ -3421,7 +3175,7 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
assert(BT);
auto report = std::unique_ptr<BugReport>(
- new CFRefReport(*BT, C.getASTContext().getLangOpts(), C.isObjCGCEnabled(),
+ new CFRefReport(*BT, C.getASTContext().getLangOpts(),
SummaryLog, N, Sym));
report->addRange(ErrorRange);
C.emitReport(std::move(report));
@@ -3443,7 +3197,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
return false;
// For now, we're only handling the functions that return aliases of their
- // arguments: CFRetain and CFMakeCollectable (and their families).
+ // arguments: CFRetain (and its families).
// Eventually we should add other functions we can model entirely,
// such as CFRelease, which don't invalidate their arguments or globals.
if (CE->getNumArgs() != 1)
@@ -3460,19 +3214,14 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
bool hasTrustedImplementationAnnotation = false;
QualType ResultTy = CE->getCallReturnType(C.getASTContext());
- if (ResultTy->isObjCIdType()) {
- // Handle: id NSMakeCollectable(CFTypeRef)
- canEval = II->isStr("NSMakeCollectable");
- } else if (ResultTy->isPointerType()) {
+ if (ResultTy->isPointerType()) {
// Handle: (CF|CG|CV)Retain
// CFAutorelease
- // CFMakeCollectable
- // It's okay to be a little sloppy here (CGMakeCollectable doesn't exist).
+ // It's okay to be a little sloppy here.
if (cocoa::isRefType(ResultTy, "CF", FName) ||
cocoa::isRefType(ResultTy, "CG", FName) ||
cocoa::isRefType(ResultTy, "CV", FName)) {
- canEval = isRetain(FD, FName) || isAutorelease(FD, FName) ||
- isMakeCollectable(FD, FName);
+ canEval = isRetain(FD, FName) || isAutorelease(FD, FName);
} else {
if (FD->getDefinition()) {
canEval = isTrustedReferenceCountImplementation(FD->getDefinition());
@@ -3641,18 +3390,9 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
if (X.isReturnedOwned() && X.getCount() == 0) {
if (RE.getKind() != RetEffect::NoRet) {
bool hasError = false;
- if (C.isObjCGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
- // Things are more complicated with garbage collection. If the
- // returned object is suppose to be an Objective-C object, we have
- // a leak (as the caller expects a GC'ed object) because no
- // method should return ownership unless it returns a CF object.
- hasError = true;
- X = X ^ RefVal::ErrorGCLeakReturned;
- }
- else if (!RE.isOwned()) {
- // Either we are using GC and the returned object is a CF type
- // or we aren't using GC. In either case, we expect that the
- // enclosing method is expected to return ownership.
+ if (!RE.isOwned()) {
+ // The returning type is a CF, we expect the enclosing method should
+ // return ownership.
hasError = true;
X = X ^ RefVal::ErrorLeakReturned;
}
@@ -3665,9 +3405,8 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
if (N) {
const LangOptions &LOpts = C.getASTContext().getLangOpts();
- bool GCEnabled = C.isObjCGCEnabled();
C.emitReport(std::unique_ptr<BugReport>(new CFRefLeakReport(
- *getLeakAtReturnBug(LOpts, GCEnabled), LOpts, GCEnabled,
+ *getLeakAtReturnBug(LOpts), LOpts,
SummaryLog, N, Sym, C, IncludeAllocationLine)));
}
}
@@ -3695,7 +3434,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
C.emitReport(std::unique_ptr<BugReport>(new CFRefReport(
*returnNotOwnedForOwned, C.getASTContext().getLangOpts(),
- C.isObjCGCEnabled(), SummaryLog, N, Sym)));
+ SummaryLog, N, Sym)));
}
}
}
@@ -3839,7 +3578,6 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
if (!ACnt)
return state;
- assert(!Ctx.isObjCGCEnabled() && "Autorelease counts in GC mode?");
unsigned Cnt = V.getCount();
// FIXME: Handle sending 'autorelease' to already released object.
@@ -3899,7 +3637,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
Ctx.emitReport(std::unique_ptr<BugReport>(
- new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false,
+ new CFRefReport(*overAutorelease, LOpts,
SummaryLog, N, Sym, os.str())));
}
@@ -3947,13 +3685,12 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
- bool GCEnabled = Ctx.isObjCGCEnabled();
- CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts, GCEnabled)
- : getLeakAtReturnBug(LOpts, GCEnabled);
+ CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts)
+ : getLeakAtReturnBug(LOpts);
assert(BT && "BugType not initialized.");
Ctx.emitReport(std::unique_ptr<BugReport>(
- new CFRefLeakReport(*BT, LOpts, GCEnabled, SummaryLog, N, *I, Ctx,
+ new CFRefLeakReport(*BT, LOpts, SummaryLog, N, *I, Ctx,
IncludeAllocationLine)));
}
}
@@ -4130,7 +3867,7 @@ namespace objc_retain {
#define createCallEffect(D, KIND)\
ASTContext &Ctx = D->getASTContext();\
LangOptions L = Ctx.getLangOpts();\
- RetainSummaryManager M(Ctx, L.GCOnly, L.ObjCAutoRefCount);\
+ RetainSummaryManager M(Ctx, L.ObjCAutoRefCount);\
const RetainSummary *S = M.get ## KIND ## Summary(D);\
CallEffects CE(S->getRetEffect());\
CE.Receiver = S->getReceiverEffect();\
OpenPOWER on IntegriCloud