]> granicus.if.org Git - clang/commitdiff
This patch inserts ivars declared in @implementation in its object and verifies
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 26 Sep 2007 18:27:25 +0000 (18:27 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 26 Sep 2007 18:27:25 +0000 (18:27 +0000)
that they conform(in type, name and numbers) to those declared in @interface.
Test case highlights kind of checking we do here.

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

AST/Decl.cpp
Sema/Sema.h
Sema/SemaDecl.cpp
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
test/Sema/conflicting-ivar-test-1.m [new file with mode: 0644]

index c0a77a2faa58b9a0081602fb07202590448d760b..83762e946580a49015f9e45d35c0d55fab8dbf74 100644 (file)
@@ -294,6 +294,19 @@ void ObjcInterfaceDecl::ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars,
   }
 }
 
+/// ObjcAddInstanceVariablesToClassImpl - Checks for correctness of Instance 
+/// Variables (Ivars) relative to what declared in @implementation;s class. 
+/// Ivars into ObjcImplementationDecl's fields.
+///
+void ObjcImplementationDecl::ObjcAddInstanceVariablesToClassImpl(
+                              ObjcIvarDecl **ivars, unsigned numIvars) {
+  NumIvars = numIvars;
+  if (numIvars) {
+    Ivars = new ObjcIvarDecl*[numIvars];
+    memcpy(Ivars, ivars, numIvars*sizeof(ObjcIvarDecl*));
+  }
+}
+
 /// addObjcMethods - Insert instance and methods declarations into
 /// ObjcInterfaceDecl's InsMethods and ClsMethods fields.
 ///
index 0891c66453e08241771b1477197ea88ef8c5ae28..bb83b0e6aeda91a57f7369d4b4d74a346d0346e7 100644 (file)
@@ -386,6 +386,10 @@ public:
 
   virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl, 
                                     DeclTy **allMethods, unsigned allNum);
+  
+  virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
+                                          DeclTy **Fields, unsigned NumFields);
+  
   virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, 
                    tok::TokenKind MethodType, TypeTy *ReturnType,
                    ObjcKeywordDecl *Keywords, unsigned NumKeywords, 
index 5470eb456bd326b974098eda4dd8361488daa40e..1fb4142796014eaf262af5c0e6c7d7d1c8da4a59 100644 (file)
@@ -1129,6 +1129,51 @@ Sema::DeclTy *Sema::ObjcStartClassImplementation(Scope *S,
   return IMPDecl;
 }
 
+void Sema::ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
+                                      DeclTy **Fields, unsigned numIvars) {
+  ObjcInterfaceDecl* IDecl = 
+    cast<ObjcInterfaceDecl>(static_cast<Decl*>(ClassDecl));
+  assert(IDecl && "missing named interface class decl");
+  ObjcIvarDecl** ivars = reinterpret_cast<ObjcIvarDecl**>(Fields);
+  assert(ivars && "missing @implementation ivars");
+  
+    // Check interface's Ivar list against those in the implementation.
+    // names and types must match.
+    //
+  ObjcIvarDecl** IntfIvars = IDecl->getIntfDeclIvars();
+  int IntfNumIvars = IDecl->getIntfDeclNumIvars();
+  unsigned j = 0;
+  bool err = false;
+  while (numIvars > 0 && IntfNumIvars > 0) {
+    ObjcIvarDecl* ImplIvar = ivars[j];
+    ObjcIvarDecl* ClsIvar = IntfIvars[j++];
+    assert (ImplIvar && "missing implementation ivar");
+    assert (ClsIvar && "missing class ivar");
+    if (ImplIvar->getCanonicalType() != ClsIvar->getCanonicalType()) {
+      Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type,
+           ImplIvar->getIdentifier()->getName());
+      Diag(ClsIvar->getLocation(), diag::err_previous_definition,
+           ClsIvar->getIdentifier()->getName());
+    }
+    // TODO: Two mismatched (unequal width) Ivar bitfields should be diagnosed 
+    // as error.
+    else if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) {
+      Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name,
+           ImplIvar->getIdentifier()->getName());
+      Diag(ClsIvar->getLocation(), diag::err_previous_definition,
+           ClsIvar->getIdentifier()->getName());
+      err = true;
+      break;
+    }
+    --numIvars;
+    --IntfNumIvars;
+  }
+  if (!err && (numIvars > 0 || IntfNumIvars > 0))
+    Diag(numIvars > 0 ? ivars[j]->getLocation() : IntfIvars[j]->getLocation(), 
+         diag::err_inconsistant_ivar);
+      
+}
+
 /// ObjcClassDeclaration - 
 /// Scope will always be top level file scope. 
 Action::DeclTy *
@@ -1463,8 +1508,20 @@ void Sema::ActOnFields(SourceLocation RecLoc, DeclTy *RecDecl,
   else {
     ObjcIvarDecl **ClsFields = 
                     reinterpret_cast<ObjcIvarDecl**>(&RecFields[0]);
-    cast<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl))->
-      ObjcAddInstanceVariablesToClass(ClsFields, RecFields.size());
+    if (isa<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl)))
+      cast<ObjcInterfaceDecl>(static_cast<Decl*>(RecDecl))->
+        ObjcAddInstanceVariablesToClass(ClsFields, RecFields.size());
+    else if (isa<ObjcImplementationDecl>(static_cast<Decl*>(RecDecl))) {
+      ObjcImplementationDecl* IMPDecl = 
+       cast<ObjcImplementationDecl>(static_cast<Decl*>(RecDecl));
+      assert(IMPDecl && "ActOnFields - missing ObjcImplementationDecl");
+      IMPDecl->ObjcAddInstanceVariablesToClassImpl(ClsFields, RecFields.size());
+      ObjcInterfaceDecl* IDecl = 
+        Context.getObjCInterfaceDecl(IMPDecl->getIdentifier());
+      if (IDecl)
+        ActOnImpleIvarVsClassIvars(static_cast<DeclTy*>(IDecl), 
+          reinterpret_cast<DeclTy**>(&RecFields[0]), RecFields.size());
+    }
   }
 }
 
index 7cb370b41cdb47dd3781ef0252ae0e7e1ce24f17..b420c1da813f871c4b40d354ef7225f7ef6469f0 100644 (file)
@@ -587,6 +587,9 @@ public:
       NumIntfRefProtocols = numRefProtos;
     }
   }
+  ObjcIvarDecl **getIntfDeclIvars() const { return Ivars; }
+  int getIntfDeclNumIvars() const { return NumIvars; }
+  
   void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, 
                                       unsigned numIvars);
 
@@ -883,8 +886,8 @@ class ObjcImplementationDecl : public TypeDecl {
       Ivars(0), NumIvars(-1),
       InsMethods(0), NumInsMethods(-1), ClsMethods(0), NumClsMethods(-1) {}
   
-  void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, 
-                                       unsigned numIvars);
+  void ObjcAddInstanceVariablesToClassImpl(ObjcIvarDecl **ivars, 
+                                           unsigned numIvars);
     
   void ObjcAddMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
                         ObjcMethodDecl **clsMethods, unsigned numClsMembers);
index bd41546cd3359d5902b746255fb026b76d780c3d..d77e6b4d24eeec9000be7dd22b62d3d00f4d9f83 100644 (file)
@@ -426,6 +426,13 @@ DIAG(err_dup_implementation_class, ERROR,
      "reimplementation of class '%0'")
 DIAG(err_conflicting_super_class, ERROR,
      "conflicting super class name '%0'")
+DIAG(err_conflicting_ivar_name, ERROR,
+     "conflicting instance variable name '%0'")
+DIAG(err_inconsistant_ivar, ERROR,
+     "inconsistent instance variable specification")
+DIAG(err_conflicting_ivar_type, ERROR,
+     "conflicting instance variable type")
+
 
 //===----------------------------------------------------------------------===//
 // Semantic Analysis
index fe902fc00f2b5eea4120f2f97c2f929a195f49db..bc14226bec0f4b519809be5e13e533494d34a160 100644 (file)
@@ -448,6 +448,10 @@ public:
                                     DeclTy **allMethods, unsigned allNum) {
     return;
   }
+  virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
+                                          DeclTy **Fields, unsigned NumFields) {
+    return;
+  }
   virtual DeclTy *ObjcStartProtoInterface(Scope* S,
                    SourceLocation AtProtoInterfaceLoc,
                     IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
diff --git a/test/Sema/conflicting-ivar-test-1.m b/test/Sema/conflicting-ivar-test-1.m
new file mode 100644 (file)
index 0000000..e08da34
--- /dev/null
@@ -0,0 +1,84 @@
+@interface INTF 
+{
+@public
+       int IVAR; // expected-error {{previous definition is here}}
+}
+@end
+
+@implementation INTF
+{
+@private
+
+        int XIVAR; // expected-error {{conflicting instance variable name 'XIVAR'}}
+}
+@end
+
+
+
+@interface INTF1 
+{
+@public
+       int IVAR;
+       int IVAR1; // expected-error {{inconsistent instance variable specification}}
+}
+@end
+
+@implementation INTF1
+{
+@private
+
+        int IVAR;
+}
+@end
+
+
+@interface INTF2 
+{
+@public
+       int IVAR;
+}
+@end
+
+@implementation INTF2
+{
+@private
+
+        int IVAR;
+       int IVAR1; // expected-error {{inconsistent instance variable specification}}
+}
+@end
+
+
+@interface INTF3
+{
+@public
+       int IVAR; // expected-error {{previous definition is here}}
+}
+@end
+
+@implementation INTF3
+{
+@private
+
+        short IVAR; // expected-error {{conflicting instance variable type}}
+}
+@end
+
+@implementation  INTF4 // expected-warning {{cannot find interface declaration for 'INTF4'}}
+{
+@private
+
+        short IVAR;
+}
+@end
+
+@interface INTF5
+{
+  char * ch;
+}
+@end
+
+@implementation  INTF5
+{
+}
+@end