r196316 - [objc] Emit a warning when the implementation of a designated initializer does not chain to
Argyrios Kyrtzidis
akyrtzi at gmail.com
Tue Dec 3 13:11:37 PST 2013
Author: akirtzidis
Date: Tue Dec 3 15:11:36 2013
New Revision: 196316
URL: http://llvm.org/viewvc/llvm-project?rev=196316&view=rev
Log:
[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.
Modified:
cfe/trunk/include/clang/AST/DeclObjC.h
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/ScopeInfo.h
cfe/trunk/lib/AST/DeclObjC.cpp
cfe/trunk/lib/Sema/ScopeInfo.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/lib/Sema/SemaExprObjC.cpp
cfe/trunk/test/SemaObjC/attr-designated-init.m
Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Tue Dec 3 15:11:36 2013
@@ -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 {
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Dec 3 15:11:36 2013
@@ -232,6 +232,7 @@ def BadFunctionCast : DiagGroup<"bad-fun
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,
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Dec 3 15:11:36 2013
@@ -2432,6 +2432,11 @@ def err_attr_objc_designated_not_init_fa
"'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">;
Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Tue Dec 3 15:11:36 2013
@@ -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();
Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Tue Dec 3 15:11:36 2013
@@ -398,12 +398,39 @@ void ObjCInterfaceDecl::getDesignatedIni
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::CreateDe
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());
}
Modified: cfe/trunk/lib/Sema/ScopeInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ScopeInfo.cpp?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/ScopeInfo.cpp (original)
+++ cfe/trunk/lib/Sema/ScopeInfo.cpp Tue Dec 3 15:11:36 2013
@@ -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();
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Dec 3 15:11:36 2013
@@ -9814,6 +9814,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl
<< 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;
}
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Dec 3 15:11:36 2013
@@ -391,6 +391,9 @@ void Sema::ActOnStartOfObjCMethodDef(Sco
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(Sco
getCurFunction()->ObjCShouldCallSuper =
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
}
+
+ if (getCurFunction()->ObjCIsDesignatedInit)
+ getCurFunction()->ObjCWarnForNoDesignatedInitChain = true;
}
}
}
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Tue Dec 3 15:11:36 2013
@@ -2447,6 +2447,16 @@ ExprResult Sema::BuildInstanceMessage(Ex
}
}
+ 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();
Modified: cfe/trunk/test/SemaObjC/attr-designated-init.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/attr-designated-init.m?rev=196316&r1=196315&r2=196316&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/attr-designated-init.m (original)
+++ cfe/trunk/test/SemaObjC/attr-designated-init.m Tue Dec 3 15:11:36 2013
@@ -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))
+ at 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;
+ at end
+
+ at implementation B1
+-(id)initB1 { return 0; }
+-(id)initB2 { return 0; }
+-(id)initB3 { return 0; }
+ at end
+
+ at 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;
+ at end
+
+ at 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];
+}
+ at end
+
+ at interface S2 : B1
+-(id)initB1;
+ at end
+
+ at interface SS2 : S2
+-(id)initSS1 NS_DESIGNATED_INITIALIZER;
+ at end
+
+ at implementation SS2
+-(id)initSS1 {
+ return [super initB1];
+}
+ at end
+
+ at interface S3 : B1
+-(id)initS1 NS_DESIGNATED_INITIALIZER;
+ at end
+
+ at interface SS3 : S3
+-(id)initSS1 NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
+ at end
+
+ at implementation SS3
+-(id)initSS1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
+ return [super initB1];
+}
+ at end
+
+ at interface S4 : B1
+-(id)initB1;
+-(id)initB3;
+ at end
+
+ at 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];
+}
+ at end
+
+ at interface S5 : B1
+ at end
+
+ at 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];
+}
+ at end
More information about the cfe-commits
mailing list