aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclObjC.h7
-rw-r--r--include/clang/Basic/DiagnosticKinds.def4
-rw-r--r--lib/AST/DeclObjC.cpp54
-rw-r--r--lib/Sema/SemaDeclObjC.cpp35
-rw-r--r--test/CodeGenObjC/property.m8
-rw-r--r--test/SemaObjC/property-impl-misuse.m16
6 files changed, 118 insertions, 6 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 19fd11d1da..d2c707c955 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -1005,6 +1005,9 @@ public:
PropertyImplementations.push_back(property);
}
+ ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId) const;
+ ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const;
+
unsigned getNumPropertyImplementations() const
{ return PropertyImplementations.size(); }
@@ -1101,6 +1104,10 @@ public:
void addPropertyImplementation(ObjCPropertyImplDecl *property) {
PropertyImplementations.push_back(property);
}
+
+ ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId) const;
+ ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const;
+
typedef llvm::SmallVector<ObjCPropertyImplDecl*, 8>::const_iterator
propimpl_iterator;
propimpl_iterator propimpl_begin() const {
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 31708b0112..0205789bd8 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -575,6 +575,10 @@ DIAG(err_setter_type_void, ERROR,
"type of setter must be void")
DIAG(warn_conflicting_types, WARNING,
"conflicting types for %0")
+DIAG(error_property_implemented, ERROR,
+ "property %0 is already implemented")
+DIAG(error_duplicate_ivar_use, ERROR,
+ "synthesized properties %0 and %1 both claim ivar %2")
/// C++ parser diagnostics
DIAG(err_expected_unqualified_id, ERROR,
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index a313acf200..d873ad0746 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -716,6 +716,60 @@ ObjCMethodDecl *ObjCImplementationDecl::getClassMethod(Selector Sel) const {
return NULL;
}
+/// FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl
+/// added to the list of those properties @synthesized/@dynamic in this
+/// @implementation block.
+///
+ObjCPropertyImplDecl *ObjCImplementationDecl::FindPropertyImplDecl(IdentifierInfo *Id) const {
+ for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyDecl()->getIdentifier() == Id)
+ return PID;
+ }
+ return 0;
+}
+
+/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of
+/// properties implemented in this @implementation block and returns it if
+/// found.
+///
+ObjCPropertyImplDecl *ObjCImplementationDecl::FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const {
+ for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyIvarDecl() &&
+ PID->getPropertyIvarDecl()->getIdentifier() == ivarId)
+ return PID;
+ }
+ return 0;
+}
+
+/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of
+/// properties implemented in this category @implementation block and returns it if
+/// found.
+///
+ObjCPropertyImplDecl *ObjCCategoryImplDecl::FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const {
+ for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyIvarDecl() &&
+ PID->getPropertyIvarDecl()->getIdentifier() == ivarId)
+ return PID;
+ }
+ return 0;
+}
+
+/// FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl
+/// added to the list of those properties @synthesized/@dynamic in this
+/// category @implementation block.
+///
+ObjCPropertyImplDecl *ObjCCategoryImplDecl::FindPropertyImplDecl(IdentifierInfo *Id) const {
+ for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); i != e; ++i) {
+ ObjCPropertyImplDecl *PID = *i;
+ if (PID->getPropertyDecl()->getIdentifier() == Id)
+ return PID;
+ }
+ return 0;
+}
+
// lookupInstanceMethod - This method returns an instance method by looking in
// the class implementation. Unlike interfaces, we don't look outside the
// implementation.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index a58d1da632..03c803054c 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1506,10 +1506,41 @@ Sema::DeclTy *Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
ObjCPropertyImplDecl::Synthesize
: ObjCPropertyImplDecl::Dynamic),
Ivar);
- if (IC)
+ if (IC) {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ IC->FindPropertyImplIvarDecl(PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl = IC->FindPropertyImplDecl(PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return 0;
+ }
IC->addPropertyImplementation(PIDecl);
- else
+ }
+ else {
+ if (Synthesize)
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) {
+ Diag(PropertyLoc, diag::error_duplicate_ivar_use)
+ << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier()
+ << PropertyIvar;
+ Diag(PPIDecl->getLocation(), diag::note_previous_use);
+ }
+
+ if (ObjCPropertyImplDecl *PPIDecl =
+ CatImplClass->FindPropertyImplDecl(PropertyId)) {
+ Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
+ Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
+ return 0;
+ }
CatImplClass->addPropertyImplementation(PIDecl);
+ }
return PIDecl;
}
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index 4598aaa79a..91d3659dcd 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -9,6 +9,7 @@
@interface A : Root {
int x;
+ int y, ro, z;
id ob0, ob1, ob2, ob3, ob4;
}
@property int x;
@@ -24,10 +25,9 @@
@implementation A
@dynamic x;
-@synthesize x;
-@synthesize y = x;
-@synthesize z = x;
-@synthesize ro = x;
+@synthesize y;
+@synthesize z = z;
+@synthesize ro;
@synthesize ob0;
@synthesize ob1;
@synthesize ob2;
diff --git a/test/SemaObjC/property-impl-misuse.m b/test/SemaObjC/property-impl-misuse.m
new file mode 100644
index 0000000000..e1913be0e3
--- /dev/null
+++ b/test/SemaObjC/property-impl-misuse.m
@@ -0,0 +1,16 @@
+// RUN: clang -fsyntax-only -verify %s
+
+@interface I {
+ int Y;
+}
+@property int X;
+@property int Y;
+@property int Z;
+@end
+
+@implementation I
+@dynamic X; // expected-note {{previous declaration is here}}
+@dynamic X; // expected-error {{property 'X' is already implemented}}
+@synthesize Y; // expected-note {{previous use is here}}
+@synthesize Z=Y; // expected-error {{synthesized properties 'Z' and 'Y' both claim ivar 'Y'}}
+@end