summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
diff options
context:
space:
mode:
authorGeorge Karpenkov <ekarpenkov@apple.com>2018-08-17 21:40:38 +0000
committerGeorge Karpenkov <ekarpenkov@apple.com>2018-08-17 21:40:38 +0000
commit7390ddc968c52a0580c2eefdb4b5bc714fe3efc3 (patch)
tree1c9936bba68e3678170abd1ed1b2cff4fdca4bfa /clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
parentea4b476a301ae69fe10cd4e2bc726d3f3feccae4 (diff)
downloadbcm5719-llvm-7390ddc968c52a0580c2eefdb4b5bc714fe3efc3.tar.gz
bcm5719-llvm-7390ddc968c52a0580c2eefdb4b5bc714fe3efc3.zip
[analyzer] Drop support for GC mode in RetainCountChecker
A lot of code in RetainCountChecker deals with GC mode. Given that GC mode is deprecated, Apple does not ship runtime for it, and modern compiler toolchain does not support it, it makes sense to remove the code dealing with it in order to aid understanding of RetainCountChecker. Differential Revision: https://reviews.llvm.org/D50747 llvm-svn: 340091
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