diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-06-07 00:44:06 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2012-06-07 00:44:06 +0000 |
commit | 76a5245d7fb558625453ebe2281ee0bc9c93c245 (patch) | |
tree | f1d84c4ae755e8b86c4b9008be6700542340ae61 | |
parent | e14da79c7b1c336b72e6a4548f53b1a9534f7e0d (diff) | |
download | clang-76a5245d7fb558625453ebe2281ee0bc9c93c245.tar.gz |
[arcmt] At an unbridged cast error, if we're returning a load-of-ivar from a +0 method,
automatically insert a __bridge cast.
radar://11560638
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158127 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/ARCMigrate/TransAutoreleasePool.cpp | 2 | ||||
-rw-r--r-- | lib/ARCMigrate/TransRetainReleaseDealloc.cpp | 2 | ||||
-rw-r--r-- | lib/ARCMigrate/TransUnbridgedCasts.cpp | 21 | ||||
-rw-r--r-- | lib/ARCMigrate/TransUnusedInitDelegate.cpp | 2 | ||||
-rw-r--r-- | lib/ARCMigrate/Transforms.h | 12 | ||||
-rw-r--r-- | test/ARCMT/nonobjc-to-objc-cast-2.m | 31 | ||||
-rw-r--r-- | test/ARCMT/nonobjc-to-objc-cast.m | 27 | ||||
-rw-r--r-- | test/ARCMT/nonobjc-to-objc-cast.m.result | 27 |
8 files changed, 102 insertions, 22 deletions
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp index 87877242a1..f0db4d024d 100644 --- a/lib/ARCMigrate/TransAutoreleasePool.cpp +++ b/lib/ARCMigrate/TransAutoreleasePool.cpp @@ -75,7 +75,7 @@ public: &pass.Ctx.Idents.get("drain")); } - void transformBody(Stmt *body) { + void transformBody(Stmt *body, Decl *ParentD) { Body = body; TraverseStmt(body); } diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index df3cd5858e..b8a84ec5b8 100644 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -49,7 +49,7 @@ public: Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); } - void transformBody(Stmt *body) { + void transformBody(Stmt *body, Decl *ParentD) { Body = body; collectRemovables(body, Removables); StmtMap.reset(new ParentMap(body)); diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp index 37cebc9e3a..72c0d8e7de 100644 --- a/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -50,13 +50,15 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ MigrationPass &Pass; IdentifierInfo *SelfII; OwningPtr<ParentMap> StmtMap; + Decl *ParentD; public: - UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) { + UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) { SelfII = &Pass.Ctx.Idents.get("self"); } - void transformBody(Stmt *body) { + void transformBody(Stmt *body, Decl *ParentD) { + this->ParentD = ParentD; StmtMap.reset(new ParentMap(body)); TraverseStmt(body); } @@ -155,6 +157,21 @@ private: } } } + + // If returning an ivar or a member of an ivar from a +0 method, use + // a __bridge cast. + Expr *base = inner->IgnoreParenImpCasts(); + while (isa<MemberExpr>(base)) + base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts(); + if (isa<ObjCIvarRefExpr>(base) && + isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) { + if (ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) { + if (!method->hasAttr<NSReturnsRetainedAttr>()) { + castToObjCObject(E, /*retained=*/false); + return; + } + } + } } void castToObjCObject(CastExpr *E, bool retained) { diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp index 60ed32aef4..7a825e8165 100644 --- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp +++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp @@ -40,7 +40,7 @@ public: UnusedInitRewriter(MigrationPass &pass) : Body(0), Pass(pass) { } - void transformBody(Stmt *body) { + void transformBody(Stmt *body, Decl *ParentD) { Body = body; collectRemovables(body, Removables); TraverseStmt(body); diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index 7abc0304b1..5d4ac94460 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -13,6 +13,7 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/ParentMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/Support/SaveAndRestore.h" namespace clang { class Decl; @@ -176,15 +177,22 @@ StringRef getNilString(ASTContext &Ctx); template <typename BODY_TRANS> class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > { MigrationPass &Pass; + Decl *ParentD; + typedef RecursiveASTVisitor<BodyTransform<BODY_TRANS> > base; public: - BodyTransform(MigrationPass &pass) : Pass(pass) { } + BodyTransform(MigrationPass &pass) : Pass(pass), ParentD(0) { } bool TraverseStmt(Stmt *rootS) { if (rootS) - BODY_TRANS(Pass).transformBody(rootS); + BODY_TRANS(Pass).transformBody(rootS, ParentD); return true; } + + bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { + SaveAndRestore<Decl *> SetParent(ParentD, D); + return base::TraverseObjCMethodDecl(D); + } }; typedef llvm::DenseSet<Expr *> ExprSet; diff --git a/test/ARCMT/nonobjc-to-objc-cast-2.m b/test/ARCMT/nonobjc-to-objc-cast-2.m index 1ec0089f08..80d694e586 100644 --- a/test/ARCMT/nonobjc-to-objc-cast-2.m +++ b/test/ARCMT/nonobjc-to-objc-cast-2.m @@ -3,16 +3,37 @@ #include "Common.h" -@interface NSString : NSObject --(id)string; --(id)newString; -@end - typedef const struct __CFString * CFStringRef; typedef const void * CFTypeRef; CFTypeRef CFBridgingRetain(id X); id CFBridgingRelease(CFTypeRef); +struct StrS { + CFStringRef sref_member; +}; + +@interface NSString : NSObject { + CFStringRef sref; + struct StrS *strS; +} +-(id)string; +-(id)newString; +@end + +@implementation NSString +-(id)string { + if (0) + return sref; + else + return strS->sref_member; +} +-(id)newString { + return sref; // expected-error {{implicit conversion of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'id' requires a bridged cast}} \ + // expected-note{{use __bridge to convert directly (no change in ownership)}} \ + // expected-note{{use CFBridgingRelease call to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}} +} +@end + void f(BOOL b) { CFStringRef cfstr; NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \ diff --git a/test/ARCMT/nonobjc-to-objc-cast.m b/test/ARCMT/nonobjc-to-objc-cast.m index fcdcd89c9c..55b6655fa4 100644 --- a/test/ARCMT/nonobjc-to-objc-cast.m +++ b/test/ARCMT/nonobjc-to-objc-cast.m @@ -5,11 +5,6 @@ #include "Common.h" -@interface NSString : NSObject --(id)string; --(id)newString; -@end - typedef const struct __CFString * CFStringRef; extern const CFStringRef kUTTypePlainText; extern const CFStringRef kUTTypeRTF; @@ -21,6 +16,18 @@ extern const CFAllocatorRef kCFAllocatorDefault; extern CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid); +struct StrS { + CFStringRef sref_member; +}; + +@interface NSString : NSObject { + CFStringRef sref; + struct StrS *strS; +} +-(id)string; +-(id)newString; +@end + void f(BOOL b, id p) { NSString *str = (NSString *)kUTTypePlainText; str = b ? kUTTypeRTF : kUTTypePlainText; @@ -41,6 +48,16 @@ void f(BOOL b, id p) { } @end +@implementation NSString +-(id)string { + if (0) + return sref; + else + return strS->sref_member; +} +-(id)newString { return 0; } +@end + extern void consumeParam(CFStringRef CF_CONSUMED p); void f2(NSString *s) { diff --git a/test/ARCMT/nonobjc-to-objc-cast.m.result b/test/ARCMT/nonobjc-to-objc-cast.m.result index 0a3b2bb526..4f508f6adf 100644 --- a/test/ARCMT/nonobjc-to-objc-cast.m.result +++ b/test/ARCMT/nonobjc-to-objc-cast.m.result @@ -5,11 +5,6 @@ #include "Common.h" -@interface NSString : NSObject --(id)string; --(id)newString; -@end - typedef const struct __CFString * CFStringRef; extern const CFStringRef kUTTypePlainText; extern const CFStringRef kUTTypeRTF; @@ -21,6 +16,18 @@ extern const CFAllocatorRef kCFAllocatorDefault; extern CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid); +struct StrS { + CFStringRef sref_member; +}; + +@interface NSString : NSObject { + CFStringRef sref; + struct StrS *strS; +} +-(id)string; +-(id)newString; +@end + void f(BOOL b, id p) { NSString *str = (__bridge NSString *)kUTTypePlainText; str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText); @@ -41,6 +48,16 @@ void f(BOOL b, id p) { } @end +@implementation NSString +-(id)string { + if (0) + return (__bridge id)(sref); + else + return (__bridge id)(strS->sref_member); +} +-(id)newString { return 0; } +@end + extern void consumeParam(CFStringRef CF_CONSUMED p); void f2(NSString *s) { |