forked from OSchip/llvm-project
[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:
parent
fcded9b93a
commit
b66d3cf5cf
|
@ -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)
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -30,6 +30,8 @@ void FunctionScopeInfo::Clear() {
|
|||
ObjCShouldCallSuper = false;
|
||||
ObjCIsDesignatedInit = false;
|
||||
ObjCWarnForNoDesignatedInitChain = false;
|
||||
ObjCIsSecondaryInit = false;
|
||||
ObjCWarnForNoInitDelegation = false;
|
||||
|
||||
SwitchStack.clear();
|
||||
Returns.clear();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue