зеркало из https://github.com/microsoft/clang-1.git
[analyzer] Move the knowledge of whether or not GC is enabled for the current analysis from CFRefCount to ExprEngine.
Remove TransferFuncs from ExprEngine and AnalysisConsumer. Demote RetainReleaseChecker to a regular checker, and give it the name osx.cocoa.RetainCount (class name change coming shortly). Update tests accordingly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138998 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
e648ac33e5
Коммит
17a38e2636
|
@ -103,6 +103,10 @@ public:
|
|||
return getSValBuilder().getSymbolManager();
|
||||
}
|
||||
|
||||
bool isObjCGCEnabled() {
|
||||
return Eng.isObjCGCEnabled();
|
||||
}
|
||||
|
||||
ExplodedNode *generateNode(bool autoTransition = true) {
|
||||
assert(statement && "Only transitions with statements currently supported");
|
||||
ExplodedNode *N = generateNodeImpl(statement, getState(), false,
|
||||
|
|
|
@ -74,16 +74,17 @@ class ExprEngine : public SubEngine {
|
|||
// Obj-C Selectors.
|
||||
Selector* NSExceptionInstanceRaiseSelectors;
|
||||
Selector RaiseSel;
|
||||
|
||||
/// Whether or not GC is enabled in this analysis.
|
||||
bool ObjCGCEnabled;
|
||||
|
||||
/// The BugReporter associated with this engine. It is important that
|
||||
/// this object be placed at the very end of member variables so that its
|
||||
/// destructor is called before the rest of the ExprEngine is destroyed.
|
||||
GRBugReporter BR;
|
||||
|
||||
llvm::OwningPtr<TransferFuncs> TF;
|
||||
|
||||
public:
|
||||
ExprEngine(AnalysisManager &mgr, TransferFuncs *tf);
|
||||
ExprEngine(AnalysisManager &mgr, bool gcEnabled);
|
||||
|
||||
~ExprEngine();
|
||||
|
||||
|
@ -111,14 +112,11 @@ public:
|
|||
|
||||
SValBuilder &getSValBuilder() { return svalBuilder; }
|
||||
|
||||
TransferFuncs& getTF() { return *TF; }
|
||||
|
||||
BugReporter& getBugReporter() { return BR; }
|
||||
|
||||
StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
|
||||
|
||||
// FIXME: Remove once TransferFuncs is no longer referenced.
|
||||
void setTransferFunction(TransferFuncs* tf);
|
||||
bool isObjCGCEnabled() { return ObjCGCEnabled; }
|
||||
|
||||
/// ViewGraph - Visualize the ExplodedGraph created by executing the
|
||||
/// simulation.
|
||||
|
|
|
@ -311,6 +311,10 @@ def NSErrorChecker : Checker<"NSError">,
|
|||
HelpText<"Check usage of NSError** parameters">,
|
||||
DescFile<"NSErrorChecker.cpp">;
|
||||
|
||||
def RetainCountChecker : Checker<"RetainCount">,
|
||||
HelpText<"Check for leaks and improper reference count management">,
|
||||
DescFile<"RetainCountChecker.cpp">;
|
||||
|
||||
} // end "cocoa"
|
||||
|
||||
let ParentPackage = CocoaExperimental in {
|
||||
|
|
|
@ -2357,11 +2357,8 @@ class RetainReleaseChecker
|
|||
mutable SummaryLogTy SummaryLog;
|
||||
mutable bool ShouldResetSummaryLog;
|
||||
|
||||
LangOptions::GCMode GCMode;
|
||||
|
||||
public:
|
||||
RetainReleaseChecker()
|
||||
: ShouldResetSummaryLog(false), GCMode(LangOptions::HybridGC) {}
|
||||
RetainReleaseChecker() : ShouldResetSummaryLog(false) {}
|
||||
|
||||
virtual ~RetainReleaseChecker() {
|
||||
DeleteContainerSeconds(DeadSymbolTags);
|
||||
|
@ -2403,41 +2400,17 @@ public:
|
|||
ShouldResetSummaryLog = !SummaryLog.empty();
|
||||
}
|
||||
|
||||
void setGCMode(LangOptions::GCMode newGC) {
|
||||
// FIXME: This is definitely not const behavior; its intended use is to
|
||||
// set the GC mode for the entire coming code body. This setting will
|
||||
// most likely live somewhere else in the future.
|
||||
assert(newGC != LangOptions::HybridGC && "Analysis requires GC on or off.");
|
||||
GCMode = newGC;
|
||||
}
|
||||
|
||||
bool isGCEnabled() const {
|
||||
switch (GCMode) {
|
||||
case LangOptions::HybridGC:
|
||||
llvm_unreachable("GC mode not set yet!");
|
||||
case LangOptions::NonGC:
|
||||
return false;
|
||||
case LangOptions::GCOnly:
|
||||
return true;
|
||||
}
|
||||
|
||||
llvm_unreachable("Invalid/unknown GC mode.");
|
||||
}
|
||||
|
||||
bool isARCorGCEnabled(ASTContext &Ctx) const {
|
||||
return isGCEnabled() || Ctx.getLangOptions().ObjCAutoRefCount;
|
||||
}
|
||||
|
||||
CFRefBug *getLeakWithinFunctionBug(ASTContext &Ctx) const {
|
||||
if (isGCEnabled()) {
|
||||
CFRefBug *getLeakWithinFunctionBug(const LangOptions &LOpts,
|
||||
bool GCEnabled) const {
|
||||
if (GCEnabled) {
|
||||
if (!leakWithinFunctionGC)
|
||||
leakWithinFunctionGC.reset(new LeakWithinFunction("Leak of object when "
|
||||
"using garbage "
|
||||
"collection"));
|
||||
return &*leakWithinFunctionGC;
|
||||
return leakWithinFunctionGC.get();
|
||||
} else {
|
||||
if (!leakWithinFunction) {
|
||||
if (Ctx.getLangOptions().getGCMode() == LangOptions::HybridGC) {
|
||||
if (LOpts.getGCMode() == LangOptions::HybridGC) {
|
||||
leakWithinFunction.reset(new LeakWithinFunction("Leak of object when "
|
||||
"not using garbage "
|
||||
"collection (GC) in "
|
||||
|
@ -2447,19 +2420,19 @@ public:
|
|||
leakWithinFunction.reset(new LeakWithinFunction("Leak"));
|
||||
}
|
||||
}
|
||||
return &*leakWithinFunction;
|
||||
return leakWithinFunction.get();
|
||||
}
|
||||
}
|
||||
|
||||
CFRefBug *getLeakAtReturnBug(ASTContext &Ctx) const {
|
||||
if (isGCEnabled()) {
|
||||
CFRefBug *getLeakAtReturnBug(const LangOptions &LOpts, bool GCEnabled) const {
|
||||
if (GCEnabled) {
|
||||
if (!leakAtReturnGC)
|
||||
leakAtReturnGC.reset(new LeakAtReturn("Leak of returned object when "
|
||||
"using garbage collection"));
|
||||
return &*leakAtReturnGC;
|
||||
return leakAtReturnGC.get();
|
||||
} else {
|
||||
if (!leakAtReturn) {
|
||||
if (Ctx.getLangOptions().getGCMode() == LangOptions::HybridGC) {
|
||||
if (LOpts.getGCMode() == LangOptions::HybridGC) {
|
||||
leakAtReturn.reset(new LeakAtReturn("Leak of returned object when "
|
||||
"not using garbage collection "
|
||||
"(GC) in dual GC/non-GC code"));
|
||||
|
@ -2467,26 +2440,34 @@ public:
|
|||
leakAtReturn.reset(new LeakAtReturn("Leak of returned object"));
|
||||
}
|
||||
}
|
||||
return &*leakAtReturn;
|
||||
return leakAtReturn.get();
|
||||
}
|
||||
}
|
||||
|
||||
RetainSummaryManager &getSummaryManager(ASTContext &Ctx) const {
|
||||
if (isGCEnabled()) {
|
||||
if (!SummariesGC) {
|
||||
bool ARCEnabled = (bool)Ctx.getLangOptions().ObjCAutoRefCount;
|
||||
RetainSummaryManager &getSummaryManager(ASTContext &Ctx,
|
||||
bool GCEnabled) 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.getLangOptions().ObjCAutoRefCount;
|
||||
if (GCEnabled) {
|
||||
if (!SummariesGC)
|
||||
SummariesGC.reset(new RetainSummaryManager(Ctx, true, ARCEnabled));
|
||||
}
|
||||
else
|
||||
assert(SummariesGC->isARCEnabled() == ARCEnabled);
|
||||
return *SummariesGC;
|
||||
} else {
|
||||
if (!Summaries) {
|
||||
bool ARCEnabled = (bool)Ctx.getLangOptions().ObjCAutoRefCount;
|
||||
if (!Summaries)
|
||||
Summaries.reset(new RetainSummaryManager(Ctx, false, ARCEnabled));
|
||||
}
|
||||
else
|
||||
assert(Summaries->isARCEnabled() == ARCEnabled);
|
||||
return *Summaries;
|
||||
}
|
||||
}
|
||||
|
||||
RetainSummaryManager &getSummaryManager(CheckerContext &C) const {
|
||||
return getSummaryManager(C.getASTContext(), C.isObjCGCEnabled());
|
||||
}
|
||||
|
||||
void printState(raw_ostream &Out, const ProgramState *State,
|
||||
const char *NL, const char *Sep) const;
|
||||
|
||||
|
@ -2524,8 +2505,8 @@ public:
|
|||
void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const;
|
||||
|
||||
const ProgramState *updateSymbol(const ProgramState *state, SymbolRef sym,
|
||||
RefVal V, ArgEffect E,
|
||||
RefVal::Kind &hasErr) const;
|
||||
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
|
||||
CheckerContext &C) const;
|
||||
|
||||
void processNonLeakError(const ProgramState *St, SourceRange ErrorRange,
|
||||
RefVal::Kind ErrorKind, SymbolRef Sym,
|
||||
|
@ -2730,7 +2711,7 @@ void RetainReleaseChecker::checkPostStmt(const CastExpr *CE,
|
|||
return;
|
||||
|
||||
RefVal::Kind hasErr = (RefVal::Kind) 0;
|
||||
state = updateSymbol(state, Sym, *T, AE, hasErr);
|
||||
state = updateSymbol(state, Sym, *T, AE, hasErr, C);
|
||||
|
||||
if (hasErr) {
|
||||
// FIXME: If we get an error during a bridge cast, should we report it?
|
||||
|
@ -2748,7 +2729,7 @@ void RetainReleaseChecker::checkPostStmt(const CallExpr *CE,
|
|||
const Expr *Callee = CE->getCallee();
|
||||
SVal L = state->getSVal(Callee);
|
||||
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext());
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C);
|
||||
RetainSummary *Summ = 0;
|
||||
|
||||
// FIXME: Better support for blocks. For now we stop tracking anything
|
||||
|
@ -2776,7 +2757,7 @@ void RetainReleaseChecker::checkPostStmt(const CXXConstructExpr *CE,
|
|||
if (!Ctor)
|
||||
return;
|
||||
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext());
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C);
|
||||
RetainSummary *Summ = Summaries.getSummary(Ctor);
|
||||
|
||||
// If we didn't get a summary, this constructor doesn't affect retain counts.
|
||||
|
@ -2792,7 +2773,7 @@ void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg,
|
|||
const ProgramState *state = C.getState();
|
||||
ExplodedNode *Pred = C.getPredecessor();
|
||||
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext());
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C);
|
||||
|
||||
RetainSummary *Summ;
|
||||
if (Msg.isInstanceMessage()) {
|
||||
|
@ -2824,7 +2805,7 @@ void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
|
|||
|
||||
if (SymbolRef Sym = V.getAsLocSymbol()) {
|
||||
if (RefBindings::data_type *T = state->get<RefBindings>(Sym)) {
|
||||
state = updateSymbol(state, Sym, *T, Summ.getArg(idx), hasErr);
|
||||
state = updateSymbol(state, Sym, *T, Summ.getArg(idx), hasErr, C);
|
||||
if (hasErr) {
|
||||
ErrorRange = CallOrMsg.getArgSourceRange(idx);
|
||||
ErrorSym = Sym;
|
||||
|
@ -2842,7 +2823,8 @@ void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
|
|||
if (SymbolRef Sym = Receiver.getAsLocSymbol()) {
|
||||
if (const RefVal *T = state->get<RefBindings>(Sym)) {
|
||||
ReceiverIsTracked = true;
|
||||
state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
|
||||
state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(),
|
||||
hasErr, C);
|
||||
if (hasErr) {
|
||||
ErrorRange = CallOrMsg.getReceiverSourceRange();
|
||||
ErrorSym = Sym;
|
||||
|
@ -2862,7 +2844,7 @@ void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
|
|||
|
||||
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
|
||||
if (ReceiverIsTracked)
|
||||
RE = getSummaryManager(C.getASTContext()).getObjAllocRetEffect();
|
||||
RE = getSummaryManager(C).getObjAllocRetEffect();
|
||||
else
|
||||
RE = RetEffect::MakeNoRet();
|
||||
}
|
||||
|
@ -2940,21 +2922,24 @@ void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
|
|||
|
||||
const ProgramState *
|
||||
RetainReleaseChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
|
||||
RefVal V, ArgEffect E,
|
||||
RefVal::Kind &hasErr) const {
|
||||
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
|
||||
CheckerContext &C) const {
|
||||
// In GC mode [... release] and [... retain] do nothing.
|
||||
ASTContext &Ctx = state->getStateManager().getContext();
|
||||
bool IgnoreRetainMsg = C.isObjCGCEnabled();
|
||||
if (!IgnoreRetainMsg)
|
||||
IgnoreRetainMsg = (bool)C.getASTContext().getLangOptions().ObjCAutoRefCount;
|
||||
|
||||
switch (E) {
|
||||
default: break;
|
||||
case IncRefMsg: E = isARCorGCEnabled(Ctx) ? DoNothing : IncRef; break;
|
||||
case DecRefMsg: E = isARCorGCEnabled(Ctx) ? DoNothing : DecRef; break;
|
||||
case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
|
||||
case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
|
||||
NewAutoreleasePool; break;
|
||||
case IncRefMsg: E = IgnoreRetainMsg ? DoNothing : IncRef; break;
|
||||
case DecRefMsg: E = IgnoreRetainMsg ? DoNothing : DecRef; break;
|
||||
case MakeCollectable: E = C.isObjCGCEnabled() ? DecRef : DoNothing; break;
|
||||
case NewAutoreleasePool: E = C.isObjCGCEnabled() ? DoNothing :
|
||||
NewAutoreleasePool; break;
|
||||
}
|
||||
|
||||
// Handle all use-after-releases.
|
||||
if (!isGCEnabled() && V.getKind() == RefVal::Released) {
|
||||
if (!C.isObjCGCEnabled() && V.getKind() == RefVal::Released) {
|
||||
V = V ^ RefVal::ErrorUseAfterRelease;
|
||||
hasErr = V.getKind();
|
||||
return state->set<RefBindings>(sym, V);
|
||||
|
@ -2969,7 +2954,7 @@ RetainReleaseChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
|
|||
|
||||
case Dealloc:
|
||||
// Any use of -dealloc in GC is *bad*.
|
||||
if (isGCEnabled()) {
|
||||
if (C.isObjCGCEnabled()) {
|
||||
V = V ^ RefVal::ErrorDeallocGC;
|
||||
hasErr = V.getKind();
|
||||
break;
|
||||
|
@ -2992,7 +2977,7 @@ RetainReleaseChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
|
|||
break;
|
||||
|
||||
case NewAutoreleasePool:
|
||||
assert(!isGCEnabled());
|
||||
assert(!C.isObjCGCEnabled());
|
||||
return state->add<AutoreleaseStack>(sym);
|
||||
|
||||
case MayEscape:
|
||||
|
@ -3007,7 +2992,7 @@ RetainReleaseChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
|
|||
return state;
|
||||
|
||||
case Autorelease:
|
||||
if (isGCEnabled())
|
||||
if (C.isObjCGCEnabled())
|
||||
return state;
|
||||
|
||||
// Update the autorelease counts.
|
||||
|
@ -3029,7 +3014,7 @@ RetainReleaseChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
|
|||
break;
|
||||
case RefVal::Released:
|
||||
// Non-GC cases are handled above.
|
||||
assert(isGCEnabled());
|
||||
assert(C.isObjCGCEnabled());
|
||||
V = (V ^ RefVal::Owned) + 1;
|
||||
break;
|
||||
}
|
||||
|
@ -3065,7 +3050,7 @@ RetainReleaseChecker::updateSymbol(const ProgramState *state, SymbolRef sym,
|
|||
|
||||
case RefVal::Released:
|
||||
// Non-GC cases are handled above.
|
||||
assert(isGCEnabled());
|
||||
assert(C.isObjCGCEnabled());
|
||||
V = V ^ RefVal::ErrorUseAfterRelease;
|
||||
hasErr = V.getKind();
|
||||
break;
|
||||
|
@ -3113,7 +3098,8 @@ void RetainReleaseChecker::processNonLeakError(const ProgramState *St,
|
|||
|
||||
assert(BT);
|
||||
CFRefReport *report = new CFRefReport(*BT, C.getASTContext().getLangOptions(),
|
||||
isGCEnabled(), SummaryLog, N, Sym);
|
||||
C.isObjCGCEnabled(), SummaryLog,
|
||||
N, Sym);
|
||||
report->addRange(ErrorRange);
|
||||
C.EmitReport(report);
|
||||
}
|
||||
|
@ -3271,7 +3257,7 @@ void RetainReleaseChecker::checkPreStmt(const ReturnStmt *S,
|
|||
X = *T;
|
||||
|
||||
// Consult the summary of the enclosing method.
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C.getASTContext());
|
||||
RetainSummaryManager &Summaries = getSummaryManager(C);
|
||||
const Decl *CD = &Pred->getCodeDecl();
|
||||
|
||||
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
|
||||
|
@ -3301,7 +3287,7 @@ void RetainReleaseChecker::checkReturnWithRetEffect(const ReturnStmt *S,
|
|||
if (X.isReturnedOwned() && X.getCount() == 0) {
|
||||
if (RE.getKind() != RetEffect::NoRet) {
|
||||
bool hasError = false;
|
||||
if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
|
||||
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
|
||||
|
@ -3327,11 +3313,12 @@ void RetainReleaseChecker::checkReturnWithRetEffect(const ReturnStmt *S,
|
|||
ExplodedNode *N = Builder.generateNode(S, state, Pred,
|
||||
&ReturnOwnLeakTag);
|
||||
if (N) {
|
||||
ASTContext &Ctx = C.getASTContext();
|
||||
const LangOptions &LOpts = C.getASTContext().getLangOptions();
|
||||
bool GCEnabled = C.isObjCGCEnabled();
|
||||
CFRefReport *report =
|
||||
new CFRefLeakReport(*getLeakAtReturnBug(Ctx), Ctx.getLangOptions(),
|
||||
isGCEnabled(), SummaryLog, N, Sym,
|
||||
C.getEngine());
|
||||
new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled),
|
||||
LOpts, GCEnabled, SummaryLog,
|
||||
N, Sym, C.getEngine());
|
||||
C.EmitReport(report);
|
||||
}
|
||||
}
|
||||
|
@ -3353,8 +3340,8 @@ void RetainReleaseChecker::checkReturnWithRetEffect(const ReturnStmt *S,
|
|||
|
||||
CFRefReport *report =
|
||||
new CFRefReport(*returnNotOwnedForOwned,
|
||||
C.getASTContext().getLangOptions(), isGCEnabled(),
|
||||
SummaryLog, N, Sym);
|
||||
C.getASTContext().getLangOptions(),
|
||||
C.isObjCGCEnabled(), SummaryLog, N, Sym);
|
||||
C.EmitReport(report);
|
||||
}
|
||||
}
|
||||
|
@ -3377,7 +3364,7 @@ RetainReleaseChecker::handleAutoreleaseCounts(const ProgramState *state,
|
|||
if (!ACnt)
|
||||
return std::make_pair(Pred, state);
|
||||
|
||||
assert(!isGCEnabled() && "Autorelease counts in GC mode?");
|
||||
assert(!Eng.isObjCGCEnabled() && "Autorelease counts in GC mode?");
|
||||
unsigned Cnt = V.getCount();
|
||||
|
||||
// FIXME: Handle sending 'autorelease' to already released object.
|
||||
|
@ -3465,13 +3452,13 @@ RetainReleaseChecker::processLeaks(const ProgramState *state,
|
|||
for (SmallVectorImpl<SymbolRef>::iterator
|
||||
I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
|
||||
|
||||
ASTContext &Ctx = Eng.getContext();
|
||||
CFRefBug *BT = Pred ? getLeakWithinFunctionBug(Ctx)
|
||||
: getLeakAtReturnBug(Ctx);
|
||||
const LangOptions &LOpts = Eng.getContext().getLangOptions();
|
||||
bool GCEnabled = Eng.isObjCGCEnabled();
|
||||
CFRefBug *BT = Pred ? getLeakWithinFunctionBug(LOpts, GCEnabled)
|
||||
: getLeakAtReturnBug(LOpts, GCEnabled);
|
||||
assert(BT && "BugType not initialized.");
|
||||
|
||||
const LangOptions &LOpts = Ctx.getLangOptions();
|
||||
CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, isGCEnabled(),
|
||||
CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled,
|
||||
SummaryLog, N, *I, Eng);
|
||||
Eng.getBugReporter().EmitReport(report);
|
||||
}
|
||||
|
@ -3638,10 +3625,24 @@ void CFRefCount::RegisterChecks(ExprEngine& Eng) {
|
|||
RetainReleaseChecker *checker =
|
||||
Eng.getCheckerManager().registerChecker<RetainReleaseChecker>();
|
||||
assert(checker);
|
||||
checker->setGCMode(GCEnabled ? LangOptions::GCOnly : LangOptions::NonGC);
|
||||
//checker->setGCMode(GCEnabled ? LangOptions::GCOnly : LangOptions::NonGC);
|
||||
}
|
||||
|
||||
TransferFuncs* ento::MakeCFRefCountTF(ASTContext &Ctx, bool GCEnabled,
|
||||
const LangOptions& lopts) {
|
||||
return new CFRefCount(Ctx, GCEnabled, lopts);
|
||||
}
|
||||
|
||||
|
||||
// FIXME: This will be unnecessary once RetainReleaseChecker is moved to
|
||||
// the Checkers library (...and renamed to RetainCountChecker).
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
void registerRetainCountChecker(CheckerManager &Mgr);
|
||||
}
|
||||
}
|
||||
|
||||
void ento::registerRetainCountChecker(CheckerManager &Mgr) {
|
||||
Mgr.registerChecker<RetainReleaseChecker>();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ static inline Selector GetNullarySelector(const char* name, ASTContext &Ctx) {
|
|||
// Engine construction and deletion.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
|
||||
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled)
|
||||
: AMgr(mgr),
|
||||
Engine(*this),
|
||||
G(Engine.getGraph()),
|
||||
|
@ -63,10 +63,7 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
|
|||
EntryNode(NULL), currentStmt(NULL),
|
||||
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
|
||||
RaiseSel(GetNullarySelector("raise", getContext())),
|
||||
BR(mgr, *this), TF(tf) {
|
||||
|
||||
// FIXME: Eventually remove the TF object entirely.
|
||||
TF->RegisterChecks(*this);
|
||||
BR(mgr, *this), ObjCGCEnabled(gcEnabled) {
|
||||
|
||||
if (mgr.shouldEagerlyTrimExplodedGraph()) {
|
||||
// Enable eager node reclaimation when constructing the ExplodedGraph.
|
||||
|
|
|
@ -262,8 +262,8 @@ static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
|
|||
FindBlocks(DC, WL);
|
||||
}
|
||||
|
||||
static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
|
||||
Decl *D);
|
||||
static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr,
|
||||
Decl *D);
|
||||
|
||||
void AnalysisConsumer::HandleCode(Decl *D) {
|
||||
|
||||
|
@ -295,7 +295,7 @@ void AnalysisConsumer::HandleCode(Decl *D) {
|
|||
if ((*WI)->hasBody()) {
|
||||
checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
|
||||
if (checkerMgr->hasPathSensitiveCheckers())
|
||||
ActionObjCMemChecker(*this, *Mgr, *WI);
|
||||
RunPathSensitiveChecks(*this, *Mgr, *WI);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,18 +303,14 @@ void AnalysisConsumer::HandleCode(Decl *D) {
|
|||
// Path-sensitive checking.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
|
||||
Decl *D,
|
||||
TransferFuncs* tf) {
|
||||
|
||||
llvm::OwningPtr<TransferFuncs> TF(tf);
|
||||
|
||||
static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager &mgr,
|
||||
Decl *D, bool ObjCGCEnabled) {
|
||||
// Construct the analysis engine. We first query for the LiveVariables
|
||||
// information to see if the CFG is valid.
|
||||
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
|
||||
if (!mgr.getLiveVariables(D))
|
||||
return;
|
||||
ExprEngine Eng(mgr, TF.take());
|
||||
ExprEngine Eng(mgr, ObjCGCEnabled);
|
||||
|
||||
// Set the graph auditor.
|
||||
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
|
||||
|
@ -338,35 +334,25 @@ static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
|
|||
Eng.getBugReporter().FlushReports();
|
||||
}
|
||||
|
||||
static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
|
||||
Decl *D, bool GCEnabled) {
|
||||
static void RunPathSensitiveChecks(AnalysisConsumer &C, AnalysisManager &mgr,
|
||||
Decl *D) {
|
||||
|
||||
TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
|
||||
GCEnabled,
|
||||
mgr.getLangOptions());
|
||||
|
||||
ActionExprEngine(C, mgr, D, TF);
|
||||
}
|
||||
|
||||
static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
|
||||
Decl *D) {
|
||||
|
||||
switch (mgr.getLangOptions().getGCMode()) {
|
||||
default:
|
||||
assert (false && "Invalid GC mode.");
|
||||
case LangOptions::NonGC:
|
||||
ActionObjCMemCheckerAux(C, mgr, D, false);
|
||||
break;
|
||||
|
||||
case LangOptions::GCOnly:
|
||||
ActionObjCMemCheckerAux(C, mgr, D, true);
|
||||
break;
|
||||
|
||||
case LangOptions::HybridGC:
|
||||
ActionObjCMemCheckerAux(C, mgr, D, false);
|
||||
ActionObjCMemCheckerAux(C, mgr, D, true);
|
||||
break;
|
||||
}
|
||||
switch (mgr.getLangOptions().getGCMode()) {
|
||||
default:
|
||||
llvm_unreachable("Invalid GC mode.");
|
||||
case LangOptions::NonGC:
|
||||
ActionExprEngine(C, mgr, D, false);
|
||||
break;
|
||||
|
||||
case LangOptions::GCOnly:
|
||||
ActionExprEngine(C, mgr, D, true);
|
||||
break;
|
||||
|
||||
case LangOptions::HybridGC:
|
||||
ActionExprEngine(C, mgr, D, false);
|
||||
ActionExprEngine(C, mgr, D, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -fobjc-gc %s -Wno-implicit-function-declaration
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify -fobjc-gc %s -Wno-implicit-function-declaration
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The following code is reduced using delta-debugging from
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify -triple x86_64-apple-darwin9 %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.coreFoundation.CFNumber,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify -triple x86_64-apple-darwin9 %s
|
||||
|
||||
typedef signed long CFIndex;
|
||||
typedef const struct __CFAllocator * CFAllocatorRef;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify %s -analyzer-constraints=basic -analyzer-store=region
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -verify %s -analyzer-constraints=range -analyzer-store=region
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -verify %s -analyzer-constraints=basic -analyzer-store=region
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -verify %s -analyzer-constraints=range -analyzer-store=region
|
||||
|
||||
typedef struct objc_selector *SEL;
|
||||
typedef signed char BOOL;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
|
||||
typedef struct CGColorSpace *CGColorSpaceRef;
|
||||
extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
|
||||
// BEGIN delta-debugging reduced header stuff
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,osx.AtomicCAS,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-checker=deadcode.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-checker=deadcode.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core,deadcode.DeadStores -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
|
||||
// These declarations were reduced using Delta-Debugging from Foundation.h
|
||||
// on Mac OS X. The test cases are below.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=range -analyzer-store=region -fobjc-gc -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=range -analyzer-store=region -fobjc-gc -verify %s
|
||||
|
||||
typedef const void * CFTypeRef;
|
||||
typedef const struct __CFString * CFStringRef;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=basic -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -verify %s
|
||||
|
||||
typedef unsigned char Boolean;
|
||||
typedef signed long CFIndex;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.core -analyzer-checker=deadcode.DeadStores,osx.cocoa.RetainCount -verify %s
|
||||
|
||||
typedef signed char BOOL;
|
||||
typedef unsigned int NSUInteger;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-checker=deadcode.IdempotentOperations,osx.cocoa.RetainCount -verify %s
|
||||
|
||||
typedef signed char BOOL;
|
||||
typedef unsigned long NSUInteger;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-checker=deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-nonfragile-abi -fobjc-arc %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-nonfragile-abi -fobjc-arc %s
|
||||
|
||||
typedef signed char BOOL;
|
||||
typedef struct _NSZone NSZone;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -analyzer-constraints=range -fblocks -analyzer-output=plist -o - %s | FileCheck %s
|
||||
|
||||
void test_null_init(void) {
|
||||
int *p = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -pedantic -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -pedantic -analyzer-store=region -verify %s
|
||||
|
||||
// BEGIN delta-debugging reduced header stuff
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -verify %s
|
||||
|
||||
typedef signed char BOOL;
|
||||
typedef unsigned int NSUInteger;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-constraints=basic -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-constraints=basic -analyzer-store=region -verify %s
|
||||
//
|
||||
// This test case mainly checks that the retain/release checker doesn't crash
|
||||
// on this file.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,experimental.core -analyzer-store=region -verify %s
|
||||
|
||||
typedef const struct __CFString * CFStringRef;
|
||||
typedef const struct __CFAllocator * CFAllocatorRef;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.NSAutoreleasePool -analyzer-store=region -fobjc-gc-only -fblocks -verify %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Header stuff.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -analyzer-output=text -fobjc-gc-only -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -fobjc-gc-only -verify %s
|
||||
|
||||
/***
|
||||
This file is for testing the path-sensitive notes for retain/release errors.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -analyzer-output=text -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
|
||||
|
||||
/***
|
||||
This file is for testing the path-sensitive notes for retain/release errors.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -analyzer-max-loop 6 -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-store=region -analyzer-max-loop 6 -verify %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// The following code is reduced using delta-debugging from
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify -x objective-c++ %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify -x objective-c++ %s
|
||||
|
||||
#if __has_feature(attribute_ns_returns_retained)
|
||||
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -fblocks -verify %s
|
||||
|
||||
#if __has_feature(attribute_ns_returns_retained)
|
||||
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
|
||||
|
|
Загрузка…
Ссылка в новой задаче