Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 0801638

Browse files
committed
[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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196316 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 5a02446 commit 0801638

File tree

10 files changed

+207
-2
lines changed

10 files changed

+207
-2
lines changed

Diff for: include/clang/AST/DeclObjC.h

+20
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,14 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
451451
return ImplementationControl(DeclImplementation);
452452
}
453453

454+
/// Returns true if this specific method declaration is marked with the
455+
/// designated initializer attribute.
456+
bool isThisDeclarationADesignatedInitializer() const;
457+
458+
/// Returns true if the method selector resolves to a designated initializer
459+
/// in the class's interface.
460+
bool isDesignatedInitializerForTheInterface() const;
461+
454462
/// \brief Determine whether this method has a body.
455463
virtual bool hasBody() const { return Body.isValid(); }
456464

@@ -884,6 +892,18 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
884892
void getDesignatedInitializers(
885893
llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const;
886894

895+
/// Returns true if the given selector is a designated initializer for the
896+
/// interface.
897+
///
898+
/// If this declaration does not have methods marked as designated
899+
/// initializers then the interface inherits the designated initializers of
900+
/// its super class.
901+
///
902+
/// \param InitMethod if non-null and the function returns true, it receives
903+
/// the method that was marked as a designated initializer.
904+
bool isDesignatedInitializer(Selector Sel,
905+
const ObjCMethodDecl **InitMethod = 0) const;
906+
887907
/// \brief Determine whether this particular declaration of this class is
888908
/// actually also a definition.
889909
bool isThisDeclarationADefinition() const {

Diff for: include/clang/Basic/DiagnosticGroups.td

+2
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ def BadFunctionCast : DiagGroup<"bad-function-cast">;
232232
def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">;
233233
def ObjCPropertyNoAttribute : DiagGroup<"objc-property-no-attribute">;
234234
def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
235+
def ObjCDesignatedInit : DiagGroup<"objc-designated-initializers">;
235236
def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
236237
def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">;
237238
def ObjCInvalidIBOutletProperty : DiagGroup<"invalid-iboutlet">;
@@ -502,6 +503,7 @@ def Most : DiagGroup<"most", [
502503
Unused,
503504
VolatileRegisterVar,
504505
ObjCMissingSuperCalls,
506+
ObjCDesignatedInit,
505507
OverloadedVirtual,
506508
PrivateExtern,
507509
SelTypeCast,

Diff for: include/clang/Basic/DiagnosticSemaKinds.td

+5
Original file line numberDiff line numberDiff line change
@@ -2432,6 +2432,11 @@ def err_attr_objc_designated_not_init_family : Error<
24322432
"'objc_designated_initializer' only applies to methods of the init family">;
24332433
def err_attr_objc_designated_not_interface : Error<
24342434
"'objc_designated_initializer' only applies to methods of interface declarations">;
2435+
def warn_objc_designated_init_missing_super_call : Warning<
2436+
"designated initializer missing a 'super' call to a designated initializer of the super class">,
2437+
InGroup<ObjCDesignatedInit>;
2438+
def note_objc_designated_init_marked_here : Note<
2439+
"method marked as designated initializer of the class here">;
24352440

24362441
def err_ns_bridged_not_interface : Error<
24372442
"parameter of 'ns_bridged' attribute does not name an Objective-C class">;

Diff for: include/clang/Sema/ScopeInfo.h

+9
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ class FunctionScopeInfo {
110110
/// with \c __attribute__((objc_requires_super)).
111111
bool ObjCShouldCallSuper;
112112

113+
/// True when this is a method marked as a designated initializer.
114+
bool ObjCIsDesignatedInit;
115+
/// This starts true for a method marked as designated initializer and will
116+
/// be set to false if there is an invocation to a designated initializer of
117+
/// the super class.
118+
bool ObjCWarnForNoDesignatedInitChain;
119+
113120
/// \brief Used to determine if errors occurred in this function or block.
114121
DiagnosticErrorTrap ErrorTrap;
115122

@@ -318,6 +325,8 @@ class FunctionScopeInfo {
318325
HasIndirectGoto(false),
319326
HasDroppedStmt(false),
320327
ObjCShouldCallSuper(false),
328+
ObjCIsDesignatedInit(false),
329+
ObjCWarnForNoDesignatedInitChain(false),
321330
ErrorTrap(Diag) { }
322331

323332
virtual ~FunctionScopeInfo();

Diff for: lib/AST/DeclObjC.cpp

+43-2
Original file line numberDiff line numberDiff line change
@@ -398,12 +398,39 @@ void ObjCInterfaceDecl::getDesignatedInitializers(
398398
for (instmeth_iterator I = IFace->instmeth_begin(),
399399
E = IFace->instmeth_end(); I != E; ++I) {
400400
const ObjCMethodDecl *MD = *I;
401-
if (MD->getMethodFamily() == OMF_init &&
402-
MD->hasAttr<ObjCDesignatedInitializerAttr>())
401+
if (MD->isThisDeclarationADesignatedInitializer())
403402
Methods.push_back(MD);
404403
}
405404
}
406405

406+
bool ObjCInterfaceDecl::isDesignatedInitializer(Selector Sel,
407+
const ObjCMethodDecl **InitMethod) const {
408+
assert(hasDefinition());
409+
if (data().ExternallyCompleted)
410+
LoadExternalDefinition();
411+
412+
const ObjCInterfaceDecl *IFace = this;
413+
while (IFace) {
414+
if (IFace->data().HasDesignatedInitializers)
415+
break;
416+
IFace = IFace->getSuperClass();
417+
}
418+
419+
if (!IFace)
420+
return false;
421+
422+
if (const ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true,
423+
/*shallowCategoryLookup=*/true,
424+
/*followSuper=*/false)) {
425+
if (MD->isThisDeclarationADesignatedInitializer()) {
426+
if (InitMethod)
427+
*InitMethod = MD;
428+
return true;
429+
}
430+
}
431+
return false;
432+
}
433+
407434
void ObjCInterfaceDecl::allocateDefinitionData() {
408435
assert(!hasDefinition() && "ObjC class already has a definition");
409436
Data.setPointer(new (getASTContext()) DefinitionData());
@@ -623,6 +650,20 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
623650
Selector(), QualType(), 0, 0);
624651
}
625652

653+
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
654+
return getMethodFamily() == OMF_init &&
655+
hasAttr<ObjCDesignatedInitializerAttr>();
656+
}
657+
658+
bool ObjCMethodDecl::isDesignatedInitializerForTheInterface() const {
659+
const DeclContext *DC = getDeclContext();
660+
if (isa<ObjCProtocolDecl>(DC))
661+
return false;
662+
if (const ObjCInterfaceDecl *ID = getClassInterface())
663+
return ID->isDesignatedInitializer(getSelector());
664+
return false;
665+
}
666+
626667
Stmt *ObjCMethodDecl::getBody() const {
627668
return Body.get(getASTContext().getExternalSource());
628669
}

Diff for: lib/Sema/ScopeInfo.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ void FunctionScopeInfo::Clear() {
2626
HasBranchProtectedScope = false;
2727
HasBranchIntoScope = false;
2828
HasIndirectGoto = false;
29+
HasDroppedStmt = false;
30+
ObjCShouldCallSuper = false;
31+
ObjCIsDesignatedInit = false;
32+
ObjCWarnForNoDesignatedInitChain = false;
2933

3034
SwitchStack.clear();
3135
Returns.clear();

Diff for: lib/Sema/SemaDecl.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -9814,6 +9814,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
98149814
<< MD->getSelector().getAsString();
98159815
getCurFunction()->ObjCShouldCallSuper = false;
98169816
}
9817+
if (getCurFunction()->ObjCWarnForNoDesignatedInitChain) {
9818+
const ObjCMethodDecl *InitMethod = 0;
9819+
bool isDesignated = MD->getClassInterface()
9820+
->isDesignatedInitializer(MD->getSelector(), &InitMethod);
9821+
assert(isDesignated && InitMethod);
9822+
(void)isDesignated;
9823+
Diag(MD->getLocation(),
9824+
diag::warn_objc_designated_init_missing_super_call);
9825+
Diag(InitMethod->getLocation(),
9826+
diag::note_objc_designated_init_marked_here);
9827+
getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
9828+
}
98179829
} else {
98189830
return 0;
98199831
}

Diff for: lib/Sema/SemaDeclObjC.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
391391
MDecl->getLocation(), 0);
392392
}
393393

