diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 19fd11d1da25..d2c707c955de 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/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::const_iterator propimpl_iterator; propimpl_iterator propimpl_begin() const { diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 31708b011241..0205789bd832 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/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/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index a313acf20078..d873ad0746be 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index a58d1da63227..03c803054ca4 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/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/clang/test/CodeGenObjC/property.m b/clang/test/CodeGenObjC/property.m index 4598aaa79aad..91d3659dcde7 100644 --- a/clang/test/CodeGenObjC/property.m +++ b/clang/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/clang/test/SemaObjC/property-impl-misuse.m b/clang/test/SemaObjC/property-impl-misuse.m new file mode 100644 index 000000000000..e1913be0e36a --- /dev/null +++ b/clang/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