forked from OSchip/llvm-project
[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:
parent
ae02c5a93e
commit
b03cc793a9
|
@ -75,7 +75,7 @@ public:
|
|||
&pass.Ctx.Idents.get("drain"));
|
||||
}
|
||||
|
||||
void transformBody(Stmt *body) {
|
||||
void transformBody(Stmt *body, Decl *ParentD) {
|
||||
Body = body;
|
||||
TraverseStmt(body);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}} \
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue