]> granicus.if.org Git - clang/commitdiff
Class continuation now has its own property ast for
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 15 Feb 2010 21:55:26 +0000 (21:55 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 15 Feb 2010 21:55:26 +0000 (21:55 +0000)
those declared in it. This is to allow duplicate
property diagnostics for properties declared in class extensions
multiple times (radar 7629420) and for future use.

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

include/clang/AST/DeclObjC.h
lib/AST/DeclObjC.cpp
lib/Sema/SemaDeclObjC.cpp
test/SemaObjC/duplicate-property-class-extension.m [new file with mode: 0644]

index 994d68b445db0ac8b5ed8aadc1011dec711bfbf6..e562d352e070ee87dc7c0c591b8e3757d33e8a94 100644 (file)
@@ -949,6 +949,8 @@ public:
     ClassInterface->setCategoryList(this);
   }
 
+  bool IsClassExtension() const { return getIdentifier() == 0; }
+  
   SourceLocation getAtLoc() const { return AtLoc; }
   void setAtLoc(SourceLocation At) { AtLoc = At; }
 
index ffda505aaab1904449dc10e10bc093ae9316883e..131e098d04678b282defa2c6c3a499b8dd294273 100644 (file)
@@ -111,8 +111,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
     // Look through categories.
     for (ObjCCategoryDecl *Category = OID->getCategoryList();
          Category; Category = Category->getNextClassCategory()) {
-      if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
-        return P;
+      if (!Category->IsClassExtension())
+        if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId))
+          return P;
     }
     // Look through protocols.
     for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(),
@@ -124,10 +125,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
       return OID->getSuperClass()->FindPropertyDeclaration(PropertyId);
   } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) {
     // Look through protocols.
-    for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
-         E = OCD->protocol_end(); I != E; ++I) {
-      if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
-        return P;
+    if (!OCD->IsClassExtension())
+      for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(),
+           E = OCD->protocol_end(); I != E; ++I) {
+        if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
+          return P;
     }
   }
   return 0;
index af51fb10c16a5889bb2d5dcbac962f368426d20d..1e9b56a90ed6eaf04f3273205bba367ffc42e08d 100644 (file)
@@ -446,18 +446,19 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
     // Category
     ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
     assert (CatDecl && "MatchOneProtocolPropertiesInClass");
-    for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
-         E = PDecl->prop_end(); P != E; ++P) {
-      ObjCPropertyDecl *Pr = (*P);
-      ObjCCategoryDecl::prop_iterator CP, CE;
-      // Is this property already in  category's list of properties?
-      for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
-        if ((*CP)->getIdentifier() == Pr->getIdentifier())
-          break;
-      if (CP != CE)
-        // Property protocol already exist in class. Diagnose any mismatch.
-        DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
-    }
+    if (!CatDecl->IsClassExtension())
+      for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+           E = PDecl->prop_end(); P != E; ++P) {
+        ObjCPropertyDecl *Pr = (*P);
+        ObjCCategoryDecl::prop_iterator CP, CE;
+        // Is this property already in  category's list of properties?
+        for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP)
+          if ((*CP)->getIdentifier() == Pr->getIdentifier())
+            break;
+        if (CP != CE)
+          // Property protocol already exist in class. Diagnose any mismatch.
+          DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier());
+      }
     return;
   }
   for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
@@ -596,44 +597,59 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
                             unsigned NumProtoRefs,
                             const SourceLocation *ProtoLocs,
                             SourceLocation EndProtoLoc) {
-  ObjCCategoryDecl *CDecl =
-    ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
-                             CategoryLoc, CategoryName);
-  // FIXME: PushOnScopeChains?
-  CurContext->addDecl(CDecl);
-
+  ObjCCategoryDecl *CDecl = 0;
   ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc);
-  /// Check that class of this category is already completely declared.
-  if (!IDecl || IDecl->isForwardDecl()) {
-    CDecl->setInvalidDecl();
-    Diag(ClassLoc, diag::err_undef_interface) << ClassName;
-    return DeclPtrTy::make(CDecl);
+  if (!CategoryName) {
+    // Class extensions require a special treatment. Use an existing one.
+    for (CDecl = IDecl->getCategoryList(); CDecl;
+         CDecl = CDecl->getNextClassCategory())
+      if (CDecl->IsClassExtension()) 
+        break;  
   }
+  if (!CDecl) {
+    CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
+                                     CategoryLoc, CategoryName);
+    // FIXME: PushOnScopeChains?
+    CurContext->addDecl(CDecl);
+
+    /// Check that class of this category is already completely declared.
+    if (!IDecl || IDecl->isForwardDecl()) {
+      CDecl->setInvalidDecl();
+      Diag(ClassLoc, diag::err_undef_interface) << ClassName;
+      return DeclPtrTy::make(CDecl);
+    }
 
-  CDecl->setClassInterface(IDecl);
+    CDecl->setClassInterface(IDecl);
+    // Insert first use of class extension to the list of class's categories.
+    if (!CategoryName)
+      CDecl->insertNextClassCategory();
+  }
 
   // If the interface is deprecated, warn about it.
   (void)DiagnoseUseOfDecl(IDecl, ClassLoc);
 
