ObjectiveC migrator: When inferring a property,

preserve getter's attribute. Also, do not attach
an inferred NS_RETURNS_INNER_POINTER to the inferred
property (it is illegal).

llvm-svn: 190223
This commit is contained in:
Fariborz Jahanian 2013-09-06 23:45:20 +00:00
parent fdd91c92d0
commit 215f96c084
3 changed files with 89 additions and 60 deletions

View File

@ -51,6 +51,7 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
void migrateMethods(ASTContext &Ctx, ObjCContainerDecl *CDecl); void migrateMethods(ASTContext &Ctx, ObjCContainerDecl *CDecl);
void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl, void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
ObjCMethodDecl *OM); ObjCMethodDecl *OM);
bool migrateProperty(ASTContext &Ctx, ObjCInterfaceDecl *D, ObjCMethodDecl *OM);
void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM); void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl, void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
ObjCMethodDecl *OM, ObjCMethodDecl *OM,
@ -316,8 +317,13 @@ static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter,
} }
else else
PropertyString += PropertyNameString; PropertyString += PropertyNameString;
SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
Selector GetterSelector = Getter->getSelector();
SourceLocation EndGetterSelectorLoc =
StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
Getter->getDeclaratorEndLoc()), EndGetterSelectorLoc),
PropertyString); PropertyString);
if (Setter) { if (Setter) {
SourceLocation EndLoc = Setter->getDeclaratorEndLoc(); SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
@ -333,64 +339,8 @@ void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end(); for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
M != MEnd; ++M) { M != MEnd; ++M) {
ObjCMethodDecl *Method = (*M); ObjCMethodDecl *Method = (*M);
if (Method->isPropertyAccessor() || !Method->isInstanceMethod() || if (!migrateProperty(Ctx, D, Method))
Method->param_size() != 0) migrateNsReturnsInnerPointer(Ctx, Method);
continue;
// Is this method candidate to be a getter?
QualType GRT = Method->getResultType();
if (GRT->isVoidType())
continue;
// FIXME. Don't know what todo with attributes, skip for now.
if (Method->hasAttrs())
continue;
Selector GetterSelector = Method->getSelector();
IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
Selector SetterSelector =
SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
PP.getSelectorTable(),
getterName);
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") && !GRT->isObjCRetainableType()) {
GetterHasIsPrefix = true;
const char *CGetterName = getterNameString.data() + 2;
if (CGetterName[0] && isUppercase(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())
continue;
const ParmVarDecl *argDecl = *SetterMethod->param_begin();
QualType ArgType = argDecl->getType();
if (!Ctx.hasSameUnqualifiedType(ArgType, GRT) ||
SetterMethod->hasAttrs())
continue;
edit::Commit commit(*Editor);
rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
GetterHasIsPrefix);
Editor->commit(commit);
}
else if (MigrateReadonlyProperty) {
// Try a non-void method with no argument (and no setter or property of same name
// as a 'readonly' property.
edit::Commit commit(*Editor);
rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
false /*GetterHasIsPrefix*/);
Editor->commit(commit);
}
} }
} }
@ -747,6 +697,72 @@ static bool TypeIsInnerPointer(QualType T) {
return true; return true;
} }
bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
ObjCInterfaceDecl *D,
ObjCMethodDecl *Method) {
if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
Method->param_size() != 0)
return false;
// Is this method candidate to be a getter?
QualType GRT = Method->getResultType();
if (GRT->isVoidType())
return false;
// FIXME. Don't know what todo with attributes, skip for now.
if (Method->hasAttrs())
return false;
Selector GetterSelector = Method->getSelector();
IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
Selector SetterSelector =
SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
PP.getSelectorTable(),
getterName);
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") && !GRT->isObjCRetainableType()) {
GetterHasIsPrefix = true;
const char *CGetterName = getterNameString.data() + 2;
if (CGetterName[0] && isUppercase(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())
return false;
const ParmVarDecl *argDecl = *SetterMethod->param_begin();
QualType ArgType = argDecl->getType();
if (!Ctx.hasSameUnqualifiedType(ArgType, GRT) ||
SetterMethod->hasAttrs())
return false;
edit::Commit commit(*Editor);
rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
GetterHasIsPrefix);
Editor->commit(commit);
return true;
}
else if (MigrateReadonlyProperty) {
// Try a non-void method with no argument (and no setter or property of same name
// as a 'readonly' property.
edit::Commit commit(*Editor);
rewriteToObjCProperty(Method, 0 /*SetterMethod*/, *NSAPIObj, commit,
false /*GetterHasIsPrefix*/);
Editor->commit(commit);
return true;
}
return false;
}
void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx, void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
ObjCMethodDecl *OM) { ObjCMethodDecl *OM) {
if (OM->hasAttr<ObjCReturnsInnerPointerAttr>()) if (OM->hasAttr<ObjCReturnsInnerPointerAttr>())
@ -770,7 +786,6 @@ void ObjCMigrateASTConsumer::migrateMethods(ASTContext &Ctx,
M != MEnd; ++M) { M != MEnd; ++M) {
ObjCMethodDecl *Method = (*M); ObjCMethodDecl *Method = (*M);
migrateMethodInstanceType(Ctx, CDecl, Method); migrateMethodInstanceType(Ctx, CDecl, Method);
migrateNsReturnsInnerPointer(Ctx, Method);
} }
} }

View File

@ -3,6 +3,10 @@
// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result // 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 // 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
#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
typedef char BOOL; typedef char BOOL;
@class NSString; @class NSString;
@protocol NSCopying @end @protocol NSCopying @end
@ -92,4 +96,7 @@ typedef char BOOL;
- (int) Length; - (int) Length;
- (id) object; - (id) object;
+ (double) D; + (double) D;
- (void *)JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
@end @end

View File

@ -3,6 +3,10 @@
// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result // 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 // 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
#define WEBKIT_OBJC_METHOD_ANNOTATION(ANNOTATION) ANNOTATION
#define WEAK_IMPORT_ATTRIBUTE __attribute__((objc_arc_weak_reference_unavailable))
#define AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER
typedef char BOOL; typedef char BOOL;
@class NSString; @class NSString;
@protocol NSCopying @end @protocol NSCopying @end
@ -92,4 +96,7 @@ typedef char BOOL;
@property(nonatomic, readonly) int Length; @property(nonatomic, readonly) int Length;
@property(nonatomic, readonly) id object; @property(nonatomic, readonly) id object;
+ (double) D; + (double) D;
@property(nonatomic, readonly) void * JSObject WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_WEBKIT_VERSION_3_0_AND_LATER);
@end @end