ObjC migrator: Improve on hueristics.
migrate to 'copy attribute if Object
class implements NSCopying otherwise 
assume implied 'strong'. Remove 
lifetime qualifier on property as it has
moved to property's attribute. Added TODO
comment for future work by poking into
setter implementation.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186037 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index e4ca61a..1e7a0d7 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -1136,6 +1136,8 @@
     return lookupInstanceVariable(IVarName, ClassDeclared);
   }
 
+  ObjCProtocolDecl *lookupNestedProtocol(IdentifierInfo *Name);
+                          
   // Lookup a method. First, we search locally. If a method isn't
   // found, we search referenced protocols and class categories.
   ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 3895a52..c15f01d 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -441,6 +441,17 @@
   return NULL;
 }
 
+ObjCProtocolDecl *
+ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
+  for (ObjCInterfaceDecl::all_protocol_iterator P =
+       all_referenced_protocol_begin(), PE = all_referenced_protocol_end();
+       P != PE; ++P)
+    if ((*P)->lookupProtocolNamed(Name))
+      return (*P);
+  ObjCInterfaceDecl *SuperClass = getSuperClass();
+  return SuperClass ? SuperClass->lookupNestedProtocol(Name) : NULL;
+}
+
 /// lookupMethod - This method returns an instance/class method by looking in
 /// the class, its categories, and its super classes (using a linear search).
 /// When argument category "C" is specified, any implicit method found
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index e257a0b..8d24003d 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -358,23 +358,38 @@
 bool edit::rewriteToObjCProperty(const ObjCMethodDecl *Getter,
                                  const ObjCMethodDecl *Setter,
                                  const NSAPI &NS, Commit &commit) {
+  ASTContext &Context = NS.getASTContext();
   std::string PropertyString = "@property";
   const ParmVarDecl *argDecl = *Setter->param_begin();
-  QualType ArgType = argDecl->getType();
+  QualType ArgType = Context.getCanonicalType(argDecl->getType());
   Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
   
   if (ArgType->isObjCRetainableType() &&
       propertyLifetime == Qualifiers::OCL_Strong) {
-    PropertyString += "(copy)";
+    if (const ObjCObjectPointerType *ObjPtrTy =
+          ArgType->getAs<ObjCObjectPointerType>()) {
+      ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
+      if (IDecl &&
+          IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
+        PropertyString += "(copy)";
+    }
   }
   else if (propertyLifetime == Qualifiers::OCL_Weak)
+    // TODO. More precise determination of 'weak' attribute requires
+    // looking into setter's implementation for backing weak ivar.
     PropertyString += "(weak)";
   else
     PropertyString += "(unsafe_unretained)";
-  
-  QualType PropQT = Getter->getResultType();
+
+  // strip off any ARC lifetime qualifier.
+  QualType CanResultTy = Context.getCanonicalType(Getter->getResultType());
+  if (CanResultTy.getQualifiers().hasObjCLifetime()) {
+    Qualifiers Qs = CanResultTy.getQualifiers();
+    Qs.removeObjCLifetime();
+    CanResultTy = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
+  }
   PropertyString += " ";
-  PropertyString += PropQT.getAsString(NS.getASTContext().getPrintingPolicy());
+  PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy());
   PropertyString += " ";
   PropertyString += Getter->getNameAsString();
   commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
diff --git a/test/ARCMT/objcmt-property.m b/test/ARCMT/objcmt-property.m
index 1f0bcdd..ca1b504 100644
--- a/test/ARCMT/objcmt-property.m
+++ b/test/ARCMT/objcmt-property.m
@@ -4,7 +4,13 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc -fobjc-default-synthesize-properties %s.result
 
 @class NSString;
-@interface NSObject @end
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
 
 @interface I : NSObject {
   int ivarVal;
@@ -24,6 +30,8 @@
 - (NSString *) UnavailProp2;
 - (void) setUnavailProp2  : (NSString *)Val  __attribute__((unavailable));
 
+- (NSDictionary*) undoAction;
+- (void) setUndoAction: (NSDictionary*)Arg;
 @end
 
 @implementation I
diff --git a/test/ARCMT/objcmt-property.m.result b/test/ARCMT/objcmt-property.m.result
index 11912d9..2bcae86 100644
--- a/test/ARCMT/objcmt-property.m.result
+++ b/test/ARCMT/objcmt-property.m.result
@@ -4,15 +4,21 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c -fobjc-runtime-has-weak -fobjc-arc -fobjc-default-synthesize-properties %s.result
 
 @class NSString;
-@interface NSObject @end
+@protocol NSCopying @end
+
+@interface NSObject <NSCopying>
+@end
+
+@interface NSDictionary : NSObject
+@end
 
 @interface I : NSObject {
   int ivarVal;
 }
 
-@property(weak) NSString *__weak WeakProp;
+@property(weak) NSString * WeakProp;
 
-@property(copy) NSString * StrongProp;
+@property NSString * StrongProp;
 
 
 - (NSString *) UnavailProp  __attribute__((unavailable));
@@ -24,6 +30,8 @@
 - (NSString *) UnavailProp2;
 - (void) setUnavailProp2  : (NSString *)Val  __attribute__((unavailable));
 
+@property(copy) NSDictionary * undoAction;
+
 @end
 
 @implementation I
@@ -42,8 +50,8 @@
 
 
 
-@property(copy) NSArray * names2;
-@property(copy) NSArray * names3;
-@property(copy) NSArray *__strong names4;
-@property(copy) NSArray * names1;
+@property NSArray * names2;
+@property NSArray * names3;
+@property NSArray * names4;
+@property NSArray * names1;
 @end