]> granicus.if.org Git - clang/commitdiff
objective-c: Normally, a property cannot be both 'readonly' and having a
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 20 Jun 2012 22:57:42 +0000 (22:57 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 20 Jun 2012 22:57:42 +0000 (22:57 +0000)
"write" attribute (copy/retain/etc.). But, property declaration in
primary class and protcols are tentative as they may be overridden
into a 'readwrite' property in class extensions. Postpone diagnosing
such warnings until the class implementation is seen.
// rdar://11656982

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

include/clang/Sema/Sema.h
lib/Sema/SemaObjCProperty.cpp
test/SemaObjC/property-12.m
test/SemaObjC/tentative-property-decl.m [new file with mode: 0644]

index 4be823a8db2605140e28645c1c4f15d605f98628..6e7f23bd6b9e2da36e1f910fd69e2934279965a6 100644 (file)
@@ -6006,7 +6006,8 @@ public:
   /// be modified to be consistent with \arg PropertyTy.
   void CheckObjCPropertyAttributes(Decl *PropertyPtrTy,
                                    SourceLocation Loc,
-                                   unsigned &Attributes);
+                                   unsigned &Attributes,
+                                   bool propertyInPrimaryClass);
 
   /// Process the specified property declaration and create decls for the
   /// setters and getters as needed.
index 95fbde39af0cbbabae6b4d4a74d145bcf19fc21b..32fbb0432ad4570b8ff7e3d225e63337a89873eb 100644 (file)
@@ -135,7 +135,6 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
 
   // Proceed with constructing the ObjCPropertDecls.
   ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
-
   if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
     if (CDecl->IsClassExtension()) {
       Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
@@ -146,7 +145,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
                                            isOverridingProperty, TSI,
                                            MethodImplKind);
       if (Res) {
-        CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+        CheckObjCPropertyAttributes(Res, AtLoc, Attributes, false);
         if (getLangOpts().ObjCAutoRefCount)
           checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
       }
@@ -163,7 +162,9 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
     Res->setLexicalDeclContext(lexicalDC);
 
   // Validate the attributes on the @property.
-  CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
+  CheckObjCPropertyAttributes(Res, AtLoc, Attributes, 
+                              (isa<ObjCInterfaceDecl>(ClassDecl) ||
+                               isa<ObjCProtocolDecl>(ClassDecl)));
 
   if (getLangOpts().ObjCAutoRefCount)
     checkARCPropertyDecl(*this, Res);
@@ -601,6 +602,67 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
   return;
 }
 
+/// DiagnoseClassAndClassExtPropertyMismatch - diagnose inconsistant property
+/// attribute declared in primary class and attributes overridden in any of its
+/// class extensions.
+static void
+DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl, 
+                                         ObjCPropertyDecl *property) {
+  unsigned Attributes = property->getPropertyAttributesAsWritten();
+  bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly);
+  for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
+       CDecl; CDecl = CDecl->getNextClassExtension()) {
+    warn = false;
+    ObjCPropertyDecl *ClassExtProperty = 0;
+    for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(),
+         E = CDecl->prop_end(); P != E; ++P) {
+      if ((*P)->getIdentifier() == property->getIdentifier()) {
+        ClassExtProperty = *P;
+        break;
+      }
+    }
+    if (ClassExtProperty) {
+      unsigned classExtPropertyAttr = 
+        ClassExtProperty->getPropertyAttributesAsWritten();
+      // We are issuing the warning that we postponed because class extensions
+      // can override readonly->readwrite and 'setter' attributes originally
+      // placed on class's property declaration now make sense in the overridden
+      // property.
+      if (Attributes & ObjCDeclSpec::DQ_PR_readonly) {
+        if (!classExtPropertyAttr ||
+            (classExtPropertyAttr & ObjCDeclSpec::DQ_PR_readwrite))
+          continue;
+        warn = true;
+        break;
+      }
+    }
+  }
+  if (warn) {
+    unsigned setterAttrs = (ObjCDeclSpec::DQ_PR_assign |
+                            ObjCDeclSpec::DQ_PR_unsafe_unretained |
+                            ObjCDeclSpec::DQ_PR_copy |
+                            ObjCDeclSpec::DQ_PR_retain |
+                            ObjCDeclSpec::DQ_PR_strong);
+    if (Attributes & setterAttrs) {
+      const char * which =     
+      (Attributes & ObjCDeclSpec::DQ_PR_assign) ?
+      "assign" :
+      (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) ?
+      "unsafe_unretained" :
+      (Attributes & ObjCDeclSpec::DQ_PR_copy) ?
+      "copy" : 
+      (Attributes & ObjCDeclSpec::DQ_PR_retain) ?
+      "retain" : "strong";
+      
+      S.Diag(property->getLocation(), 
+             diag::warn_objc_property_attr_mutually_exclusive)
+      << "readonly" << which;
+    }
+  }
+  
+  
+}
+
 /// ActOnPropertyImplDecl - This routine performs semantic checks and
 /// builds the AST node for a property implementation declaration; declared
 /// as \@synthesize or \@dynamic.
@@ -681,6 +743,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
         FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
       }
     }
+    
+    DiagnoseClassAndClassExtPropertyMismatch(*this, IDecl, property);
         
   } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) {
     if (Synthesize) {
@@ -1887,7 +1951,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
 
 void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
                                        SourceLocation Loc,
-                                       unsigned &Attributes) {
+                                       unsigned &Attributes,
+                                       bool propertyInPrimaryClass) {
   // FIXME: Improve the reported location.
   if (!PDecl || PDecl->isInvalidDecl())
     return;
@@ -1910,9 +1975,18 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
       return;
   }
   
+  if (propertyInPrimaryClass) {
+    // we postpone most property diagnosis until class's implementation
+    // because, its readonly attribute may be overridden in its class 
+    // extensions making other attributes, which make no sense, to make sense.
+    if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+        (Attributes & ObjCDeclSpec::DQ_PR_readwrite))
+      Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) 
+        << "readonly" << "readwrite";
+  }
   // readonly and readwrite/assign/retain/copy conflict.
-  if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
-      (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
+  else if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
+           (Attributes & (ObjCDeclSpec::DQ_PR_readwrite |
                      ObjCDeclSpec::DQ_PR_assign |
                      ObjCDeclSpec::DQ_PR_unsafe_unretained |
                      ObjCDeclSpec::DQ_PR_copy |
index cd0fccf0e3834f2b0f01273dda82148cfe7905bb..ee9cb1a843fdea90b1ecb5f7d8eed91b36f55e07 100644 (file)
 @end
 
 
+// rdar://11656982
+@interface I0 <P0> @end
+@implementation I0 
+@synthesize X;
+@end
+
+@interface I1 <P1> @end
+@implementation I1 
+@synthesize X;
+@end
+
+@interface I2 <P2> @end
+@implementation I2 
+@synthesize X;
+@end
+
+@interface I3 <P3> @end
+@implementation I3 
+@synthesize X;
+@end
+
+@interface I4 <P4> @end
+@implementation I4 
+@synthesize X;
+@end
+
+@interface I5 <P5> @end
+@implementation I5 
+@synthesize X;
+@end
+
+@interface I6 <P6> @end
+@implementation I6 
+@synthesize X;
+@end
 
diff --git a/test/SemaObjC/tentative-property-decl.m b/test/SemaObjC/tentative-property-decl.m
new file mode 100644 (file)
index 0000000..4ab2f56
--- /dev/null
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -Weverything -verify %s
+// rdar://11656982
+/** Normally, a property cannot be both 'readonly' and having a "write" attribute
+    (copy/retain/etc.). But, property declaration in primary class and protcols
+    are tentative as they may be overridden into a 'readwrite' property in class 
+    extensions. Postpone diagnosing such warnings until the class implementation 
+    is seen.
+*/
+
+@interface Super {
+}
+@end
+
+@class NSString;
+
+@interface MyClass : Super
+@property(nonatomic, copy, readonly) NSString *prop;
+@end
+
+@interface MyClass ()
+@property(nonatomic, copy, readwrite) NSString *prop;
+@end
+
+@implementation MyClass
+@synthesize prop;
+@end
+
+
+@protocol P
+@property(nonatomic, copy, readonly) NSString *prop;
+@end
+
+@interface YourClass : Super <P>
+@end
+
+@interface YourClass ()
+@property(nonatomic, copy, readwrite) NSString *prop;
+@end
+
+@implementation YourClass 
+@synthesize prop;
+@end
+