forked from OSchip/llvm-project
[objc] Emit a warning when the implementation of a designated initializer does not chain to
an init method that is a designated initializer for the superclass. llvm-svn: 196316
This commit is contained in:
parent
9ed9e5f31c
commit
22bfa2c28b
|
@ -451,6 +451,14 @@ public:
|
|||
return ImplementationControl(DeclImplementation);
|
||||
}
|
||||
|
||||
/// Returns true if this specific method declaration is marked with the
|
||||
/// designated initializer attribute.
|
||||
bool isThisDeclarationADesignatedInitializer() const;
|
||||
|
||||
/// Returns true if the method selector resolves to a designated initializer
|
||||
/// in the class's interface.
|
||||
bool isDesignatedInitializerForTheInterface() const;
|
||||
|
||||
/// \brief Determine whether this method has a body.
|
||||
virtual bool hasBody() const { return Body.isValid(); }
|
||||
|
||||
|
@ -884,6 +892,18 @@ public:
|
|||
void getDesignatedInitializers(
|
||||
llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const;
|
||||
|
||||
/// Returns true if the given selector is a designated initializer for the
|
||||
/// interface.
|
||||
///
|
||||
/// If this declaration does not have methods marked as designated
|
||||
/// initializers then the interface inherits the designated initializers of
|
||||
/// its super class.
|
||||
///
|
||||
/// \param InitMethod if non-null and the function returns true, it receives
|
||||
/// the method that was marked as a designated initializer.
|
||||
bool isDesignatedInitializer(Selector Sel,
|
||||
const ObjCMethodDecl **InitMethod = 0) const;
|
||||
|
||||
/// \brief Determine whether this particular declaration of this class is
|
||||
/// actually also a definition.
|
||||
bool isThisDeclarationADefinition() const {
|
||||
|
|
|
@ -232,6 +232,7 @@ def BadFunctionCast : DiagGroup<"bad-function-cast">;
|
|||
def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">;
|
||||
def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">;
|
||||
def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
|
||||
def ObjCDesignatedInit : DiagGroup<"objc-designated-initializers">;
|
||||
def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
|
||||
def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">;
|
||||
def ObjCInvalidIBOutletProperty : DiagGroup<"invalid-iboutlet">;
|
||||
|
@ -502,6 +503,7 @@ def Most : DiagGroup<"most", [
|
|||
Unused,
|
||||
VolatileRegisterVar,
|
||||
ObjCMissingSuperCalls,
|
||||
ObjCDesignatedInit,
|
||||
OverloadedVirtual,
|
||||
PrivateExtern,
|
||||
SelTypeCast,
|
||||
|
|
|
@ -2432,6 +2432,11 @@ def err_attr_objc_designated_not_init_family : Error<
|
|||
"'objc_designated_initializer' only applies to methods of the init family">;
|
||||
def err_attr_objc_designated_not_interface : Error<
|
||||
"'objc_designated_initializer' only applies to methods of interface declarations">;
|
||||
def warn_objc_designated_init_missing_super_call : Warning<
|
||||
"designated initializer missing a 'super' call to a designated initializer of the super class">,
|
||||
InGroup<ObjCDesignatedInit>;
|
||||
def note_objc_designated_init_marked_here : Note<
|
||||
"method marked as designated initializer of the class here">;
|
||||
|
||||
def err_ns_bridged_not_interface : Error<
|
||||
"parameter of 'ns_bridged' attribute does not name an Objective-C class">;
|
||||
|
|
|
@ -110,6 +110,13 @@ public:
|
|||
/// with \c __attribute__((objc_requires_super)).
|
||||
bool ObjCShouldCallSuper;
|
||||
|
||||
/// True when this is a method marked as a designated initializer.
|
||||
bool ObjCIsDesignatedInit;
|
||||
/// This starts true for a method marked as designated initializer and will
|
||||
/// be set to false if there is an invocation to a designated initializer of
|
||||
/// the super class.
|
||||
bool ObjCWarnForNoDesignatedInitChain;
|
||||
|
||||
/// \brief Used to determine if errors occurred in this function or block.
|
||||
DiagnosticErrorTrap ErrorTrap;
|
||||
|
||||
|
@ -318,6 +325,8 @@ public:
|
|||
HasIndirectGoto(false),
|
||||
HasDroppedStmt(false),
|
||||
ObjCShouldCallSuper(false),
|
||||
ObjCIsDesignatedInit(false),
|
||||
ObjCWarnForNoDesignatedInitChain(false),
|
||||
ErrorTrap(Diag) { }
|
||||
|
||||
virtual ~FunctionScopeInfo();
|
||||
|
|
|
@ -398,12 +398,39 @@ void ObjCInterfaceDecl::getDesignatedInitializers(
|
|||
for (instmeth_iterator I = IFace->instmeth_begin(),
|
||||
E = IFace->instmeth_end(); I != E; ++I) {
|
||||
const ObjCMethodDecl *MD = *I;
|
||||
if (MD->getMethodFamily() == OMF_init &&
|
||||
MD->hasAttr<ObjCDesignatedInitializerAttr>())
|
||||
if (MD->isThisDeclarationADesignatedInitializer())
|
||||
Methods.push_back(MD);
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjCInterfaceDecl::isDesignatedInitializer(Selector Sel,
|
||||
const ObjCMethodDecl **InitMethod) const {
|
||||
assert(hasDefinition());
|
||||
if (data().ExternallyCompleted)
|
||||
LoadExternalDefinition();
|
||||
|
||||
const ObjCInterfaceDecl *IFace = this;
|
||||
while (IFace) {
|
||||
if (IFace->data().HasDesignatedInitializers)
|
||||
break;
|
||||
IFace = IFace->getSuperClass();
|
||||
}
|
||||
|
||||
if (!IFace)
|
||||
return false;
|
||||
|
||||
if (const ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true,
|
||||
/*shallowCategoryLookup=*/true,
|
||||
/*followSuper=*/false)) {
|
||||
if (MD->isThisDeclarationADesignatedInitializer()) {
|
||||
if (InitMethod)
|
||||
*InitMethod = MD;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ObjCInterfaceDecl::allocateDefinitionData() {
|
||||
assert(!hasDefinition() && "ObjC class already has a definition");
|
||||
Data.setPointer(new (getASTContext()) DefinitionData());
|
||||
|
@ -623,6 +650,20 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
|||
Selector(), QualType(), 0, 0);
|
||||
}
|
||||
|
||||
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
|
||||
return getMethodFamily() == OMF_init &&
|
||||
hasAttr<ObjCDesignatedInitializerAttr>();
|
||||
}
|
||||
|
||||
bool ObjCMethodDecl::isDesignatedInitializerForTheInterface() const {
|
||||
const DeclContext *DC = getDeclContext();
|
||||
if (isa<ObjCProtocolDecl>(DC))
|
||||
return false;
|
||||
if (const ObjCInterfaceDecl *ID = getClassInterface())
|
||||
return ID->isDesignatedInitializer(getSelector());
|
||||
return false;
|
||||
}
|
||||
|
||||
Stmt *ObjCMethodDecl::getBody() const {
|
||||
return Body.get(getASTContext().getExternalSource());
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ void FunctionScopeInfo::Clear() {
|
|||
HasBranchProtectedScope = false;
|
||||
HasBranchIntoScope = false;
|
||||
HasIndirectGoto = false;
|
||||
HasDroppedStmt = false;
|
||||
ObjCShouldCallSuper = false;
|
||||
ObjCIsDesignatedInit = false;
|
||||
ObjCWarnForNoDesignatedInitChain = false;
|
||||
|
||||
SwitchStack.clear();
|
||||
Returns.clear();
|
||||
|
|
|
@ -9814,6 +9814,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
|
|||
<< MD->getSelector().getAsString();
|
||||
getCurFunction()->ObjCShouldCallSuper = false;
|
||||
}
|
||||
if (getCurFunction()->ObjCWarnForNoDesignatedInitChain) {
|
||||
const ObjCMethodDecl *InitMethod = 0;
|
||||
bool isDesignated = MD->getClassInterface()
|
||||
->isDesignatedInitializer(MD->getSelector(), &InitMethod);
|
||||
assert(isDesignated && InitMethod);
|
||||
(void)isDesignated;
|
||||
Diag(MD->getLocation(),
|
||||
diag::warn_objc_designated_init_missing_super_call);
|
||||
Diag(InitMethod->getLocation(),
|
||||
diag::note_objc_designated_init_marked_here);
|
||||
getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -391,6 +391,9 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
|
|||
MDecl->getLocation(), 0);
|
||||
}
|
||||
|
||||
if (MDecl->isDesignatedInitializerForTheInterface())
|
||||
getCurFunction()->ObjCIsDesignatedInit = true;
|
||||
|
||||
// If this is "dealloc" or "finalize", set some bit here.
|
||||
// Then in ActOnSuperMessage() (SemaExprObjC), set it back to false.
|
||||
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
|
||||
|
@ -413,6 +416,9 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
|
|||
getCurFunction()->ObjCShouldCallSuper =
|
||||
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
|
||||
}
|
||||
|
||||
if (getCurFunction()->ObjCIsDesignatedInit)
|
||||
getCurFunction()->ObjCWarnForNoDesignatedInitChain = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2447,6 +2447,16 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
|
|||
}
|
||||
}
|
||||
|
||||
if (SuperLoc.isValid() && getCurFunction()->ObjCIsDesignatedInit) {
|
||||
if (const ObjCObjectPointerType *
|
||||
OCIType = ReceiverType->getAsObjCInterfacePointerType()) {
|
||||
if (const ObjCInterfaceDecl *ID = OCIType->getInterfaceDecl()) {
|
||||
if (ID->isDesignatedInitializer(Sel))
|
||||
getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the message arguments.
|
||||
unsigned NumArgs = ArgsIn.size();
|
||||
Expr **Args = ArgsIn.data();
|
||||
|
|
|
@ -30,3 +30,99 @@ __attribute__((objc_root_class))
|
|||
-(id)init3 { return 0; }
|
||||
-(id)init4 NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}}
|
||||
@end
|
||||
|
||||
__attribute__((objc_root_class))
|
||||
@interface B1
|
||||
-(id)initB1 NS_DESIGNATED_INITIALIZER; // expected-note 2 {{method marked as designated initializer of the class here}}
|
||||
-(id)initB2;
|
||||
-(id)initB3 NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@implementation B1
|
||||
-(id)initB1 { return 0; }
|
||||
-(id)initB2 { return 0; }
|
||||
-(id)initB3 { return 0; }
|
||||
@end
|
||||
|
||||
@interface S1 : B1
|
||||
-(id)initS1 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
|
||||
-(id)initS2 NS_DESIGNATED_INITIALIZER;
|
||||
-(id)initS3 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
|
||||
-(id)initS4 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
|
||||
-(id)initB1;
|
||||
@end
|
||||
|
||||
@implementation S1
|
||||
-(id)initS1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
|
||||
return 0;
|
||||
}
|
||||
-(id)initS2 {
|
||||
return [super initB1];
|
||||
}
|
||||
-(id)initS3 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
|
||||
return [super initB2];
|
||||
}
|
||||
-(id)initS4 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
|
||||
return [self initB1];
|
||||
}
|
||||
-(id)initB1 {
|
||||
return [self initS1];
|
||||
}
|
||||
-(id)initB3 {
|
||||
return [self initS1];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface S2 : B1
|
||||
-(id)initB1;
|
||||
@end
|
||||
|
||||
@interface SS2 : S2
|
||||
-(id)initSS1 NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@implementation SS2
|
||||
-(id)initSS1 {
|
||||
return [super initB1];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface S3 : B1
|
||||
-(id)initS1 NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
|
||||
@interface SS3 : S3
|
||||
-(id)initSS1 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
|
||||
@end
|
||||
|
||||
@implementation SS3
|
||||
-(id)initSS1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
|
||||
return [super initB1];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface S4 : B1
|
||||
-(id)initB1;
|
||||
-(id)initB3;
|
||||
@end
|
||||
|
||||
@implementation S4
|
||||
-(id)initB1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
|
||||
return 0;
|
||||
}
|
||||
-(id)initB3 {
|
||||
return [super initB3];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface S5 : B1
|
||||
@end
|
||||
|
||||
@implementation S5
|
||||
-(id)initB1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
|
||||
return 0;
|
||||
}
|
||||
-(id)initB3 {
|
||||
return [super initB3];
|
||||
}
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue