[objcmt] When in ARC mode, also convert "[[.. alloc] init]" messages to literals,
since the change from +1 to +0 will be handled fine by ARC.

rdar://11606358

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158114 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index c36793f..465f180 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -22,7 +22,8 @@
 using namespace edit;
 
 static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
-                                    IdentifierInfo *&ClassId) {
+                                    IdentifierInfo *&ClassId,
+                                    const LangOptions &LangOpts) {
   if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
     return false;
 
@@ -34,6 +35,18 @@
   if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
     return true;
 
+  // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
+  // since the change from +1 to +0 will be handled fine by ARC.
+  if (LangOpts.ObjCAutoRefCount) {
+    if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
+      if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
+                           Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
+        if (Rec->getMethodFamily() == OMF_alloc)
+          return true;
+      }
+    }
+  }
+
   return false;
 }
 
@@ -44,7 +57,7 @@
 bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
                                               const NSAPI &NS, Commit &commit) {
   IdentifierInfo *II = 0;
-  if (!checkForLiteralCreation(Msg, II))
+  if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
     return false;
   if (Msg->getNumArgs() != 1)
     return false;
@@ -54,16 +67,19 @@
 
   if ((isa<ObjCStringLiteral>(Arg) &&
        NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
-       NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel)    ||
+       (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
+        NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel))   ||
 
       (isa<ObjCArrayLiteral>(Arg) &&
        NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
-       NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel)      ||
+       (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
+        NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel))     ||
 
       (isa<ObjCDictionaryLiteral>(Arg) &&
        NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
-       NS.getNSDictionarySelector(
-                              NSAPI::NSDict_dictionaryWithDictionary) == Sel)) {
+       (NS.getNSDictionarySelector(
+                              NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
+        NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
     
     commit.replaceWithInner(Msg->getSourceRange(),
                            Msg->getArg(0)->getSourceRange());
@@ -246,7 +262,7 @@
 bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
                                       const NSAPI &NS, Commit &commit) {
   IdentifierInfo *II = 0;
-  if (!checkForLiteralCreation(Msg, II))
+  if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
     return false;
 
   if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
@@ -290,7 +306,8 @@
     return true;
   }
 
-  if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects)) {
+  if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
+      Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
     if (Msg->getNumArgs() == 0)
       return false;
     const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
@@ -352,7 +369,8 @@
   }
 
   if (Sel == NS.getNSDictionarySelector(
-                                  NSAPI::NSDict_dictionaryWithObjectsAndKeys)) {
+                                  NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
+      Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
     if (Msg->getNumArgs() % 2 != 1)
       return false;
     unsigned SentinelIdx = Msg->getNumArgs() - 1;
diff --git a/test/ARCMT/objcmt-subscripting-literals-in-arc.m b/test/ARCMT/objcmt-subscripting-literals-in-arc.m
new file mode 100644
index 0000000..fd100ca
--- /dev/null
+++ b/test/ARCMT/objcmt-subscripting-literals-in-arc.m
@@ -0,0 +1,94 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fobjc-arc -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11 
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fobjc-arc -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+typedef const struct __CFString * CFStringRef;
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+- (id)initWithInt:(int)value;
+@end
+
+@interface I {
+  NSArray *ivarArr;
+}
+@end
+@implementation I
+-(void) foo {
+  NSString *str;
+  NSArray *arr;
+  NSDictionary *dict;
+
+  arr = [NSArray arrayWithObjects:str, str, nil];
+  arr = [[NSArray alloc] initWithObjects:str, str, nil];
+  dict = [NSDictionary dictionaryWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
+  dict = [[NSDictionary alloc] initWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
+
+  NSNumber *n = [[NSNumber alloc] initWithInt:2];
+}
+@end
diff --git a/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result b/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result
new file mode 100644
index 0000000..4a65a23
--- /dev/null
+++ b/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result
@@ -0,0 +1,94 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fobjc-arc -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -triple x86_64-apple-darwin11 
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -fobjc-arc -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+typedef const struct __CFString * CFStringRef;
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+- (id)initWithInt:(int)value;
+@end
+
+@interface I {
+  NSArray *ivarArr;
+}
+@end
+@implementation I
+-(void) foo {
+  NSString *str;
+  NSArray *arr;
+  NSDictionary *dict;
+
+  arr = @[str, str];
+  arr = @[str, str];
+  dict = @{@"key1": @"value1", @"key2": @"value2"};
+  dict = @{@"key1": @"value1", @"key2": @"value2"};
+
+  NSNumber *n = @2;
+}
+@end