-  /// Check for duplicate interface declaration for this category
-  ObjCCategoryDecl *CDeclChain;
-  for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
-       CDeclChain = CDeclChain->getNextClassCategory()) {
-    if (CategoryName && CDeclChain->getIdentifier() == CategoryName) {
-      Diag(CategoryLoc, diag::warn_dup_category_def)
-      << ClassName << CategoryName;
-      Diag(CDeclChain->getLocation(), diag::note_previous_definition);
-      break;
+  if (CategoryName) {
+    /// Check for duplicate interface declaration for this category
+    ObjCCategoryDecl *CDeclChain;
+    for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
+         CDeclChain = CDeclChain->getNextClassCategory()) {
+      if (CDeclChain->getIdentifier() == CategoryName) {
+        // Class extensions can be declared multiple times.
+        Diag(CategoryLoc, diag::warn_dup_category_def)
+          << ClassName << CategoryName;
+        Diag(CDeclChain->getLocation(), diag::note_previous_definition);
+        break;
+      }
     }
+    if (!CDeclChain)
+      CDecl->insertNextClassCategory();
   }
-  if (!CDeclChain)
-    CDecl->insertNextClassCategory();
 
   if (NumProtoRefs) {
     CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, 
                            ProtoLocs, Context);
     // Protocols in the class extension belong to the class.
-    if (!CDecl->getIdentifier())
+    if (CDecl->IsClassExtension())
      IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, 
                                             NumProtoRefs, ProtoLocs,
                                             Context); 
@@ -1102,11 +1118,12 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
       CollectImmediateProperties((*PI), PropMap);
   }
   if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
-    for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
-         E = CATDecl->prop_end(); P != E; ++P) {
-      ObjCPropertyDecl *Prop = (*P);
-      PropMap[Prop->getIdentifier()] = Prop;
-    }
+    if (!CATDecl->IsClassExtension())
+      for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
+           E = CATDecl->prop_end(); P != E; ++P) {
+        ObjCPropertyDecl *Prop = (*P);
+        PropMap[Prop->getIdentifier()] = Prop;
+      }
     // scan through class's protocols.
     for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
          E = CATDecl->protocol_end(); PI != E; ++PI)
@@ -1261,7 +1278,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
     // Check class extensions (unnamed categories)
     for (ObjCCategoryDecl *Categories = I->getCategoryList();
          Categories; Categories = Categories->getNextClassCategory()) {
-      if (!Categories->getIdentifier()) {
+      if (Categories->IsClassExtension()) {
         ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl);
         break;
       }
@@ -1269,7 +1286,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
   } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
     // For extended class, unimplemented methods in its protocols will
     // be reported in the primary class.
-    if (C->getIdentifier()) {
+    if (!C->IsClassExtension()) {
       for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(),
            E = C->protocol_end(); PI != E; ++PI)
         CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
@@ -1826,17 +1843,18 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
 
     // Compare protocol properties with those in category
     CompareProperties(C, DeclPtrTy::make(C));
-    if (C->getIdentifier() == 0)
+    if (C->IsClassExtension())
       DiagnoseClassExtensionDupMethods(C, C->getClassInterface());
   }
   if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) {
-    // ProcessPropertyDecl is responsible for diagnosing conflicts with any
-    // user-defined setter/getter. It also synthesizes setter/getter methods
-    // and adds them to the DeclContext and global method pools.
-    for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
-                                          E = CDecl->prop_end();
-         I != E; ++I)
-      ProcessPropertyDecl(*I, CDecl);
+    if (CDecl->getIdentifier())
+      // ProcessPropertyDecl is responsible for diagnosing conflicts with any
+      // user-defined setter/getter. It also synthesizes setter/getter methods
+      // and adds them to the DeclContext and global method pools.
+      for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(),
+                                            E = CDecl->prop_end();
+           I != E; ++I)
+        ProcessPropertyDecl(*I, CDecl);
     CDecl->setAtEndRange(AtEnd);
   }
   if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
@@ -2137,7 +2155,22 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
   // May modify Attributes.
   CheckObjCPropertyAttributes(T, AtLoc, Attributes);
   if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
-    if (!CDecl->getIdentifier()) {
+    if (CDecl->IsClassExtension()) {
+      // Diagnose if this property is already in continuation class.
+      DeclContext *DC = dyn_cast<DeclContext>(ClassDecl);
+      assert(DC && "ClassDecl is not a DeclContext");
+      DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier());
+      if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
+        Diag(AtLoc, diag::err_duplicate_property);
+        Diag((*Found.first)->getLocation(), diag::note_property_declare);
+        return DeclPtrTy();
+      }
+      ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
+                                                         FD.D.getIdentifierLoc(),
+                                                         FD.D.getIdentifier(),
+                                                         AtLoc, T);
+      DC->addDecl(PDecl);
+      
       // This is a continuation class. property requires special
       // handling.
       if ((CCPrimary = CDecl->getClassInterface())) {
@@ -2201,6 +2234,7 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
           ProcessPropertyDecl(PIDecl, CCPrimary);
           return DeclPtrTy();
         }
+        
         // No matching property found in the primary class. Just fall thru
         // and add property to continuation class's primary class.
         ClassDecl = CCPrimary;
@@ -2354,7 +2388,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc,
     }
     if (const ObjCCategoryDecl *CD = 
         dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) {
-      if (CD->getIdentifier()) {
+      if (!CD->IsClassExtension()) {
         Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName();
         Diag(property->getLocation(), diag::note_property_declare);
         return DeclPtrTy();
diff --git a/test/SemaObjC/duplicate-property-class-extension.m b/test/SemaObjC/duplicate-property-class-extension.m
new file mode 100644 (file)
index 0000000..bdf4786
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1  -fsyntax-only -verify %s
+
+@interface Foo 
+@property (readonly) char foo;
+@end
+
+@interface Foo ()
+@property (readwrite) char foo; // expected-note {{property declared here}}
+@end
+
+@interface Foo ()
+@property (readwrite) char foo;        // expected-error {{property has a previous declaration}}
+@end