[cfe-commits] r141250 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp test/Analysis/retain-release.m
Ted Kremenek
kremenek at apple.com
Wed Oct 5 16:54:30 PDT 2011
Author: kremenek
Date: Wed Oct 5 18:54:29 2011
New Revision: 141250
URL: http://llvm.org/viewvc/llvm-project?rev=141250&view=rev
Log:
Fix major regression in RetainCountChecker. DefaultSummaries were not being used when they were meant to be. Fixes <rdar://problem/10241614>.
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
cfe/trunk/test/Analysis/retain-release.m
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=141250&r1=141249&r2=141250&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Wed Oct 5 18:54:29 2011
@@ -481,19 +481,19 @@
namespace {
class ObjCSummaryCache {
- typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
+ typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy;
MapTy M;
public:
ObjCSummaryCache() {}
- RetainSummary* find(const ObjCInterfaceDecl *D, IdentifierInfo *ClsName,
+ const RetainSummary * find(const ObjCInterfaceDecl *D, IdentifierInfo *ClsName,
Selector S) {
// Lookup the method using the decl for the class @interface. If we
// have no decl, lookup using the class name.
return D ? find(D, S) : find(ClsName, S);
}
- RetainSummary* find(const ObjCInterfaceDecl *D, Selector S) {
+ const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) {
// Do a lookup with the (D,S) pair. If we find a match return
// the iterator.
ObjCSummaryKey K(D, S);
@@ -518,12 +518,12 @@
// Cache the summary with original key to make the next lookup faster
// and return the iterator.
- RetainSummary *Summ = I->second;
+ const RetainSummary *Summ = I->second;
M[K] = Summ;
return Summ;
}
- RetainSummary* find(IdentifierInfo* II, Selector S) {
+ const RetainSummary * find(IdentifierInfo* II, Selector S) {
// FIXME: Class method lookup. Right now we dont' have a good way
// of going between IdentifierInfo* and the class hierarchy.
MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
@@ -534,11 +534,11 @@
return I == M.end() ? NULL : I->second;
}
- RetainSummary*& operator[](ObjCSummaryKey K) {
+ const RetainSummary *& operator[](ObjCSummaryKey K) {
return M[K];
}
- RetainSummary*& operator[](Selector S) {
+ const RetainSummary *& operator[](Selector S) {
return M[ ObjCSummaryKey(S) ];
}
};
@@ -555,7 +555,7 @@
// Typedefs.
//==-----------------------------------------------------------------==//
- typedef llvm::DenseMap<const FunctionDecl*, RetainSummary*>
+ typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *>
FuncSummariesTy;
typedef ObjCSummaryCache ObjCMethodSummariesTy;
@@ -602,7 +602,7 @@
RetEffect ObjCInitRetE;
RetainSummary DefaultSummary;
- RetainSummary* StopSummary;
+ const RetainSummary *StopSummary;
//==-----------------------------------------------------------------==//
// Methods.
@@ -617,23 +617,28 @@
public:
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
- RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func);
+ const RetainSummary *getDefaultSummary() {
+ return &DefaultSummary;
+ }
+
+ const RetainSummary * getUnarySummary(const FunctionType* FT,
+ UnaryFuncKind func);
- RetainSummary* getCFSummaryCreateRule(const FunctionDecl *FD);
- RetainSummary* getCFSummaryGetRule(const FunctionDecl *FD);
- RetainSummary* getCFCreateGetRuleSummary(const FunctionDecl *FD);
-
- RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff,
- ArgEffect ReceiverEff = DoNothing,
- ArgEffect DefaultEff = MayEscape);
-
- RetainSummary* getPersistentSummary(RetEffect RE,
- ArgEffect ReceiverEff = DoNothing,
- ArgEffect DefaultEff = MayEscape) {
+ const RetainSummary * getCFSummaryCreateRule(const FunctionDecl *FD);
+ const RetainSummary * getCFSummaryGetRule(const FunctionDecl *FD);
+ const RetainSummary * getCFCreateGetRuleSummary(const FunctionDecl *FD);
+
+ const RetainSummary * getPersistentSummary(ArgEffects AE, RetEffect RetEff,
+ ArgEffect ReceiverEff = DoNothing,
+ ArgEffect DefaultEff = MayEscape);
+
+ const RetainSummary * getPersistentSummary(RetEffect RE,
+ ArgEffect ReceiverEff = DoNothing,
+ ArgEffect DefaultEff = MayEscape) {
return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff);
}
- RetainSummary *getPersistentStopSummary() {
+ const RetainSummary *getPersistentStopSummary() {
if (StopSummary)
return StopSummary;
@@ -643,28 +648,28 @@
return StopSummary;
}
- RetainSummary *getInitMethodSummary(QualType RetTy);
+ const RetainSummary *getInitMethodSummary(QualType RetTy);
void InitializeClassMethodSummaries();
void InitializeMethodSummaries();
private:
- void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) {
+ void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) {
ObjCClassMethodSummaries[S] = Summ;
}
- void addNSObjectMethSummary(Selector S, RetainSummary *Summ) {
+ void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) {
ObjCMethodSummaries[S] = Summ;
}
void addClassMethSummary(const char* Cls, const char* nullaryName,
- RetainSummary *Summ) {
+ const RetainSummary *Summ) {
IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
Selector S = GetNullarySelector(nullaryName, Ctx);
ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
void addInstMethSummary(const char* Cls, const char* nullaryName,
- RetainSummary *Summ) {
+ const RetainSummary *Summ) {
IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
Selector S = GetNullarySelector(nullaryName, Ctx);
ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
@@ -680,26 +685,26 @@
}
void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries,
- RetainSummary* Summ, va_list argp) {
+ const RetainSummary * Summ, va_list argp) {
Selector S = generateSelector(argp);
Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
- void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) {
+ void addInstMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
va_list argp;
va_start(argp, Summ);
addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
va_end(argp);
}
- void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) {
+ void addClsMethSummary(const char* Cls, const RetainSummary * Summ, ...) {
va_list argp;
va_start(argp, Summ);
addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp);
va_end(argp);
}
- void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) {
+ void addClsMethSummary(IdentifierInfo *II, const RetainSummary * Summ, ...) {
va_list argp;
va_start(argp, Summ);
addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp);
@@ -731,29 +736,31 @@
InitializeMethodSummaries();
}
- RetainSummary* getSummary(const FunctionDecl *FD);
+ const RetainSummary * getSummary(const FunctionDecl *FD);
- RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
- const ProgramState *state,
- const LocationContext *LC);
+ const RetainSummary *getInstanceMethodSummary(const ObjCMessage &msg,
+ const ProgramState *state,
+ const LocationContext *LC);
- RetainSummary* getInstanceMethodSummary(const ObjCMessage &msg,
- const ObjCInterfaceDecl *ID) {
+ const RetainSummary * getInstanceMethodSummary(const ObjCMessage &msg,
+ const ObjCInterfaceDecl *ID) {
return getInstanceMethodSummary(msg.getSelector(), 0,
ID, msg.getMethodDecl(), msg.getType(Ctx));
}
- RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD,
- QualType RetTy);
-
- RetainSummary *getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
- const ObjCInterfaceDecl *ID,
- const ObjCMethodDecl *MD,
- QualType RetTy);
+ const RetainSummary * getInstanceMethodSummary(Selector S,
+ IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy);
+
+ const RetainSummary *getClassMethodSummary(Selector S,
+ IdentifierInfo *ClsName,
+ const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy);
- RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
+ const RetainSummary *getClassMethodSummary(const ObjCMessage &msg) {
const ObjCInterfaceDecl *Class = 0;
if (!msg.isInstanceMessage())
Class = msg.getReceiverInterface();
@@ -766,7 +773,7 @@
/// getMethodSummary - This version of getMethodSummary is used to query
/// the summary for the current method being analyzed.
- RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
+ const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
// FIXME: Eventually this should be unneeded.
const ObjCInterfaceDecl *ID = MD->getClassInterface();
Selector S = MD->getSelector();
@@ -779,13 +786,13 @@
return getClassMethodSummary(S, ClsName, ID, MD, ResultTy);
}
- RetainSummary* getCommonMethodSummary(const ObjCMethodDecl *MD,
- Selector S, QualType RetTy);
+ const RetainSummary * getCommonMethodSummary(const ObjCMethodDecl *MD,
+ Selector S, QualType RetTy);
- void updateSummaryFromAnnotations(RetainSummary *&Summ,
+ void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const ObjCMethodDecl *MD);
- void updateSummaryFromAnnotations(RetainSummary *&Summ,
+ void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD);
bool isGCEnabled() const { return GCEnabled; }
@@ -794,8 +801,8 @@
bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
- RetainSummary *copySummary(RetainSummary *OldSumm) {
- RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+ const RetainSummary *copySummary(const RetainSummary *OldSumm) {
+ RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
new (Summ) RetainSummary(*OldSumm);
return Summ;
}
@@ -807,28 +814,34 @@
// and then copied into managed memory.
class RetainSummaryTemplate {
RetainSummaryManager &Manager;
- RetainSummary *&RealSummary;
+ const RetainSummary *&RealSummary;
+ const RetainSummary *BaseSummary;
RetainSummary ScratchSummary;
bool Accessed;
public:
- RetainSummaryTemplate(RetainSummary *&real, const RetainSummary &base,
+ RetainSummaryTemplate(const RetainSummary *&real, const RetainSummary &base,
RetainSummaryManager &manager)
- : Manager(manager), RealSummary(real), ScratchSummary(base), Accessed(false)
- {}
+ : Manager(manager),
+ RealSummary(real),
+ BaseSummary(&base),
+ ScratchSummary(base),
+ Accessed(false) {}
~RetainSummaryTemplate() {
- if (!RealSummary && Accessed)
+ if (Accessed)
RealSummary = Manager.copySummary(&ScratchSummary);
+ else if (!RealSummary)
+ RealSummary = BaseSummary;
}
RetainSummary &operator*() {
Accessed = true;
- return RealSummary ? *RealSummary : ScratchSummary;
+ return ScratchSummary;
}
RetainSummary *operator->() {
Accessed = true;
- return RealSummary ? RealSummary : &ScratchSummary;
+ return &ScratchSummary;
}
};
@@ -844,12 +857,12 @@
return AE;
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
ArgEffect ReceiverEff,
ArgEffect DefaultEff) {
// Create the summary and return it.
- RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+ RetainSummary *Summ = (RetainSummary *) BPAlloc.Allocate<RetainSummary>();
new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff);
return Summ;
}
@@ -872,14 +885,14 @@
return FName.find("MakeCollectable") != StringRef::npos;
}
-RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl *FD) {
+const RetainSummary * RetainSummaryManager::getSummary(const FunctionDecl *FD) {
// Look up a summary in our cache of FunctionDecls -> Summaries.
FuncSummariesTy::iterator I = FuncSummaries.find(FD);
if (I != FuncSummaries.end())
return I->second;
// No summary? Generate one.
- RetainSummary *S = 0;
+ const RetainSummary *S = 0;
do {
// We generate "stop" summaries for implicitly defined functions.
@@ -1068,7 +1081,7 @@
return S;
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl *FD) {
if (coreFoundation::followsCreateRule(FD))
return getCFSummaryCreateRule(FD);
@@ -1076,7 +1089,7 @@
return getCFSummaryGetRule(FD);
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getUnarySummary(const FunctionType* FT,
UnaryFuncKind func) {
@@ -1100,14 +1113,14 @@
return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
assert (ScratchArgs.isEmpty());
return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
assert (ScratchArgs.isEmpty());
return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
@@ -1118,7 +1131,7 @@
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
assert(ScratchArgs.isEmpty());
// 'init' methods conceptually return a newly allocated object and claim
@@ -1127,11 +1140,11 @@
coreFoundation::isCFObjectRef(RetTy))
return getPersistentSummary(ObjCInitRetE, DecRefMsg);
- return 0;
+ return getDefaultSummary();
}
void
-RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary *&Summ,
+RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD) {
if (!FD)
return;
@@ -1179,8 +1192,8 @@
}
void
-RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary *&Summ,
- const ObjCMethodDecl *MD) {
+RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
+ const ObjCMethodDecl *MD) {
if (!MD)
return;
@@ -1233,7 +1246,7 @@
}
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy) {
@@ -1286,12 +1299,12 @@
}
if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing)
- return 0;
+ return getDefaultSummary();
return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape);
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getInstanceMethodSummary(const ObjCMessage &msg,
const ProgramState *state,
const LocationContext *LC) {
@@ -1334,7 +1347,7 @@
return getInstanceMethodSummary(msg, ID);
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getInstanceMethodSummary(Selector S,
IdentifierInfo *ClsName,
const ObjCInterfaceDecl *ID,
@@ -1342,7 +1355,7 @@
QualType RetTy) {
// Look up a summary in our summary cache.
- RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S);
+ const RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S);
if (!Summ) {
assert(ScratchArgs.isEmpty());
@@ -1363,14 +1376,14 @@
return Summ;
}
-RetainSummary*
+const RetainSummary *
RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
const ObjCInterfaceDecl *ID,
const ObjCMethodDecl *MD,
QualType RetTy) {
assert(ClsName && "Class name must be specified.");
- RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S);
+ const RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S);
if (!Summ) {
Summ = getCommonMethodSummary(MD, S, RetTy);
@@ -1402,7 +1415,7 @@
// used for delegates that can release the object. When we have better
// inter-procedural analysis we can potentially do something better. This
// workaround is to remove false positives.
- RetainSummary *Summ =
+ const RetainSummary *Summ =
getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking);
IdentifierInfo *NSObjectII = &Ctx.Idents.get("NSObject");
addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
@@ -1427,7 +1440,7 @@
// Create the "init" selector. It just acts as a pass-through for the
// receiver.
- RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg);
+ const RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg);
addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
// awakeAfterUsingCoder: behaves basically like an 'init' method. It
@@ -1436,13 +1449,13 @@
InitSumm);
// The next methods are allocators.
- RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
- RetainSummary *CFAllocSumm =
+ const RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
+ const RetainSummary *CFAllocSumm =
getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
// Create the "retain" selector.
RetEffect NoRet = RetEffect::MakeNoRet();
- RetainSummary *Summ = getPersistentSummary(NoRet, IncRefMsg);
+ const RetainSummary *Summ = getPersistentSummary(NoRet, IncRefMsg);
addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
// Create the "release" selector.
@@ -1471,7 +1484,7 @@
// Thus, we need to track an NSWindow's display status.
// This is tracked in <rdar://problem/6062711>.
// See also http://llvm.org/bugs/show_bug.cgi?id=3714.
- RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(),
+ const RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(),
StopTracking,
StopTracking);
@@ -2561,7 +2574,7 @@
SVal L = state->getSVal(Callee);
RetainSummaryManager &Summaries = getSummaryManager(C);
- RetainSummary *Summ = 0;
+ const RetainSummary *Summ = 0;
// FIXME: Better support for blocks. For now we stop tracking anything
// that is passed to blocks.
@@ -2575,9 +2588,8 @@
Summ = Summaries.getSummary(MD);
}
- // If we didn't get a summary, this function doesn't affect retain counts.
if (!Summ)
- return;
+ Summ = Summaries.getDefaultSummary();
checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
}
@@ -2589,7 +2601,7 @@
return;
RetainSummaryManager &Summaries = getSummaryManager(C);
- RetainSummary *Summ = Summaries.getSummary(Ctor);
+ const RetainSummary *Summ = Summaries.getSummary(Ctor);
// If we didn't get a summary, this constructor doesn't affect retain counts.
if (!Summ)
@@ -2606,7 +2618,7 @@
RetainSummaryManager &Summaries = getSummaryManager(C);
- RetainSummary *Summ;
+ const RetainSummary *Summ;
if (Msg.isInstanceMessage()) {
const LocationContext *LC = Pred->getLocationContext();
Summ = Summaries.getInstanceMethodSummary(Msg, state, LC);
Modified: cfe/trunk/test/Analysis/retain-release.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=141250&r1=141249&r2=141250&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release.m (original)
+++ cfe/trunk/test/Analysis/retain-release.m Wed Oct 5 18:54:29 2011
@@ -146,7 +146,9 @@
typedef double NSTimeInterval;
@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
@end typedef unsigned short unichar;
- at interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+ at interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
+- (NSUInteger)length;
+- (NSString *)stringByAppendingString:(NSString *)aString;
- ( const char *)UTF8String;
- (id)initWithUTF8String:(const char *)nullTerminatedCString;
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
@@ -268,6 +270,12 @@
CGGradientDrawingOptions options);
extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+ at interface NSMutableArray : NSObject
+- (void)addObject:(id)object;
++ (id)array;
+ at end
+
+
//===----------------------------------------------------------------------===//
// Test cases.
//===----------------------------------------------------------------------===//
@@ -1571,3 +1579,28 @@
CFAbsoluteTime t = CFAbsoluteTimeGetCurrent();
global = CFDateCreate(0, t); // no-warning
}
+
+// <rdar://problem/10232019> - Test that objects passed to containers
+// are marked "escaped".
+
+void rdar10232019() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [array addObject:string];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // no-warning
+ NSLog(@"%@", otherString);
+}
+
+void rdar10232019_positive() {
+ NSMutableArray *array = [NSMutableArray array];
+
+ NSString *string = [[NSString alloc] initWithUTF8String:"foo"];
+ [string release];
+
+ NSString *otherString = [string stringByAppendingString:@"bar"]; // expected-warning {{Reference-counted object is used after it is release}}
+ NSLog(@"%@", otherString);
+}
+
More information about the cfe-commits
mailing list