]> granicus.if.org Git - clang/commitdiff
This patch is about merging ObjC2's properties declared in class
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 2 May 2008 19:17:30 +0000 (19:17 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 2 May 2008 19:17:30 +0000 (19:17 +0000)
protocols into class's property list and performing semantics
on them for while doing so.

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

include/clang/AST/DeclObjC.h
include/clang/Basic/DiagnosticKinds.def
lib/AST/DeclObjC.cpp
lib/Sema/Sema.h
lib/Sema/SemaDeclObjC.cpp
test/Sema/objc-property-3.m
test/Sema/objc-property-4.m [new file with mode: 0644]

index 93a34577643df3bcffe737e15c17b2960fc28e9c..5e92708962182f9c4d54467e0b89da70cb0f7213 100644 (file)
@@ -285,6 +285,12 @@ public:
   ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const;
   ObjCIvarDecl *FindIvarDeclaration(IdentifierInfo *IvarId) const;
   
+  typedef ObjCProtocolDecl * const * protocol_iterator;
+  protocol_iterator protocol_begin() const { return ReferencedProtocols; }
+  protocol_iterator protocol_end() const {
+    return ReferencedProtocols+NumReferencedProtocols;
+  }
+  
   typedef ObjCIvarDecl * const *ivar_iterator;
   ivar_iterator ivar_begin() const { return Ivars; }
   ivar_iterator ivar_end() const { return Ivars + ivar_size();}
@@ -314,6 +320,8 @@ public:
   
   void addProperties(ObjCPropertyDecl **Properties, unsigned NumProperties);
   
+  void mergeProperties(ObjCPropertyDecl **Properties, unsigned NumProperties);
+  
   typedef ObjCPropertyDecl * const * classprop_iterator;
   classprop_iterator classprop_begin() const { return PropertyDecl; }
   classprop_iterator classprop_end() const {
@@ -517,6 +525,12 @@ public:
     return ReferencedProtocols; 
   }
   unsigned getNumReferencedProtocols() const { return NumReferencedProtocols; }
+  typedef ObjCProtocolDecl * const * protocol_iterator;
+  protocol_iterator protocol_begin() const { return ReferencedProtocols; }
+  protocol_iterator protocol_end() const {
+    return ReferencedProtocols+NumReferencedProtocols;
+  }
+  
   unsigned getNumInstanceMethods() const { return NumInstanceMethods; }
   unsigned getNumClassMethods() const { return NumClassMethods; }
   
index 396bd40ae84448cf708bcc0bbf54e79eeafefb61..f8583a901984c74f42f933ec210971b6e0266e07 100644 (file)
@@ -510,12 +510,11 @@ DIAG(error_property_ivar_type, ERROR,
      "type of property '%0'  does not match type of ivar '%1'") 
 DIAG(warn_readonly_property, WARNING,
      "attribute 'readonly' of property '%0' restricts attribute "
-     "'readwrite' of '%1' property in super class")
+     "'readwrite' of property inherited from '%1'")
 DIAG(warn_property_attribute, WARNING,
-     "property '%0' '%1' attribute does not match super class '%2' "
-     "property")
+     "property '%0' '%1' attribute does not match the property inherited from'%2' ")
 DIAG(warn_property_type, WARNING,
-     "property type '%0' does not match super class '%1' property type")
+     "property type '%0' does not match property type inherited from '%1'")
 
 //===----------------------------------------------------------------------===//
 // Semantic Analysis
index ef4a6e1c3d06bd8a58728b2985df6386e2315531..89f6d2c50195ecc5306a597ec106e7d7bb56e87b 100644 (file)
@@ -242,6 +242,33 @@ void ObjCInterfaceDecl::addProperties(ObjCPropertyDecl **Properties,
   memcpy(PropertyDecl, Properties, NumProperties*sizeof(ObjCPropertyDecl*));
 }                                   
 
+/// mergeProperties - Adds properties to the end of list of current properties
+/// for this class.
+
+void ObjCInterfaceDecl::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*));
+    free(PropertyDecl);
+    PropertyDecl = newPropertyDecl;
+    NumPropertyDecl += NumNewProperties;
+  }
+  else {
+    PropertyDecl = new ObjCPropertyDecl*[NumNewProperties];
+    memcpy(PropertyDecl, Properties, NumNewProperties*sizeof(ObjCPropertyDecl*));
+    NumPropertyDecl = NumNewProperties;
+  }
+}
+
 /// addProperties - Insert property declaration AST nodes into
 /// ObjCProtocolDecl's PropertyDecl field.
 ///
index 1bed03c1fcabe86203b756e7642e56ad5d080f8e..68a834c6b4cbc3223c508cff90203a5e88d87f8b 100644 (file)
@@ -662,9 +662,15 @@ public:
   
   void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, 
                                 ObjCPropertyDecl *SuperProperty,
-                                ObjCInterfaceDecl*SuperIDecl);
+                                const char *Name);
   void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl);
   
+  void MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+                                        DeclTy *MergeProtocols);
+  
+  void MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+                                           ObjCProtocolDecl *PDecl);
+  
   virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl,
                       DeclTy **allMethods = 0, unsigned allNum = 0,
                       DeclTy **allProperties = 0, unsigned pNum = 0);
index e95ad6469bab56945dd7955748764319e2c98546..afac82ca76f505c43795d884e1b762d0e689fc4d 100644 (file)
@@ -247,12 +247,10 @@ Sema::FindProtocolDeclaration(SourceLocation TypeLoc,
 /// DiagnosePropertyMismatch - Compares two properties for their
 /// attributes and types and warns on a variety of inconsistancies.
 ///
-// TODO: Incomplete. 
-//
 void
 Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, 
                                ObjCPropertyDecl *SuperProperty,
-                               ObjCInterfaceDecl *SuperIDecl) {
+                               const char *inheritedName) {
   ObjCPropertyDecl::PropertyAttributeKind CAttr = 
   Property->getPropertyAttributes();
   ObjCPropertyDecl::PropertyAttributeKind SAttr = 
@@ -260,36 +258,36 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
   if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly)
       && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite))
     Diag(Property->getLocation(), diag::warn_readonly_property, 
-               Property->getName(), SuperIDecl->getName());
+               Property->getName(), inheritedName);
   if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy)
       != (SAttr & ObjCPropertyDecl::OBJC_PR_copy))
     Diag(Property->getLocation(), diag::warn_property_attribute,
-         Property->getName(), "copy", SuperIDecl->getName()
+         Property->getName(), "copy", inheritedName
          SourceRange());
   else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain)
            != (SAttr & ObjCPropertyDecl::OBJC_PR_retain))
     Diag(Property->getLocation(), diag::warn_property_attribute,
-         Property->getName(), "retain", SuperIDecl->getName()
+         Property->getName(), "retain", inheritedName
          SourceRange());
   
   if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
       != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
     Diag(Property->getLocation(), diag::warn_property_attribute,
-         Property->getName(), "atomic", SuperIDecl->getName()
+         Property->getName(), "atomic", inheritedName
          SourceRange());
   if (Property->getSetterName() != SuperProperty->getSetterName())
     Diag(Property->getLocation(), diag::warn_property_attribute,
-         Property->getName(), "setter", SuperIDecl->getName()
+         Property->getName(), "setter", inheritedName
          SourceRange());
   if (Property->getGetterName() != SuperProperty->getGetterName())
     Diag(Property->getLocation(), diag::warn_property_attribute,
-         Property->getName(), "getter", SuperIDecl->getName()
+         Property->getName(), "getter", inheritedName
          SourceRange());
   
   if (Property->getCanonicalType() != SuperProperty->getCanonicalType())
     Diag(Property->getLocation(), diag::warn_property_type,
          Property->getType().getAsString(),  
-         SuperIDecl->getName());
+         inheritedName);
   
 }
 
@@ -310,11 +308,69 @@ Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
          E = IDecl->classprop_end(); I != E; ++I) {
       ObjCPropertyDecl *PDecl = (*I);
       if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
-          DiagnosePropertyMismatch(PDecl, SuperPDecl, SDecl);
+          DiagnosePropertyMismatch(PDecl, SuperPDecl, SDecl->getName());
     }
   }
 }
 
