aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2008-05-02 19:17:30 +0000
committerFariborz Jahanian <fjahanian@apple.com>2008-05-02 19:17:30 +0000
commitaebf0cba02c014ac8b19d615c654248e0e93779f (patch)
tree040257a5cee7aedded907f159d659c71ac0b2423
parent92261971835f822e6bcee7baadf2c34b482dfe96 (diff)
This patch is about merging ObjC2's properties declared in class
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
-rw-r--r--include/clang/AST/DeclObjC.h14
-rw-r--r--include/clang/Basic/DiagnosticKinds.def7
-rw-r--r--lib/AST/DeclObjC.cpp27
-rw-r--r--lib/Sema/Sema.h8
-rw-r--r--lib/Sema/SemaDeclObjC.cpp81
-rw-r--r--test/Sema/objc-property-3.m4
-rw-r--r--test/Sema/objc-property-4.m30
7 files changed, 152 insertions, 19 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 93a3457764..5e92708962 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -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; }
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 396bd40ae8..f8583a9019 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -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
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index ef4a6e1c3d..89f6d2c501 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -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.
///
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 1bed03c1fc..68a834c6b4 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index e95ad6469b..afac82ca76 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -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);
diff --git a/test/Sema/objc-property-3.m b/test/Sema/objc-property-3.m
index 565a006fe4..dd45ab43f4 100644
--- a/test/Sema/objc-property-3.m
+++ b/test/Sema/objc-property-3.m
@@ -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
index 0000000000..b5a8f8b1cc
--- /dev/null
+++ b/test/Sema/objc-property-4.m
@@ -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
+