394+
if (MDecl->isDesignatedInitializerForTheInterface())
395+
getCurFunction()->ObjCIsDesignatedInit = true;
396+
394397
// If this is "dealloc" or "finalize", set some bit here.
395398
// Then in ActOnSuperMessage() (SemaExprObjC), set it back to false.
396399
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
@@ -413,6 +416,9 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
413416
getCurFunction()->ObjCShouldCallSuper =
414417
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
415418
}
419+
420+
if (getCurFunction()->ObjCIsDesignatedInit)
421+
getCurFunction()->ObjCWarnForNoDesignatedInitChain = true;
416422
}
417423
}
418424
}

Diff for: lib/Sema/SemaExprObjC.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,16 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
24472447
}
24482448
}
24492449

2450+
if (SuperLoc.isValid() && getCurFunction()->ObjCIsDesignatedInit) {
2451+
if (const ObjCObjectPointerType *
2452+
OCIType = ReceiverType->getAsObjCInterfacePointerType()) {
2453+
if (const ObjCInterfaceDecl *ID = OCIType->getInterfaceDecl()) {
2454+
if (ID->isDesignatedInitializer(Sel))
2455+
getCurFunction()->ObjCWarnForNoDesignatedInitChain = false;
2456+
}
2457+
}
2458+
}
2459+
24502460
// Check the message arguments.
24512461
unsigned NumArgs = ArgsIn.size();
24522462
Expr **Args = ArgsIn.data();

