diff options
-rw-r--r-- | Driver/RewriteObjC.cpp | 68 | ||||
-rw-r--r-- | test/Rewriter/properties.m | 53 |
2 files changed, 111 insertions, 10 deletions
diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp index d08633f728..907d7bb464 100644 --- a/Driver/RewriteObjC.cpp +++ b/Driver/RewriteObjC.cpp @@ -16,6 +16,7 @@ #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/TranslationUnit.h" +#include "clang/AST/ParentMap.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Diagnostic.h" @@ -107,6 +108,10 @@ namespace { // This maps a property to it's assignment statement. llvm::DenseMap<ObjCPropertyRefExpr *, BinaryOperator *> PropSetters; + // This maps a property to it's synthesied message expression. + // This allows us to rewrite chained getters (e.g. o.a.b.c). + llvm::DenseMap<ObjCPropertyRefExpr *, Stmt *> PropGetters; + // This maps an original source AST to it's rewritten form. This allows // us to avoid rewriting the same node twice (which is very uncommon). // This is needed to support some of the exotic property rewriting. @@ -209,6 +214,9 @@ namespace { Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); void CollectPropertySetters(Stmt *S); + Stmt *CurrentBody; + ParentMap *PropParentMap; // created lazily. + Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart); Stmt *RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr); @@ -1016,7 +1024,13 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt) { llvm::SmallVector<Expr *, 1> ExprVec; ExprVec.push_back(newStmt); - MsgExpr = new ObjCMessageExpr(PropRefExpr->getBase(), + Stmt *Receiver = PropRefExpr->getBase(); + ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(Receiver); + if (PRE && PropGetters[PRE]) { + // This allows us to handle chain/nested property getters. + Receiver = PropGetters[PRE]; + } + MsgExpr = new ObjCMessageExpr(dyn_cast<Expr>(Receiver), PDecl->getSetterName(), PDecl->getType(), PDecl->getSetterMethodDecl(), SourceLocation(), SourceLocation(), @@ -1036,19 +1050,37 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { ObjCMessageExpr *MsgExpr; ObjCPropertyDecl *PDecl = PropRefExpr->getProperty(); - MsgExpr = new ObjCMessageExpr(PropRefExpr->getBase(), + Stmt *Receiver = PropRefExpr->getBase(); + + ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(Receiver); + if (PRE && PropGetters[PRE]) { + // This allows us to handle chain/nested property getters. + Receiver = PropGetters[PRE]; + } + MsgExpr = new ObjCMessageExpr(dyn_cast<Expr>(Receiver), PDecl->getGetterName(), PDecl->getType(), PDecl->getGetterMethodDecl(), SourceLocation(), SourceLocation(), 0, 0); Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr); - - ReplaceStmt(PropRefExpr, ReplacingStmt); - - // delete PropRefExpr; elsewhere... - delete MsgExpr; - return ReplacingStmt; + + if (!PropParentMap) + PropParentMap = new ParentMap(CurrentBody); + + Stmt *Parent = PropParentMap->getParent(PropRefExpr); + if (Parent && isa<ObjCPropertyRefExpr>(Parent)) { + // We stash away the ReplacingStmt since actually doing the + // replacement/rewrite won't work for nested getters (e.g. obj.p.i) + PropGetters[PropRefExpr] = ReplacingStmt; + delete MsgExpr; + return PropRefExpr; // return the original... + } else { + ReplaceStmt(PropRefExpr, ReplacingStmt); + // delete PropRefExpr; elsewhere... + delete MsgExpr; + return ReplacingStmt; + } } Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, @@ -4272,8 +4304,13 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { if (Stmt *Body = FD->getBody()) { CurFunctionDef = FD; CollectPropertySetters(Body); + CurrentBody = Body; FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body)); - + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } // This synthesizes and inserts the block "impl" struct, invoke function, // and any copy/dispose helper functions. InsertBlockLiteralsWithinFunction(FD); @@ -4283,10 +4320,15 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { } if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (Stmt *Body = MD->getBody()) { - //Body->dump(); CurMethodDef = MD; CollectPropertySetters(Body); + CurrentBody = Body; MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body)); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } InsertBlockLiteralsWithinMethod(MD); CurMethodDef = 0; } @@ -4312,7 +4354,13 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { if (VD->getInit()) { GlobalVarDecl = VD; CollectPropertySetters(VD->getInit()); + CurrentBody = VD->getInit(); RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getNameAsCString()); GlobalVarDecl = 0; diff --git a/test/Rewriter/properties.m b/test/Rewriter/properties.m new file mode 100644 index 0000000000..38ba086aa7 --- /dev/null +++ b/test/Rewriter/properties.m @@ -0,0 +1,53 @@ +// RUN: clang -rewrite-objc %s -o - + +@interface Foo { + int i; + int rrrr; + Foo *o; +} +@property int i; +@property(readonly) int rrrr; +@property int d; +@property(retain) Foo *o; + +- (void)foo; +@end + +@implementation Foo +@synthesize i; +@synthesize rrrr; +@synthesize o; + +@dynamic d; + +- (void)foo { + i = 99; +} + +- (int)bar { + return i; +} +@end + +@interface Bar { +} +@end + +@implementation Bar + +static int func(int i); + +- (void)baz { + Foo *obj1, *obj2; + int i; + if (obj1.i == obj2.rrrr) + obj1.i = 33; + obj1.i = func(obj2.rrrr); + obj1.i = obj2.rrrr; + obj1.i = (obj2.rrrr); + [obj1 setI:[obj2 rrrr]]; + obj1.i = [obj2 rrrr]; + i = obj1.o.i; + obj1.o.i = 77; +} +@end |