+/// 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.
+void
+Sema::MergeOneProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+                                          ObjCProtocolDecl *PDecl)
+{
+  llvm::SmallVector<ObjCPropertyDecl*, 16> mergeProperties;
+  for (ObjCProtocolDecl::classprop_iterator P = PDecl->classprop_begin(),
+       E = PDecl->classprop_end(); P != E; ++P) {
+    ObjCPropertyDecl *Pr = (*P);
+    ObjCInterfaceDecl::classprop_iterator CP, CE;
+    // Is this property already in  class's list of properties?
+    for (CP = IDecl->classprop_begin(), CE = IDecl->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->getName());
+    }
+  IDecl->mergeProperties(&mergeProperties[0], mergeProperties.size());
+}
+
+/// 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'
+///
+
+void
+Sema::MergeProtocolPropertiesIntoClass(ObjCInterfaceDecl *IDecl,
+                                       DeclTy *MergeItsProtocols) {
+  Decl *ClassDecl = static_cast<Decl *>(MergeItsProtocols);
+  if (ObjCInterfaceDecl *MDecl = 
+      dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
+    for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
+         E = MDecl->protocol_end(); P != E; ++P)
+      MergeOneProtocolPropertiesIntoClass(IDecl, (*P));
+      // Merge properties of class (*P) into IDECL's
+      ;
+    // Go thru the list of protocols for this class and recursively merge
+    // their properties into this class as well.
+    for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
+         E = IDecl->protocol_end(); P != E; ++P)
+      MergeProtocolPropertiesIntoClass(IDecl, (*P));
+  }
+  else if (ObjCProtocolDecl *MDecl = 
+           dyn_cast<ObjCProtocolDecl>(ClassDecl))
+    for (ObjCProtocolDecl::protocol_iterator P = MDecl->protocol_begin(),
+         E = MDecl->protocol_end(); P != E; ++P)
+      MergeOneProtocolPropertiesIntoClass(IDecl, (*P));
+  else
+    assert(false && "MergeProtocolPropertiesIntoClass - bad object kind");
+}
+
 /// ActOnForwardProtocolDeclaration - 
 Action::DeclTy *
 Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
@@ -820,7 +876,8 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl,
                   &clsMethods[0], clsMethods.size(), AtEndLoc);
     // Compares properties declaraed in this class to those of its 
     // super class.
-    ComparePropertiesInBaseAndSuper (I);
+    ComparePropertiesInBaseAndSuper(I);
+    MergeProtocolPropertiesIntoClass(I, I);
   } else if (ObjCProtocolDecl *P = dyn_cast<ObjCProtocolDecl>(ClassDecl)) {
     P->addMethods(&insMethods[0], insMethods.size(),
                   &clsMethods[0], clsMethods.size(), AtEndLoc);
index 565a006fe444dd20083e345dbcc31e5b424fde5f..dd45ab43f49157094daf37f380988a88341f1134 100644 (file)
@@ -9,7 +9,7 @@
 @end
 
 @interface NOW : I
-@property (readonly, retain) id d1; // expected-warning {{attribute 'readonly' of property 'd1' restricts attribute 'readwrite' of 'I' property in super class}} expected-warning {{property 'd1' 'copy' attribute does not match super class 'I' property}}
-@property (readwrite, copy) I* d2; // expected-warning {{property type 'I *' does not match super class 'I' property type}}
+@property (readonly, retain) id d1; // expected-warning {{attribute 'readonly' of property 'd1' restricts attribute 'readwrite' of property inherited from 'I'}} expected-warning {{property 'd1' 'copy' attribute does not match the property inherited from'I'}}
+@property (readwrite, copy) I* d2; // expected-warning {{property type 'I *' does not match property type inherited from 'I'}}
 @end
 
diff --git a/test/Sema/objc-property-4.m b/test/Sema/objc-property-4.m
new file mode 100644 (file)
index 0000000..b5a8f8b
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: clang -verify %s
+
+@interface Object 
+@end
+
+@protocol ProtocolObject
+@property int class;
+@property (copy) id MayCauseError;
+@end
+
+@protocol ProtocolDerivedGCObject <ProtocolObject>
+@property int Dclass;
+@end
+
+@interface GCObject  : Object <ProtocolDerivedGCObject> {
+    int ifield;
+    int iOwnClass;
+    int iDclass;
+}
+@property int OwnClass;
+@end
+
+@interface ReleaseObject : GCObject <ProtocolObject> {
+   int newO;
+   int oldO;
+}
+@property (retain) id MayCauseError;  // expected-warning {{property 'MayCauseError' 'copy' attribute does not match the property inherited from'GCObject'}} \
+                                     expected-warning {{property 'MayCauseError' 'copy' attribute does not match the property inherited from'ProtocolObject'}}
+@end
+