]> granicus.if.org Git - clang/commitdiff
[objc] Emit a warning when the implementation of a designated initializer does not...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 3 Dec 2013 21:11:36 +0000 (21:11 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 3 Dec 2013 21:11:36 +0000 (21:11 +0000)
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

include/clang/AST/DeclObjC.h
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/ScopeInfo.h
lib/AST/DeclObjC.cpp
lib/Sema/ScopeInfo.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExprObjC.cpp
test/SemaObjC/attr-designated-init.m

index 7db912903b4eeb25d2e6eee26f46fed5cbc0f249..774de1a4fedb4692d0299b7c6fb44cd5738611a8 100644 (file)
@@ -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 { 
index ec1eb1a8b59daf37a168f55ed38752f3961a98b7..7f1c5dc9c16b18714e9a2335e720f1fc9753bb61 100644 (file)
@@ -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,
index 8315c78f259e13531b9ced1b50ff360a1e9da213..314d0375e671323e9bafc8ad701ecd6a729fba4b 100644 (file)
@@ -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">;
index 06afe1a8ae9dd956032823ff4357ff926cc9d5ca..409e6158b5025ee9dd4cf2bdad2f73f5f0a06ef8 100644 (file)
@@ -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();
index 528b52fe5d5bd211b9c2cb1e1524ed22e1248c27..cb58ad482e101018df9385964279182698544df3 100644 (file)
@@ -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());
 }
index 8b3493ebfef86783f2553da3dd9abe9295e4fa8c..cf2b5ebe0e5c4b4a899d1c526d5bbddcea046430 100644 (file)
@@ -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();
index 8229a6224a2cbdfacac1cde49c73fa49c76e8547..c14cc4b8619f329a45a519d2284ca943e418706b 100644 (file)
@@ -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;
   }
index d9b6378269ad0f79bfb23b643404b88914305fdc..53c11d59e666ac221284b2d04235a02c3d9a8622 100644 (file)
@@ -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;
     }
   }
 }
index a60749b0224f4c1347776e8e73b0cf24e4165eb2..20f4b4f7248ae792c285fc22aaf324a63a40c3a9 100644 (file)
@@ -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();
index f607bb694472570ffc802e67e9278dab9a0e36a9..3190d8a97fede90c8f8c550dfc3ab64b18a3dc75 100644 (file)
@@ -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