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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196318 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclObjC.h
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 12e2a0b727ada831ad2002db6be4942fa5044fbf..d4515a272d9eab1876619a04dac44d115ff4b87d 100644 (file)
@@ -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)
index 52fc79810311d49128584ef1d63b9a963d0f9b42..0ca9a082108113e1f6f5a76bf051924927bf1d65 100644 (file)
@@ -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">;
index 409e6158b5025ee9dd4cf2bdad2f73f5f0a06ef8..130bd47568b5cef9960414968d7da4eba6e419e3 100644 (file)
@@ -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();
index b392e2f661919f1c0a9176d46e18ee81c5adde0d..7fe73efc9ebcc500eb477a4c46babf407acf3aaf 100644 (file)
@@ -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)
index cf2b5ebe0e5c4b4a899d1c526d5bbddcea046430..6d5088504c494ac2684e8011c888ffb47476e335 100644 (file)
@@ -30,6 +30,8 @@ void FunctionScopeInfo::Clear() {
   ObjCShouldCallSuper = false;
   ObjCIsDesignatedInit = false;
   ObjCWarnForNoDesignatedInitChain = false;
+  ObjCIsSecondaryInit = false;
+  ObjCWarnForNoInitDelegation = false;
 
   SwitchStack.clear();
   Returns.clear();
index f243c0e8d18a1c09e732782b76ba053577ad0a6c..dc8e66dae4c2a2cf2a1f9b11803051fe52941043 100644 (file)
@@ -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;
   }
index 53c11d59e666ac221284b2d04235a02c3d9a8622..a41bd22cdf13fa0a023e5da7cb5b4a4d312f0ac9 100644 (file)
@@ -391,8 +391,16 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
                                           MDecl->getLocation(), 0);
     }
 
-    if (MDecl->isDesignatedInitializerForTheInterface())
-      getCurFunction()->ObjCIsDesignatedInit = true;
+    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;
     }
   }
 }
index c452306457993e8678f71899ea11fd18a57b2078..5faab1e083b7a31d270b2699226b521de2e3f87f 100644 (file)
@@ -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();
index 59d1357d9e2d2fd360ab9a08a2b9b6ebc1845024..513e51515d6d3db47a8070f07aad99ec433cddfe 100644 (file)
@@ -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