[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

llvm-svn: 158127
This commit is contained in:
Argyrios Kyrtzidis 2012-06-07 00:44:06 +00:00
parent ae02c5a93e
commit b03cc793a9
8 changed files with 102 additions and 22 deletions

View File

@ -75,7 +75,7 @@ public:
&pass.Ctx.Idents.get("drain"));
}
void transformBody(Stmt *body) {
void transformBody(Stmt *body, Decl *ParentD) {
Body = body;
TraverseStmt(body);
}

View File

@ -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));

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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}} \

View File

@ -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) {

View File

@ -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) {