From: Fariborz Jahanian Date: Fri, 5 Dec 2008 22:32:48 +0000 (+0000) Subject: This test checks for duplicate implementation of the same X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ae6f6fd1527a1da84679a6f0439dec3bbbd6ca7b;p=clang This test checks for duplicate implementation of the same property. It also checks for duplicate use of the same ivar in two different iproperty implementations. It also caught an error for a test case used in CodeGen :). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60610 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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::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