[objc] Emit warning when the implementation of a secondary initializer calls on

super another initializer and when the implementation does not delegate to
another initializer via a call on 'self'.

A secondary initializer is an initializer method not marked as a designated
initializer within a class that has at least one initializer marked as a
designated initializer.

llvm-svn: 196318
This commit is contained in:
Argyrios Kyrtzidis 2013-12-03 21:11:49 +00:00
parent fcded9b93a
commit b66d3cf5cf
9 changed files with 97 additions and 8 deletions

View File

@ -750,6 +750,10 @@ public:
/// marked with the 'objc_designated_initializer' attribute.
void setHasDesignatedInitializers();
/// Returns true if this interface decl contains at least one initializer
/// marked with the 'objc_designated_initializer' attribute.
bool hasDesignatedInitializers() const;
const ObjCProtocolList &getReferencedProtocols() const {
assert(hasDefinition() && "Caller did not check for forward reference!");
if (data().ExternallyCompleted)

View File

@ -2443,6 +2443,12 @@ def warn_objc_designated_init_non_super_designated_init_call : Warning<
def warn_objc_designated_init_non_designated_init_call : Warning<
"designated initializer invoked a non-designated initializer">,
InGroup<ObjCDesignatedInit>;
def warn_objc_secondary_init_super_init_call : Warning<
"secondary initializer should not invoke an initializer on 'super'">,
InGroup<ObjCDesignatedInit>;
def warn_objc_secondary_init_missing_init_call : Warning<
"secondary initializer missing a 'self' call to another initializer">,
InGroup<ObjCDesignatedInit>;
def err_ns_bridged_not_interface : Error<
"parameter of 'ns_bridged' attribute does not name an Objective-C class">;

View File

@ -117,6 +117,14 @@ public:
/// the super class.
bool ObjCWarnForNoDesignatedInitChain;
/// True when this is an initializer method not marked as a designated
/// initializer within a class that has at least one initializer marked as a
/// designated initializer.
bool ObjCIsSecondaryInit;
/// This starts true for a secondary initializer method and will be set to
/// false if there is an invocation of an initializer on 'self'.
bool ObjCWarnForNoInitDelegation;
/// \brief Used to determine if errors occurred in this function or block.
DiagnosticErrorTrap ErrorTrap;
@ -327,6 +335,8 @@ public:
ObjCShouldCallSuper(false),
ObjCIsDesignatedInit(false),
ObjCWarnForNoDesignatedInitChain(false),
ObjCIsSecondaryInit(false),
ObjCWarnForNoInitDelegation(false),
ErrorTrap(Diag) { }
virtual ~FunctionScopeInfo();

View File

@ -1197,6 +1197,14 @@ void ObjCInterfaceDecl::setHasDesignatedInitializers() {
data().HasDesignatedInitializers = true;
}
bool ObjCInterfaceDecl::hasDesignatedInitializers() const {
assert(hasDefinition() && "Forward declarations can't contain methods");
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().HasDesignatedInitializers;
}
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
if (const ObjCInterfaceDecl *Def = getDefinition()) {
if (data().ExternallyCompleted)

View File

@ -30,6 +30,8 @@ void FunctionScopeInfo::Clear() {
ObjCShouldCallSuper = false;
ObjCIsDesignatedInit = false;
ObjCWarnForNoDesignatedInitChain = false;
ObjCIsSecondaryInit = false;
ObjCWarnForNoInitDelegation = false;
SwitchStack.clear();
Returns.clear();

View File

@ -9826,6 +9826,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
diag::note_objc_designated_init_marked_here);
getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
}
if (getCurFunction()->ObjCWarnForNoInitDelegation) {
Diag(MD->getLocation(), diag::warn_objc_secondary_init_missing_init_call);
getCurFunction()->ObjCWarnForNoInitDelegation = false;
}
} else {
return 0;
}

View File

@ -391,8 +391,16 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
MDecl->getLocation(), 0);
}
if (MDecl->isDesignatedInitializerForTheInterface())
if (MDecl->getMethodFamily() == OMF_init) {
if (MDecl->isDesignatedInitializerForTheInterface()) {
getCurFunction()->ObjCIsDesignatedInit = true;
getCurFunction()->ObjCWarnForNoDesignatedInitChain =
IC->getSuperClass() != 0;
} else if (IC->hasDesignatedInitializers()) {
getCurFunction()->ObjCIsSecondaryInit = true;
getCurFunction()->ObjCWarnForNoInitDelegation = true;
}
}
// If this is "dealloc" or "finalize", set some bit here.
// Then in ActOnSuperMessage() (SemaExprObjC), set it back to false.
@ -416,9 +424,6 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
getCurFunction()->ObjCShouldCallSuper =
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
}
if (getCurFunction()->ObjCIsDesignatedInit)
getCurFunction()->ObjCWarnForNoDesignatedInitChain = true;
}
}
}

View File

@ -2476,6 +2476,16 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
if (Method && Method->getMethodFamily() == OMF_init &&
getCurFunction()->ObjCIsSecondaryInit &&
(SuperLoc.isValid() || isSelfExpr(Receiver))) {
if (SuperLoc.isValid()) {
Diag(SelLoc, diag::warn_objc_secondary_init_super_init_call);
} else {
getCurFunction()->ObjCWarnForNoInitDelegation = false;
}
}
// Check the message arguments.
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();

View File

@ -27,8 +27,9 @@ __attribute__((objc_root_class))
-(void)meth {}
-(id)init NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}}
+(id)init { return 0; }
-(id)init3 { return 0; }
-(id)init4 NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}}
-(id)init3 { return 0; } // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
-(id)init4 NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}} \
// expected-warning {{secondary initializer missing a 'self' call to another initializer}}
@end
__attribute__((objc_root_class))
@ -40,7 +41,7 @@ __attribute__((objc_root_class))
@implementation B1
-(id)initB1 { return 0; }
-(id)initB2 { return 0; }
-(id)initB2 { return 0; } // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
-(id)initB3 { return 0; }
@end
@ -134,4 +135,43 @@ __attribute__((objc_root_class))
return [super initB3];
}
-(void)meth {}
-(id)initS1 {
return 0;
}
-(id)initS2 {
return [super initB1];
}
@end
@interface S6 : B1
-(id)initS1 NS_DESIGNATED_INITIALIZER;
-(id)initS2;
-(id)initS3;
-(id)initS4;
@end
@implementation S6
-(id)initS1 {
return [super initB1];
}
-(id)initS2 { // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
return [super initB1]; // expected-warning {{secondary initializer should not invoke an initializer on 'super'}}
}
-(id)initS3 {
return [self initB1];
}
-(id)initS4 {
return [self initS1];
}
-(id)initS5 {
[super initB1]; // expected-warning {{secondary initializer should not invoke an initializer on 'super'}}
void (^blk)(void) = ^{
[super initB1];
};
return [self initS1];
}
-(id)initS6 { // expected-warning {{secondary initializer missing a 'self' call to another initializer}}
S6 *s;
return [s initS1];
}
@end