Diff for: test/SemaObjC/attr-designated-init.m

+96
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,99 @@ +(id)init { return 0; }
3030
-(id)init3 { return 0; }
3131
-(id)init4 NS_DESIGNATED_INITIALIZER { return 0; } // expected-error {{only applies to methods of interface declarations}}
3232
@end
33+
34+
__attribute__((objc_root_class))
35+
@interface B1
36+
-(id)initB1 NS_DESIGNATED_INITIALIZER; // expected-note 2 {{method marked as designated initializer of the class here}}
37+
-(id)initB2;
38+
-(id)initB3 NS_DESIGNATED_INITIALIZER;
39+
@end
40+
41+
@implementation B1
42+
-(id)initB1 { return 0; }
43+
-(id)initB2 { return 0; }
44+
-(id)initB3 { return 0; }
45+
@end
46+
47+
@interface S1 : B1
48+
-(id)initS1 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
49+
-(id)initS2 NS_DESIGNATED_INITIALIZER;
50+
-(id)initS3 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
51+
-(id)initS4 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
52+
-(id)initB1;
53+
@end
54+
55+
@implementation S1
56+
-(id)initS1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
57+
return 0;
58+
}
59+
-(id)initS2 {
60+
return [super initB1];
61+
}
62+
-(id)initS3 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
63+
return [super initB2];
64+
}
65+
-(id)initS4 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
66+
return [self initB1];
67+
}
68+
-(id)initB1 {
69+
return [self initS1];
70+
}
71+
-(id)initB3 {
72+
return [self initS1];
73+
}
74+
@end
75+
76+
@interface S2 : B1
77+
-(id)initB1;
78+
@end
79+
80+
@interface SS2 : S2
81+
-(id)initSS1 NS_DESIGNATED_INITIALIZER;
82+
@end
83+
84+
@implementation SS2
85+
-(id)initSS1 {
86+
return [super initB1];
87+
}
88+
@end
89+
90+
@interface S3 : B1
91+
-(id)initS1 NS_DESIGNATED_INITIALIZER;
92+
@end
93+
94+
@interface SS3 : S3
95+
-(id)initSS1 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
96+
@end
97+
98+
@implementation SS3
99+
-(id)initSS1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
100+
return [super initB1];
101+
}
102+
@end
103+
104+
@interface S4 : B1
105+
-(id)initB1;
106+
-(id)initB3;
107+
@end
108+
109+
@implementation S4
110+
-(id)initB1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
111+
return 0;
112+
}
113+
-(id)initB3 {
114+
return [super initB3];
115+
}
116+
@end
117+
118+
@interface S5 : B1
119+
@end
120+
121+
@implementation S5
122+
-(id)initB1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
123+
return 0;
124+
}
125+
-(id)initB3 {
126+
return [super initB3];
127+
}
128+
@end

0 commit comments

Comments
 (0)