forked from OSchip/llvm-project
[arcmt] Remove rewriteAllocCopyWithZone transformation; not needed anymore.
llvm-svn: 133762
This commit is contained in:
parent
63b45fef45
commit
795550691e
|
@ -1,223 +0,0 @@
|
||||||
//===--- TransAllocCopyWithZone.cpp - Tranformations to ARC mode ----------===//
|
|
||||||
//
|
|
||||||
// The LLVM Compiler Infrastructure
|
|
||||||
//
|
|
||||||
// This file is distributed under the University of Illinois Open Source
|
|
||||||
// License. See LICENSE.TXT for details.
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
//
|
|
||||||
// rewriteAllocCopyWithZone:
|
|
||||||
//
|
|
||||||
// Calls to +allocWithZone/-copyWithZone/-mutableCopyWithZone are changed to
|
|
||||||
// +alloc/-copy/-mutableCopy if we can safely remove the given parameter.
|
|
||||||
//
|
|
||||||
// Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
|
|
||||||
// ---->
|
|
||||||
// Foo *foo1 = [[Foo alloc] init];
|
|
||||||
//
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
#include "Transforms.h"
|
|
||||||
#include "Internals.h"
|
|
||||||
#include "clang/Sema/SemaDiagnostic.h"
|
|
||||||
|
|
||||||
using namespace clang;
|
|
||||||
using namespace arcmt;
|
|
||||||
using namespace trans;
|
|
||||||
using llvm::StringRef;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class AllocCopyWithZoneRewriter :
|
|
||||||
public RecursiveASTVisitor<AllocCopyWithZoneRewriter> {
|
|
||||||
Decl *Dcl;
|
|
||||||
Stmt *Body;
|
|
||||||
MigrationPass &Pass;
|
|
||||||
|
|
||||||
Selector allocWithZoneSel;
|
|
||||||
Selector copyWithZoneSel;
|
|
||||||
Selector mutableCopyWithZoneSel;
|
|
||||||
Selector zoneSel;
|
|
||||||
IdentifierInfo *NSZoneII;
|
|
||||||
|
|
||||||
std::vector<DeclStmt *> NSZoneVars;
|
|
||||||
std::vector<Expr *> Removals;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AllocCopyWithZoneRewriter(Decl *D, MigrationPass &pass)
|
|
||||||
: Dcl(D), Body(0), Pass(pass) {
|
|
||||||
SelectorTable &sels = pass.Ctx.Selectors;
|
|
||||||
IdentifierTable &ids = pass.Ctx.Idents;
|
|
||||||
allocWithZoneSel = sels.getUnarySelector(&ids.get("allocWithZone"));
|
|
||||||
copyWithZoneSel = sels.getUnarySelector(&ids.get("copyWithZone"));
|
|
||||||
mutableCopyWithZoneSel = sels.getUnarySelector(
|
|
||||||
&ids.get("mutableCopyWithZone"));
|
|
||||||
zoneSel = sels.getNullarySelector(&ids.get("zone"));
|
|
||||||
NSZoneII = &ids.get("_NSZone");
|
|
||||||
}
|
|
||||||
|
|
||||||
void transformBody(Stmt *body) {
|
|
||||||
Body = body;
|
|
||||||
// Don't change allocWithZone/copyWithZone messages inside
|
|
||||||
// custom implementations of such methods, it can lead to infinite loops.
|
|
||||||
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Dcl)) {
|
|
||||||
Selector sel = MD->getSelector();
|
|
||||||
if (sel == allocWithZoneSel ||
|
|
||||||
sel == copyWithZoneSel ||
|
|
||||||
sel == mutableCopyWithZoneSel ||
|
|
||||||
sel == zoneSel)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TraverseStmt(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
~AllocCopyWithZoneRewriter() {
|
|
||||||
for (std::vector<DeclStmt *>::reverse_iterator
|
|
||||||
I = NSZoneVars.rbegin(), E = NSZoneVars.rend(); I != E; ++I) {
|
|
||||||
DeclStmt *DS = *I;
|
|
||||||
DeclGroupRef group = DS->getDeclGroup();
|
|
||||||
std::vector<Expr *> varRemovals = Removals;
|
|
||||||
|
|
||||||
bool areAllVarsUnused = true;
|
|
||||||
for (std::reverse_iterator<DeclGroupRef::iterator>
|
|
||||||
DI(group.end()), DE(group.begin()); DI != DE; ++DI) {
|
|
||||||
VarDecl *VD = cast<VarDecl>(*DI);
|
|
||||||
if (isNSZoneVarUsed(VD, varRemovals)) {
|
|
||||||
areAllVarsUnused = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
varRemovals.push_back(VD->getInit());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (areAllVarsUnused) {
|
|
||||||
Transaction Trans(Pass.TA);
|
|
||||||
clearUnavailableDiags(DS);
|
|
||||||
Pass.TA.removeStmt(DS);
|
|
||||||
Removals.swap(varRemovals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
|
|
||||||
if (!isAllocCopyWithZoneCall(E))
|
|
||||||
return true;
|
|
||||||
Expr *arg = E->getArg(0);
|
|
||||||
if (paramToAllocWithZoneHasSideEffects(arg))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Pass.TA.startTransaction();
|
|
||||||
|
|
||||||
clearUnavailableDiags(arg);
|
|
||||||
Pass.TA.clearDiagnostic(diag::err_unavailable_message,
|
|
||||||
E->getReceiverRange().getBegin());
|
|
||||||
|
|
||||||
Pass.TA.remove(SourceRange(E->getSelectorLoc(), arg->getLocEnd()));
|
|
||||||
StringRef rewrite;
|
|
||||||
if (E->getSelector() == allocWithZoneSel)
|
|
||||||
rewrite = "alloc";
|
|
||||||
else if (E->getSelector() == copyWithZoneSel)
|
|
||||||
rewrite = "copy";
|
|
||||||
else {
|
|
||||||
assert(E->getSelector() == mutableCopyWithZoneSel);
|
|
||||||
rewrite = "mutableCopy";
|
|
||||||
}
|
|
||||||
Pass.TA.insert(E->getSelectorLoc(), rewrite);
|
|
||||||
|
|
||||||
bool failed = Pass.TA.commitTransaction();
|
|
||||||
if (!failed)
|
|
||||||
Removals.push_back(arg);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VisitDeclStmt(DeclStmt *DS) {
|
|
||||||
DeclGroupRef group = DS->getDeclGroup();
|
|
||||||
if (group.begin() == group.end())
|
|
||||||
return true;
|
|
||||||
for (DeclGroupRef::iterator
|
|
||||||
DI = group.begin(), DE = group.end(); DI != DE; ++DI)
|
|
||||||
if (!isRemovableNSZoneVar(*DI))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
NSZoneVars.push_back(DS);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool isRemovableNSZoneVar(Decl *D) {
|
|
||||||
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
|
|
||||||
if (isNSZone(VD->getType()))
|
|
||||||
return !paramToAllocWithZoneHasSideEffects(VD->getInit());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNSZone(RecordDecl *RD) {
|
|
||||||
return RD && RD->getIdentifier() == NSZoneII;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNSZone(QualType Ty) {
|
|
||||||
QualType pointee = Ty->getPointeeType();
|
|
||||||
if (pointee.isNull())
|
|
||||||
return false;
|
|
||||||
if (const RecordType *recT = pointee->getAsStructureType())
|
|
||||||
return isNSZone(recT->getDecl());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNSZoneVarUsed(VarDecl *D, std::vector<Expr *> &removals) {
|
|
||||||
ExprSet refs;
|
|
||||||
collectRefs(D, Body, refs);
|
|
||||||
clearRefsIn(removals.begin(), removals.end(), refs);
|
|
||||||
|
|
||||||
return !refs.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isAllocCopyWithZoneCall(ObjCMessageExpr *E) {
|
|
||||||
if (E->getNumArgs() == 1 &&
|
|
||||||
E->getSelector() == allocWithZoneSel &&
|
|
||||||
(E->isClassMessage() ||
|
|
||||||
Pass.TA.hasDiagnostic(diag::err_unavailable_message,
|
|
||||||
E->getReceiverRange().getBegin())))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return E->isInstanceMessage() &&
|
|
||||||
E->getNumArgs() == 1 &&
|
|
||||||
(E->getSelector() == copyWithZoneSel ||
|
|
||||||
E->getSelector() == mutableCopyWithZoneSel);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isZoneCall(ObjCMessageExpr *E) {
|
|
||||||
return E->isInstanceMessage() &&
|
|
||||||
E->getNumArgs() == 0 &&
|
|
||||||
E->getSelector() == zoneSel;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool paramToAllocWithZoneHasSideEffects(Expr *E) {
|
|
||||||
if (!hasSideEffects(E, Pass.Ctx))
|
|
||||||
return false;
|
|
||||||
E = E->IgnoreParenCasts();
|
|
||||||
ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
|
|
||||||
if (!ME)
|
|
||||||
return true;
|
|
||||||
if (!isZoneCall(ME))
|
|
||||||
return true;
|
|
||||||
return hasSideEffects(ME->getInstanceReceiver(), Pass.Ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearUnavailableDiags(Stmt *S) {
|
|
||||||
if (S)
|
|
||||||
Pass.TA.clearDiagnostic(diag::err_unavailable,
|
|
||||||
diag::err_unavailable_message,
|
|
||||||
S->getSourceRange());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
void trans::rewriteAllocCopyWithZone(MigrationPass &pass) {
|
|
||||||
BodyTransform<AllocCopyWithZoneRewriter> trans(pass);
|
|
||||||
trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
|
|
||||||
}
|
|
|
@ -218,7 +218,6 @@ static void independentTransforms(MigrationPass &pass) {
|
||||||
makeAssignARCSafe(pass);
|
makeAssignARCSafe(pass);
|
||||||
rewriteUnbridgedCasts(pass);
|
rewriteUnbridgedCasts(pass);
|
||||||
rewriteBlockObjCVariable(pass);
|
rewriteBlockObjCVariable(pass);
|
||||||
rewriteAllocCopyWithZone(pass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TransformFn> arcmt::getAllTransformations() {
|
std::vector<TransformFn> arcmt::getAllTransformations() {
|
||||||
|
|
|
@ -31,7 +31,6 @@ namespace trans {
|
||||||
|
|
||||||
void rewriteAutoreleasePool(MigrationPass &pass);
|
void rewriteAutoreleasePool(MigrationPass &pass);
|
||||||
void rewriteUnbridgedCasts(MigrationPass &pass);
|
void rewriteUnbridgedCasts(MigrationPass &pass);
|
||||||
void rewriteAllocCopyWithZone(MigrationPass &pass);
|
|
||||||
void makeAssignARCSafe(MigrationPass &pass);
|
void makeAssignARCSafe(MigrationPass &pass);
|
||||||
void removeRetainReleaseDealloc(MigrationPass &pass);
|
void removeRetainReleaseDealloc(MigrationPass &pass);
|
||||||
void removeZeroOutPropsInDealloc(MigrationPass &pass);
|
void removeZeroOutPropsInDealloc(MigrationPass &pass);
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
|
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct _NSZone NSZone;
|
|
||||||
typedef int BOOL;
|
typedef int BOOL;
|
||||||
typedef unsigned NSUInteger;
|
typedef unsigned NSUInteger;
|
||||||
typedef int int32_t;
|
typedef int int32_t;
|
||||||
|
@ -18,23 +17,12 @@ typedef unsigned char UChar;
|
||||||
- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
||||||
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
||||||
- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
||||||
|
|
||||||
- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@protocol NSCopying
|
|
||||||
- (id)copyWithZone:(NSZone *)zone;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@protocol NSMutableCopying
|
|
||||||
- (id)mutableCopyWithZone:(NSZone *)zone;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface NSObject <NSObject> {}
|
@interface NSObject <NSObject> {}
|
||||||
- (id)init;
|
- (id)init;
|
||||||
|
|
||||||
+ (id)new;
|
+ (id)new;
|
||||||
+ (id)allocWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
+ (id)alloc;
|
+ (id)alloc;
|
||||||
- (void)dealloc;
|
- (void)dealloc;
|
||||||
|
|
||||||
|
@ -42,13 +30,8 @@ typedef unsigned char UChar;
|
||||||
|
|
||||||
- (id)copy;
|
- (id)copy;
|
||||||
- (id)mutableCopy;
|
- (id)mutableCopy;
|
||||||
|
|
||||||
+ (id)copyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
+ (id)mutableCopyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
extern void NSRecycleZone(NSZone *zone);
|
|
||||||
|
|
||||||
NS_AUTOMATED_REFCOUNT_UNAVAILABLE
|
NS_AUTOMATED_REFCOUNT_UNAVAILABLE
|
||||||
@interface NSAutoreleasePool : NSObject {
|
@interface NSAutoreleasePool : NSObject {
|
||||||
@private
|
@private
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
// RUN: %clang_cc1 -arcmt-check -verify -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi %s
|
|
||||||
|
|
||||||
#if __has_feature(objc_arr)
|
|
||||||
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
|
|
||||||
#else
|
|
||||||
#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _NSZone NSZone;
|
|
||||||
typedef int BOOL;
|
|
||||||
typedef unsigned NSUInteger;
|
|
||||||
|
|
||||||
@protocol NSObject
|
|
||||||
- (BOOL)isEqual:(id)object;
|
|
||||||
- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
|
|
||||||
- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE; // expected-note {{marked unavailable here}}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@protocol NSCopying
|
|
||||||
- (id)copyWithZone:(NSZone *)zone;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@protocol NSMutableCopying
|
|
||||||
- (id)mutableCopyWithZone:(NSZone *)zone;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface NSObject <NSObject> {}
|
|
||||||
- (id)init;
|
|
||||||
|
|
||||||
+ (id)allocWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE; // expected-note 2 {{marked unavailable here}}
|
|
||||||
+ (id)alloc;
|
|
||||||
- (void)dealloc;
|
|
||||||
|
|
||||||
- (void)finalize;
|
|
||||||
|
|
||||||
- (id)copy;
|
|
||||||
- (id)mutableCopy;
|
|
||||||
|
|
||||||
+ (id)copyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
+ (id)mutableCopyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
|
|
||||||
@end
|
|
||||||
|
|
||||||
extern void NSRecycleZone(NSZone *zone);
|
|
||||||
|
|
||||||
id IhaveSideEffect();
|
|
||||||
|
|
||||||
@interface Foo : NSObject <NSCopying, NSMutableCopying> {
|
|
||||||
id bar;
|
|
||||||
}
|
|
||||||
@property (retain) id bar;
|
|
||||||
-(id)test:(id)obj;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation Foo
|
|
||||||
|
|
||||||
@synthesize bar;
|
|
||||||
|
|
||||||
-(id)test:(id)obj {
|
|
||||||
Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
|
|
||||||
Foo *foo2 = [[Foo allocWithZone:[super zone]] init];
|
|
||||||
Foo *foo3 = [[Foo allocWithZone:[IhaveSideEffect() zone]] init]; // expected-error {{not available}}
|
|
||||||
NSRecycleZone([self zone]); // expected-error {{not available}}
|
|
||||||
|
|
||||||
foo1 = [foo1 copyWithZone:[self zone]];
|
|
||||||
foo2 = [foo1 copyWithZone:[super zone]];
|
|
||||||
foo3 = [foo1 copyWithZone:[IhaveSideEffect() zone]];
|
|
||||||
foo1 = [foo1 mutableCopyWithZone:[self zone]];
|
|
||||||
|
|
||||||
return foo1;
|
|
||||||
}
|
|
||||||
|
|
||||||
+(id)allocWithZone:(NSZone *)zone {
|
|
||||||
return [super allocWithZone:zone]; // expected-error {{not available in automatic reference counting mode}}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,42 +0,0 @@
|
||||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
|
|
||||||
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
|
|
||||||
// RUN: diff %t %s.result
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
@interface Foo : NSObject <NSCopying, NSMutableCopying> {
|
|
||||||
id bar;
|
|
||||||
}
|
|
||||||
@property (retain) id bar;
|
|
||||||
-(id)test:(NSZone *)z;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation Foo
|
|
||||||
|
|
||||||
@synthesize bar;
|
|
||||||
|
|
||||||
+(id)class_test:(NSZone *)z {
|
|
||||||
return [self allocWithZone:z];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(id)test:(NSZone *)z {
|
|
||||||
NSZone *z2 = [self zone], *z3 = z2;
|
|
||||||
NSZone *z4 = z3;
|
|
||||||
|
|
||||||
Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
|
|
||||||
Foo *foo2 = [[Foo allocWithZone:[super zone]] init];
|
|
||||||
Foo *foo3 = [[Foo allocWithZone:z] init];
|
|
||||||
|
|
||||||
Foo *foo4 = [[Foo allocWithZone:z2] init];
|
|
||||||
Foo *foo5 = [[Foo allocWithZone:z3] init];
|
|
||||||
Foo *foo6 = [[Foo allocWithZone:z4] init];
|
|
||||||
|
|
||||||
foo1 = [foo1 copyWithZone:[self zone]];
|
|
||||||
foo2 = [foo1 copyWithZone:[super zone]];
|
|
||||||
foo3 = [foo1 copyWithZone:z];
|
|
||||||
foo1 = [foo1 mutableCopyWithZone:[self zone]];
|
|
||||||
|
|
||||||
return foo1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
|
@ -1,40 +0,0 @@
|
||||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
|
|
||||||
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
|
|
||||||
// RUN: diff %t %s.result
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
|
|
||||||
@interface Foo : NSObject <NSCopying, NSMutableCopying> {
|
|
||||||
id bar;
|
|
||||||
}
|
|
||||||
@property (retain) id bar;
|
|
||||||
-(id)test:(NSZone *)z;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation Foo
|
|
||||||
|
|
||||||
@synthesize bar;
|
|
||||||
|
|
||||||
+(id)class_test:(NSZone *)z {
|
|
||||||
return [self alloc];
|
|
||||||
}
|
|
||||||
|
|
||||||
-(id)test:(NSZone *)z {
|
|
||||||
|
|
||||||
Foo *foo1 = [[Foo alloc] init];
|
|
||||||
Foo *foo2 = [[Foo alloc] init];
|
|
||||||
Foo *foo3 = [[Foo alloc] init];
|
|
||||||
|
|
||||||
Foo *foo4 = [[Foo alloc] init];
|
|
||||||
Foo *foo5 = [[Foo alloc] init];
|
|
||||||
Foo *foo6 = [[Foo alloc] init];
|
|
||||||
|
|
||||||
foo1 = [foo1 copy];
|
|
||||||
foo2 = [foo1 copy];
|
|
||||||
foo3 = [foo1 copy];
|
|
||||||
foo1 = [foo1 mutableCopy];
|
|
||||||
|
|
||||||
return foo1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
Loading…
Reference in New Issue