forked from OSchip/llvm-project
[objcmt] Add a modernization option to infer and suggest designated initializers.
rdar://15509284 llvm-svn: 196943
This commit is contained in:
parent
e919fc20a6
commit
4f2ecc6177
|
@ -184,6 +184,8 @@ def objcmt_returns_innerpointer_property : Flag<["-"], "objcmt-returns-innerpoin
|
|||
HelpText<"Enable migration to annotate property with NS_RETURNS_INNER_POINTER">;
|
||||
def objcmt_ns_nonatomic_iosonly: Flag<["-"], "objcmt-ns-nonatomic-iosonly">, Flags<[CC1Option]>,
|
||||
HelpText<"Enable migration to use NS_NONATOMIC_IOSONLY macro for setting property's 'atomic' attribute">;
|
||||
def objcmt_migrate_designated_init : Flag<["-"], "objcmt-migrate-designated-init">, Flags<[CC1Option]>,
|
||||
HelpText<"Enable migration to infer NS_DESIGNATED_INITIALIZER for initializer methods">;
|
||||
def objcmt_white_list_dir_path: Joined<["-"], "objcmt-white-list-dir-path=">, Flags<[CC1Option]>,
|
||||
HelpText<"Only modify files with a filename contained in the provided directory path">;
|
||||
|
||||
|
|
|
@ -179,10 +179,13 @@ public:
|
|||
ObjCMT_ReturnsInnerPointerProperty = 0x200,
|
||||
/// \brief use NS_NONATOMIC_IOSONLY for property 'atomic' attribute
|
||||
ObjCMT_NsAtomicIOSOnlyProperty = 0x400,
|
||||
/// \brief Enable inferring NS_DESIGNATED_INITIALIZER for ObjC methods.
|
||||
ObjCMT_DesignatedInitializer = 0x800,
|
||||
ObjCMT_MigrateDecls = (ObjCMT_ReadonlyProperty | ObjCMT_ReadwriteProperty |
|
||||
ObjCMT_Annotation | ObjCMT_Instancetype |
|
||||
ObjCMT_NsMacros | ObjCMT_ProtocolConformance |
|
||||
ObjCMT_NsAtomicIOSOnlyProperty),
|
||||
ObjCMT_NsAtomicIOSOnlyProperty |
|
||||
ObjCMT_DesignatedInitializer),
|
||||
ObjCMT_MigrateAll = (ObjCMT_Literals | ObjCMT_Subscripting | ObjCMT_MigrateDecls)
|
||||
};
|
||||
unsigned ObjCMTAction;
|
||||
|
|
|
@ -75,6 +75,10 @@ class ObjCMigrateASTConsumer : public ASTConsumer {
|
|||
|
||||
void migrateAddMethodAnnotation(ASTContext &Ctx,
|
||||
const ObjCMethodDecl *MethodDecl);
|
||||
|
||||
void inferDesignatedInitializers(ASTContext &Ctx,
|
||||
const ObjCImplementationDecl *ImplD);
|
||||
|
||||
public:
|
||||
std::string MigrateDir;
|
||||
unsigned ASTMigrateActions;
|
||||
|
@ -1538,6 +1542,55 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
|
|||
return;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class SuperInitChecker : public RecursiveASTVisitor<SuperInitChecker> {
|
||||
public:
|
||||
bool shouldVisitTemplateInstantiations() const { return false; }
|
||||
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
||||
|
||||
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
|
||||
if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
|
||||
if (E->getMethodFamily() == OMF_init)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
static bool hasSuperInitCall(const ObjCMethodDecl *MD) {
|
||||
return !SuperInitChecker().TraverseStmt(MD->getBody());
|
||||
}
|
||||
|
||||
void ObjCMigrateASTConsumer::inferDesignatedInitializers(
|
||||
ASTContext &Ctx,
|
||||
const ObjCImplementationDecl *ImplD) {
|
||||
|
||||
const ObjCInterfaceDecl *IFace = ImplD->getClassInterface();
|
||||
if (!IFace || IFace->hasDesignatedInitializers())
|
||||
return;
|
||||
if (!Ctx.Idents.get("NS_DESIGNATED_INITIALIZER").hasMacroDefinition())
|
||||
return;
|
||||
|
||||
for (ObjCImplementationDecl::instmeth_iterator
|
||||
I = ImplD->instmeth_begin(), E = ImplD->instmeth_end(); I != E; ++I) {
|
||||
const ObjCMethodDecl *MD = *I;
|
||||
if (MD->isDeprecated() ||
|
||||
MD->getMethodFamily() != OMF_init ||
|
||||
MD->isDesignatedInitializerForTheInterface())
|
||||
continue;
|
||||
const ObjCMethodDecl *IFaceM = IFace->getMethod(MD->getSelector(),
|
||||
/*isInstance=*/true);
|
||||
if (!IFaceM)
|
||||
continue;
|
||||
if (hasSuperInitCall(MD)) {
|
||||
edit::Commit commit(*Editor);
|
||||
commit.insert(IFaceM->getLocEnd(), " NS_DESIGNATED_INITIALIZER");
|
||||
Editor->commit(commit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class RewritesReceiver : public edit::EditsReceiver {
|
||||
|
@ -1657,6 +1710,12 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
|
|||
if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
|
||||
migrateARCSafeAnnotation(Ctx, CDecl);
|
||||
}
|
||||
|
||||
if (const ObjCImplementationDecl *
|
||||
ImplD = dyn_cast<ObjCImplementationDecl>(*D)) {
|
||||
if (ASTMigrateActions & FrontendOptions::ObjCMT_DesignatedInitializer)
|
||||
inferDesignatedInitializers(Ctx, ImplD);
|
||||
}
|
||||
}
|
||||
if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
|
||||
AnnotateImplicitBridging(Ctx);
|
||||
|
|
|
@ -820,6 +820,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
|||
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_AtomicProperty;
|
||||
if (Args.hasArg(OPT_objcmt_ns_nonatomic_iosonly))
|
||||
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty;
|
||||
if (Args.hasArg(OPT_objcmt_migrate_designated_init))
|
||||
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_DesignatedInitializer;
|
||||
if (Args.hasArg(OPT_objcmt_migrate_all))
|
||||
Opts.ObjCMTAction |= FrontendOptions::ObjCMT_MigrateDecls;
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -objcmt-migrate-designated-init %s -triple x86_64-apple-darwin11 -fobjc-arc -migrate -o %t.remap
|
||||
// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -x objective-c -fobjc-arc %s.result
|
||||
|
||||
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
|
||||
@class NSString;
|
||||
|
||||
@interface B1
|
||||
-(id)init;
|
||||
@end
|
||||
|
||||
@interface S1 : B1
|
||||
-(id)initWithFoo:(NSString*)foo;
|
||||
@end
|
||||
|
||||
@implementation S1
|
||||
-(id)initWithFoo:(NSString*)foo
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface B2
|
||||
-(id)init NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@interface S2 : B2
|
||||
-(id)init;
|
||||
@end
|
||||
|
||||
@implementation S2
|
||||
-(id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,44 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -objcmt-migrate-designated-init %s -triple x86_64-apple-darwin11 -fobjc-arc -migrate -o %t.remap
|
||||
// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -x objective-c -fobjc-arc %s.result
|
||||
|
||||
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
|
||||
@class NSString;
|
||||
|
||||
@interface B1
|
||||
-(id)init;
|
||||
@end
|
||||
|
||||
@interface S1 : B1
|
||||
-(id)initWithFoo:(NSString*)foo NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@implementation S1
|
||||
-(id)initWithFoo:(NSString*)foo
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface B2
|
||||
-(id)init NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@interface S2 : B2
|
||||
-(id)init;
|
||||
@end
|
||||
|
||||
@implementation S2
|
||||
-(id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
Loading…
Reference in New Issue