]> granicus.if.org Git - clang/commitdiff
Objective-C SDK modernization. convert message expression
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 9 Oct 2014 18:30:56 +0000 (18:30 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 9 Oct 2014 18:30:56 +0000 (18:30 +0000)
to Objective-C dot-syntax. rdar://18498572

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219424 91177308-0d34-0410-b5e6-96231b3b80d8

lib/ARCMigrate/ObjCMT.cpp
test/ARCMT/objcmt-property-dot-syntax.m [new file with mode: 0644]
test/ARCMT/objcmt-property-dot-syntax.m.result [new file with mode: 0644]

index c21e7324ebbf5dc09fb5d3da7e179a25771c105d..7eebdb78d8982acd2538f4981f314682834ecd42 100644 (file)
@@ -211,6 +211,104 @@ bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
 }
 
 namespace {
+  // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp
+  bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
+    const Expr* Expr = FullExpr->IgnoreImpCasts();
+    if (isa<ArraySubscriptExpr>(Expr) ||
+        isa<CallExpr>(Expr) ||
+        isa<DeclRefExpr>(Expr) ||
+        isa<CXXNamedCastExpr>(Expr) ||
+        isa<CXXConstructExpr>(Expr) ||
+        isa<CXXThisExpr>(Expr) ||
+        isa<CXXTypeidExpr>(Expr) ||
+        isa<CXXUnresolvedConstructExpr>(Expr) ||
+        isa<ObjCMessageExpr>(Expr) ||
+        isa<ObjCPropertyRefExpr>(Expr) ||
+        isa<ObjCProtocolExpr>(Expr) ||
+        isa<MemberExpr>(Expr) ||
+        isa<ObjCIvarRefExpr>(Expr) ||
+        isa<ParenExpr>(FullExpr) ||
+        isa<ParenListExpr>(Expr) ||
+        isa<SizeOfPackExpr>(Expr))
+      return false;
+    
+    return true;
+  }
+  
+  /// \brief - Rewrite message expression for Objective-C setter and getters into
+  /// property-dot syntax.
+  bool rewriteToPropertyDotSyntax(const ObjCMessageExpr *Msg,
+                                  Preprocessor &PP,
+                                  const NSAPI &NS, edit::Commit &commit,
+                                  const ParentMap *PMap) {
+    if (!Msg || Msg->isImplicit() ||
+        Msg->getReceiverKind() != ObjCMessageExpr::Instance)
+      return false;
+    const ObjCMethodDecl *Method = Msg->getMethodDecl();
+    if (!Method)
+      return false;
+    if (!Method->isPropertyAccessor())
+      return false;
+    
+    const ObjCInterfaceDecl *IFace =
+      NS.getASTContext().getObjContainingInterface(Method);
+    if (!IFace)
+      return false;
+    
+    const ObjCPropertyDecl *Prop = Method->findPropertyDecl();
+    if (!Prop)
+      return false;
+    
+    SourceRange MsgRange = Msg->getSourceRange();
+    const Expr *receiver = Msg->getInstanceReceiver();
+    bool NeedsParen = subscriptOperatorNeedsParens(receiver);
+    bool IsGetter = (Msg->getNumArgs() == 0);
+    if (IsGetter) {
+      // Find space location range between receiver expression and getter method.
+      SourceLocation BegLoc = receiver->getLocEnd();
+      BegLoc = PP.getLocForEndOfToken(BegLoc);
+      SourceLocation EndLoc = Msg->getSelectorLoc(0);
+      SourceRange SpaceRange(BegLoc, EndLoc);
+      std::string PropertyDotString;
+      // rewrite getter method expression into: receiver.property or
+      // (receiver).property
+      if (NeedsParen) {
+        commit.insertBefore(receiver->getLocStart(), "(");
+        PropertyDotString = ").";
+      }
+      else
+        PropertyDotString = ".";
+      PropertyDotString += Prop->getName();
+      commit.replace(SpaceRange, PropertyDotString);
+      
+      // remove '[' ']'
+      commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
+      commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
+    } else {
+      SourceRange ReceiverRange = receiver->getSourceRange();
+      if (NeedsParen)
+        commit.insertWrap("(", ReceiverRange, ")");
+      std::string PropertyDotString = ".";
+      PropertyDotString += Prop->getName();
+      PropertyDotString += " =";
+      const Expr*const* Args = Msg->getArgs();
+      const Expr *RHS = Args[0];
+      if (!RHS)
+        return false;
+      SourceLocation BegLoc = ReceiverRange.getEnd();
+      BegLoc = PP.getLocForEndOfToken(BegLoc);
+      SourceLocation EndLoc = RHS->getLocStart();
+      EndLoc = EndLoc.getLocWithOffset(-1);
+      SourceRange Range(BegLoc, EndLoc);
+      commit.replace(Range, PropertyDotString);
+      // remove '[' ']'
+      commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
+      commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
+    }
+    return true;
+  }
+  
+
 class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
   ObjCMigrateASTConsumer &Consumer;
   ParentMap &PMap;
@@ -235,6 +333,13 @@ public:
       Consumer.Editor->commit(commit);
     }
 
+    if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Property) {
+      edit::Commit commit(*Consumer.Editor);
+      rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
+                                 commit, &PMap);
+      Consumer.Editor->commit(commit);
+    }
+
     return true;
   }
 
diff --git a/test/ARCMT/objcmt-property-dot-syntax.m b/test/ARCMT/objcmt-property-dot-syntax.m
new file mode 100644 (file)
index 0000000..ce6dc16
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+// rdar://18498572
+@interface NSObject @end
+
+@interface P : NSObject
+{
+  P* obj;
+  int i1, i2, i3;
+}
+@property int count;
+@property (copy) P* PropertyReturnsPObj;
+- (P*) MethodReturnsPObj;
+@end
+
+P* fun();
+
+@implementation P
+- (int) Meth : (P*)array {
+  [obj setCount : 100];
+
+  [(P*)0 setCount : [array count]];
+
+  [[obj PropertyReturnsPObj] setCount : [array count]];
+
+  [obj setCount : (i1+i2*i3 - 100)];
+
+  return [obj count] -
+         [(P*)0 count] + [array count] +
+         [fun() count] - 
+         [[obj PropertyReturnsPObj] count] +
+         [self->obj count];
+}
+
+- (P*) MethodReturnsPObj { return 0; }
+@end
diff --git a/test/ARCMT/objcmt-property-dot-syntax.m.result b/test/ARCMT/objcmt-property-dot-syntax.m.result
new file mode 100644 (file)
index 0000000..0532c6f
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-property -mt-migrate-directory %t %s -x objective-c -fobjc-runtime-has-weak -fobjc-arc -triple x86_64-apple-darwin11
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc %s.result
+
+// rdar://18498572
+@interface NSObject @end
+
+@interface P : NSObject
+{
+  P* obj;
+  int i1, i2, i3;
+}
+@property int count;
+@property (copy) P* PropertyReturnsPObj;
+@property (nonatomic, readonly, strong) P *MethodReturnsPObj;
+@end
+
+P* fun();
+
+@implementation P
+- (int) Meth : (P*)array {
+  obj.count = 100;
+
+  ((P*)0).count = array.count;
+
+  obj.PropertyReturnsPObj.count = array.count;
+
+  obj.count = (i1+i2*i3 - 100);
+
+  return obj.count -
+         ((P*)0).count + array.count +
+         fun().count - 
+         obj.PropertyReturnsPObj.count +
+         self->obj.count;
+}
+
+- (P*) MethodReturnsPObj { return 0; }
+@end