From cf2ff9ba32993b4cd6df101dd5cc4dce57296c3c Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 8 Aug 2013 20:51:58 +0000 Subject: [PATCH] ObjectiveC migration: Handle another special case of setter/getter methods which can be migrated to a @property. llvm-svn: 188005 --- clang/lib/ARCMigrate/ObjCMT.cpp | 83 ++++++++++++++++++----- clang/test/ARCMT/objcmt-property.m | 10 +++ clang/test/ARCMT/objcmt-property.m.result | 10 +++ 3 files changed, 85 insertions(+), 18 deletions(-) diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index f676149389ec..931f6ed051f6 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -206,20 +206,31 @@ void ObjCMigrateASTConsumer::migrateDecl(Decl *D) { BodyMigrator(*this).TraverseDecl(D); } +static void append_attr(std::string &PropertyString, const char *attr, + bool GetterHasIsPrefix) { + PropertyString += (GetterHasIsPrefix ? ", " : "("); + PropertyString += attr; + PropertyString += ')'; +} + static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter, const ObjCMethodDecl *Setter, - const NSAPI &NS, edit::Commit &commit) { + const NSAPI &NS, edit::Commit &commit, + bool GetterHasIsPrefix) { ASTContext &Context = NS.getASTContext(); std::string PropertyString = "@property"; - std::string PropertyNameString = Getter->getNameAsString(); StringRef PropertyName(PropertyNameString); + if (GetterHasIsPrefix) { + PropertyString += "(getter="; + PropertyString += PropertyNameString; + } // Short circuit properties that contain the name "delegate" or "dataSource", // or have exact name "target" to have unsafe_unretained attribute. if (PropertyName.equals("target") || (PropertyName.find("delegate") != StringRef::npos) || (PropertyName.find("dataSource") != StringRef::npos)) - PropertyString += "(unsafe_unretained)"; + append_attr(PropertyString, "unsafe_unretained", GetterHasIsPrefix); else { const ParmVarDecl *argDecl = *Setter->param_begin(); QualType ArgType = Context.getCanonicalType(argDecl->getType()); @@ -231,29 +242,46 @@ static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter, ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); if (IDecl && IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying"))) - PropertyString += "(copy)"; + append_attr(PropertyString, "copy", GetterHasIsPrefix); else - PropertyString += "(retain)"; - } + append_attr(PropertyString, "retain", GetterHasIsPrefix); + } else if (GetterHasIsPrefix) + PropertyString += ')'; } 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)"; + append_attr(PropertyString, "weak", GetterHasIsPrefix); else if (RetainableObject) - PropertyString += "(retain)"; + append_attr(PropertyString, "retain", GetterHasIsPrefix); + else if (GetterHasIsPrefix) + PropertyString += ')'; } - // 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); + QualType RT = Getter->getResultType(); + if (!isa(RT)) { + // strip off any ARC lifetime qualifier. + QualType CanResultTy = Context.getCanonicalType(RT); + if (CanResultTy.getQualifiers().hasObjCLifetime()) { + Qualifiers Qs = CanResultTy.getQualifiers(); + Qs.removeObjCLifetime(); + RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); + } } PropertyString += " "; - PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy()); + PropertyString += RT.getAsString(Context.getPrintingPolicy()); PropertyString += " "; - PropertyString += PropertyNameString; + if (GetterHasIsPrefix) { + // property name must strip off "is" and lower case the first character + // after that; e.g. isContinuous will become continuous. + StringRef PropertyNameStringRef(PropertyNameString); + PropertyNameStringRef = PropertyNameStringRef.drop_front(2); + PropertyNameString = PropertyNameStringRef; + std::string NewPropertyNameString = PropertyNameString; + NewPropertyNameString[0] = std::tolower(NewPropertyNameString[0]); + PropertyString += NewPropertyNameString; + } + else + PropertyString += PropertyNameString; commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), Getter->getDeclaratorEndLoc()), PropertyString); @@ -285,7 +313,25 @@ void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx, SelectorTable::constructSetterSelector(PP.getIdentifierTable(), PP.getSelectorTable(), getterName); - if (ObjCMethodDecl *SetterMethod = D->lookupMethod(SetterSelector, true)) { + ObjCMethodDecl *SetterMethod = D->lookupMethod(SetterSelector, true); + bool GetterHasIsPrefix = false; + if (!SetterMethod) { + // try a different naming convention for getter: isXxxxx + StringRef getterNameString = getterName->getName(); + if (getterNameString.startswith("is")) { + GetterHasIsPrefix = true; + const char *CGetterName = getterNameString.data() + 2; + if (CGetterName[0]) { + getterName = &Ctx.Idents.get(CGetterName); + SetterSelector = + SelectorTable::constructSetterSelector(PP.getIdentifierTable(), + PP.getSelectorTable(), + getterName); + SetterMethod = D->lookupMethod(SetterSelector, true); + } + } + } + if (SetterMethod) { // Is this a valid setter, matching the target getter? QualType SRT = SetterMethod->getResultType(); if (!SRT->isVoidType()) @@ -296,7 +342,8 @@ void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx, SetterMethod->hasAttrs()) continue; edit::Commit commit(*Editor); - rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit); + rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit, + GetterHasIsPrefix); Editor->commit(commit); } } diff --git a/clang/test/ARCMT/objcmt-property.m b/clang/test/ARCMT/objcmt-property.m index 6511acd72c53..8453999cd25a 100644 --- a/clang/test/ARCMT/objcmt-property.m +++ b/clang/test/ARCMT/objcmt-property.m @@ -3,6 +3,7 @@ // RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result // 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 +typedef char BOOL; @class NSString; @protocol NSCopying @end @@ -77,4 +78,13 @@ - (int)value; - (void)setValue: (int)val; + +-(BOOL) isContinuous; +-(void) setContinuous:(BOOL)value; + +- (id) isAnObject; +- (void)setAnObject : (id) object; + +- (id)isxdelegateYYY; +- (void)setXdelegateYYY:(id)delegate; @end diff --git a/clang/test/ARCMT/objcmt-property.m.result b/clang/test/ARCMT/objcmt-property.m.result index 3c9a539eb7d6..1cd771a1c721 100644 --- a/clang/test/ARCMT/objcmt-property.m.result +++ b/clang/test/ARCMT/objcmt-property.m.result @@ -3,6 +3,7 @@ // RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result // 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 +typedef char BOOL; @class NSString; @protocol NSCopying @end @@ -77,4 +78,13 @@ @property int value; + +@property(getter=isContinuous) BOOL continuous; + + +@property(getter=isAnObject, retain) id anObject; + + +@property(getter=isxdelegateYYY, unsafe_unretained) id xdelegateYYY; + @end