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:
parent
fdd91c92d0
commit
215f96c084
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue