]> granicus.if.org Git - clang/commitdiff
Use of properties declared in protocols in the category
authorFariborz Jahanian <fjahanian@apple.com>
Sat, 6 Dec 2008 23:03:39 +0000 (23:03 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Sat, 6 Dec 2008 23:03:39 +0000 (23:03 +0000)
via the category's protocol list1s, with appropriate
diagnsostics and a test case.

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

include/clang/AST/DeclObjC.h
lib/AST/DeclObjC.cpp
lib/Sema/Sema.h
lib/Sema/SemaDeclObjC.cpp
test/SemaObjC/property-category-3.m [new file with mode: 0644]

index d2c707c955de59b98405e3bf542ebcc19f3fa11a..190c1c3509c0dad3342f8ce5dce560c8a3950c9b 100644 (file)
@@ -883,6 +883,8 @@ public:
   
   void addProperties(ObjCPropertyDecl **Properties, unsigned NumProperties);
 
+  void mergeProperties(ObjCPropertyDecl **Properties, unsigned NumProperties);
+
   void addPropertyMethods(ASTContext &Context,
                           ObjCPropertyDecl* Property,
                           llvm::SmallVector<ObjCMethodDecl*, 32> &insMethods,
index 58d0383d1fe3fb267a3917cdf49dbe627920530a..0458282fb38b8c706f4e79e04436061c8d401de5 100644 (file)
@@ -513,6 +513,31 @@ void ObjCCategoryDecl::addPropertyMethods(
   ::addPropertyMethods(this, Context, property, insMethods, InsMap);
 }
 
+/// mergeProperties - Adds properties to the end of list of current properties
+/// for this category.
+
+void ObjCCategoryDecl::mergeProperties(ObjCPropertyDecl **Properties, 
+                                        unsigned NumNewProperties) {
+  if (NumNewProperties == 0) return;
+  
+  if (PropertyDecl) {
+    ObjCPropertyDecl **newPropertyDecl =  
+      new ObjCPropertyDecl*[NumNewProperties + NumPropertyDecl];
+    ObjCPropertyDecl **buf = newPropertyDecl;
+    // put back original properties in buffer.
+    memcpy(buf, PropertyDecl, NumPropertyDecl*sizeof(ObjCPropertyDecl*));
+    // Add new properties to this buffer.
+    memcpy(buf+NumPropertyDecl, Properties, 
+           NumNewProperties*sizeof(ObjCPropertyDecl*));
+    delete[] PropertyDecl;
+    PropertyDecl = newPropertyDecl;
+    NumPropertyDecl += NumNewProperties;
+  }
+  else {
+    addProperties(Properties, NumNewProperties);
+  }
+}
+
 /// addPropertyMethods - Goes through list of properties declared in this class
 /// and builds setter/getter method declartions depending on the setter/getter
 /// attributes of the property.
index a9ad257e41b4b8a41707f0d237bbc2229db7edcf..ef99aaaa46c6bdbfd0e61d418ce1605c1e615cda 100644 (file)
@@ -1075,10 +1075,10 @@ public:
                                 const IdentifierInfo *Name);
   void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl);
   
-  void MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+  void MergeProtocolPropertiesIntoClass(Decl *CDecl,
                                         DeclTy *MergeProtocols);
   
-  void MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+  void MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
                                            ObjCProtocolDecl *PDecl);
   
   virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl,
index a5ffb7090565f3e47b1ae575c527ce18271cba22..54934425806ed0174a7f931a1fb4b35366c3ce08 100644 (file)
@@ -311,11 +311,35 @@ Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
 
 /// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list
 /// of properties declared in a protocol and adds them to the list
-/// of properties for current class if it is not there already.
+/// of properties for current class/category if it is not there already.
 void
-Sema::MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
                                           ObjCProtocolDecl *PDecl) {
   llvm::SmallVector<ObjCPropertyDecl*, 16> mergeProperties;
+  ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
+  if (!IDecl) {
+    // Category
+    ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+    assert (CatDecl && "MergeOneProtocolPropertiesIntoClass");
+    for (ObjCProtocolDecl::classprop_iterator P = PDecl->classprop_begin(),
+         E = PDecl->classprop_end(); P != E; ++P) {
+      ObjCPropertyDecl *Pr = (*P);
+      ObjCCategoryDecl::classprop_iterator CP, CE;
+      // Is this property already in  category's list of properties?
+      for (CP = CatDecl->classprop_begin(), CE = CatDecl->classprop_end(); 
+           CP != CE; ++CP)
+        if ((*CP)->getIdentifier() == Pr->getIdentifier())
+          break;
+      if (CP == CE)
+        // Add this property to list of properties for thie class.
+        mergeProperties.push_back(Pr);
+      else
+        // Property protocol already exist in class. Diagnose any mismatch.
+        DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+    }
+    CatDecl->mergeProperties(&mergeProperties[0], mergeProperties.size());
+    return;
+  }
   for (ObjCProtocolDecl::classprop_iterator P = PDecl->classprop_begin(),
        E = PDecl->classprop_end(); P != E; ++P) {
     ObjCPropertyDecl *Pr = (*P);
@@ -337,13 +361,39 @@ Sema::MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
 
 /// MergeProtocolPropertiesIntoClass - This routine merges properties
 /// declared in 'MergeItsProtocols' objects (which can be a class or an
-/// inherited protocol into the list of properties for class 'IDecl'
+/// inherited protocol into the list of properties for class/category 'CDecl'
 ///
 
 void
-Sema::MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
                                        DeclTy *MergeItsProtocols) {
   Decl *ClassDecl = static_cast<Decl *>(MergeItsProtocols);
+  ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
+
+  if (!IDecl) {
+    // Category
+    ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+    assert (CatDecl && "MergeProtocolPropertiesIntoClass");
+    if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
+      for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
+           E = MDecl->protocol_end(); P != E; ++P)
+      // Merge properties of category (*P) into IDECL's
+      MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
+    
+      // Go thru the list of protocols for this category and recursively merge
+      // their properties into this class as well.
+      for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
+           E = CatDecl->protocol_end(); P != E; ++P)
+        MergeProtocolPropertiesIntoClass(CatDecl, *P);
+    } else {
+      ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
+      for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
+           E = MD->protocol_end(); P != E; ++P)
+        MergeOneProtocolPropertiesIntoClass(CatDecl, (*P));
+    }
+    return;
+  }
+
   if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
     for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
          E = MDecl->protocol_end(); P != E; ++P)
@@ -1063,8 +1113,8 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl,
     // By the same token, they are also used to add new properties. No 
     // need to compare the added property to those in the class.
 
-    // FIXME: If we merge properties into class we should probably
-    // merge them into category as well?
+    // Merge protocol properties into category
+    MergeProtocolPropertiesIntoClass(C, C);
     for (ObjCCategoryDecl::classprop_iterator i = C->classprop_begin(),
          e = C->classprop_end(); i != e; ++i) {
       diagnosePropertySetterGetterMismatch((*i), InsMap[(*i)->getGetterName()],
diff --git a/test/SemaObjC/property-category-3.m b/test/SemaObjC/property-category-3.m
new file mode 100644 (file)
index 0000000..d651b85
--- /dev/null
@@ -0,0 +1,21 @@
+@protocol P
+  @property(readonly) int X;
+@end
+
+@protocol P1<P>
+  @property (copy) id ID;
+@end
+
+@interface I
+@end
+
+@interface I (Cat) <P>
+@property float X; // expected-warning {{property type 'float' does not match property type inherited from 'P'}}
+@end
+
+@interface I (Cat2) <P1>
+@property (retain) id ID; // expected-warning {{property 'ID' 'copy' attribute does not match the property inherited from 'P1'}}
+@end
+
+
+