]> granicus.if.org Git - clang/commitdiff
Objective-C [qoi]: When an class conforms to multiple
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 20 May 2013 21:20:24 +0000 (21:20 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 20 May 2013 21:20:24 +0000 (21:20 +0000)
protocols that declare the same property of incompatible
types, issue a warning when class implementation synthesizes
the property. // rdar://13075400

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

include/clang/AST/DeclObjC.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/DeclObjC.cpp
lib/Sema/SemaObjCProperty.cpp
test/SemaObjC/property-ambiguous-synthesis.m [new file with mode: 0644]

index 0028240349ae18dd4eabc62c0833908245018742..e4ca61a5c078519dc460ed6a52fcc8d26fe86269 100644 (file)
@@ -553,6 +553,9 @@ public:
 
   typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
   
+  typedef llvm::DenseMap<const ObjCProtocolDecl *, ObjCPropertyDecl*>
+            ProtocolPropertyMap;
+  
   typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
   
   /// This routine collects list of properties to be implemented in the class.
@@ -1513,6 +1516,9 @@ public:
 
   virtual void collectPropertiesToImplement(PropertyMap &PM,
                                             PropertyDeclOrder &PO) const;
+                           
+void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
+                                        ProtocolPropertyMap &PM) const;
 
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == ObjCProtocol; }
index 55fae9ffedf6aad7597d5d7f7544ad4d3a28dcb7..f1a179c259c8a2bf7fb6a99793b576e183ab0ccd 100644 (file)
@@ -488,6 +488,9 @@ def warn_property_attribute : Warning<
   "'%1' attribute on property %0 does not match the property inherited from %2">;
 def warn_property_types_are_incompatible : Warning<
   "property type %0 is incompatible with type %1 inherited from %2">;
+def warn_protocol_property_mismatch : Warning<
+  "property of type %0 was selected for synthesis">,
+  InGroup<DiagGroup<"protocol-property-synthesis-ambiguity">>;
 def err_undef_interface : Error<"cannot find interface declaration for %0">;
 def err_category_forward_interface : Error<
   "cannot define %select{category|class extension}0 for undefined class %1">;
@@ -729,6 +732,8 @@ def error_category_property : Error<
   "class implementation">;
 def note_property_declare : Note<
   "property declared here">;
+def note_protocol_property_declare : Note<
+  "it could also be property of type %0 declared here">;
 def note_property_synthesize : Note<
   "property synthesized here">;
 def error_synthesize_category_decl : Error<
index 4ddbb22199b2f94e0caabaff81633f5f8cfd9df1..0291803fd4695546ef72cd2fded22aac9eae01cf 100644 (file)
@@ -1493,6 +1493,30 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
   }
 }
 
+    
+void ObjCProtocolDecl::collectInheritedProtocolProperties(
+                                                const ObjCPropertyDecl *Property,
+                                                ProtocolPropertyMap &PM) const {
+  if (const ObjCProtocolDecl *PDecl = getDefinition()) {
+    bool MatchFound = false;
+    for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+         E = PDecl->prop_end(); P != E; ++P) {
+      ObjCPropertyDecl *Prop = *P;
+      if (Prop == Property)
+        continue;
+      if (Prop->getIdentifier() == Property->getIdentifier()) {
+        PM[PDecl] = Prop;
+        MatchFound = true;
+        break;
+      }
+    }
+    // Scan through protocol's protocols which did not have a matching property.
+    if (!MatchFound)
+      for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+           E = PDecl->protocol_end(); PI != E; ++PI)
+        (*PI)->collectInheritedProtocolProperties(Property, PM);
+  }
+}
 
 //===----------------------------------------------------------------------===//
 // ObjCCategoryDecl
index 269c65e6082cd50a091c5aceacc71285349b076c..e49edc908aa099e3fc7c745f661eec477486b699 100644 (file)
@@ -714,6 +714,58 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
   return;
 }
 
+/// DiagnosePropertyMismatchDeclInProtocols - diagnose properties declared
+/// in inherited protocols with mismatched types. Since any of them can
+/// be candidate for synthesis.
+void DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,
+                                             ObjCInterfaceDecl *ClassDecl,
+                                        ObjCPropertyDecl *Property) {
+  ObjCInterfaceDecl::ProtocolPropertyMap PropMap;
+  for (ObjCInterfaceDecl::all_protocol_iterator
+       PI = ClassDecl->all_referenced_protocol_begin(),
+       E = ClassDecl->all_referenced_protocol_end(); PI != E; ++PI) {
+    if (const ObjCProtocolDecl *PDecl = (*PI)->getDefinition())
+      PDecl->collectInheritedProtocolProperties(Property, PropMap);
+  }
+  if (ObjCInterfaceDecl *SDecl = ClassDecl->getSuperClass())
+    while (SDecl) {
+      for (ObjCInterfaceDecl::all_protocol_iterator
+           PI = SDecl->all_referenced_protocol_begin(),
+           E = SDecl->all_referenced_protocol_end(); PI != E; ++PI) {
+        if (const ObjCProtocolDecl *PDecl = (*PI)->getDefinition())
+          PDecl->collectInheritedProtocolProperties(Property, PropMap);
+      }
+      SDecl = SDecl->getSuperClass();
+    }
+  
+  if (PropMap.empty())
+    return;
+  
+  QualType RHSType = S.Context.getCanonicalType(Property->getType());
+  bool FirsTime = true;
+  for (ObjCInterfaceDecl::ProtocolPropertyMap::iterator
+       I = PropMap.begin(), E = PropMap.end(); I != E; I++) {
+    ObjCPropertyDecl *Prop = I->second;
+    QualType LHSType = S.Context.getCanonicalType(Prop->getType());
+    if (!S.Context.propertyTypesAreCompatible(LHSType, RHSType)) {
+      bool IncompatibleObjC = false;
+      QualType ConvertedType;
+      if (!S.isObjCPointerConversion(RHSType, LHSType, ConvertedType, IncompatibleObjC)
+          || IncompatibleObjC) {
+        if (FirsTime) {
+          S.Diag(Property->getLocation(), diag::warn_protocol_property_mismatch)
+            << Property->getType();
+          FirsTime = false;
+        }
+        S.Diag(Prop->getLocation(), diag::note_protocol_property_declare)
+          << Prop->getType();
+      }
+    }
+  }
+  if (!FirsTime && AtLoc.isValid())
+    S.Diag(AtLoc, diag::note_property_synthesize);
+}
+
 /// DiagnoseClassAndClassExtPropertyMismatch - diagnose inconsistant property
 /// attribute declared in primary class and attributes overridden in any of its
 /// class extensions.
@@ -879,6 +931,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
         }
       }
     }
+    if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
+      DiagnosePropertyMismatchDeclInProtocols(*this, AtLoc, IDecl, property);
     
     DiagnoseClassAndClassExtPropertyMismatch(*this, IDecl, property);
         
diff --git a/test/SemaObjC/property-ambiguous-synthesis.m b/test/SemaObjC/property-ambiguous-synthesis.m
new file mode 100644 (file)
index 0000000..98f5945
--- /dev/null
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1  -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://13075400
+
+@protocol FooAsID
+@property (copy) id foo; // expected-note 2 {{it could also be property of type 'id' declared here}} \\
+                        // expected-warning {{property of type 'id' was selected for synthesis}}
+@end
+
+@protocol FooAsDouble
+@property double foo; // expected-warning 2 {{property of type 'double' was selected for synthesis}} \
+                     // expected-note {{it could also be property of type 'double' declared here}}
+@end
+
+@protocol FooAsShort
+@property short foo; // expected-note {{it could also be property of type 'short' declared here}}
+@end
+
+@interface NSObject @end
+
+@interface AnObject : NSObject<FooAsDouble,FooAsID>
+@end
+
+@interface Sub : AnObject
+@end
+
+@implementation Sub
+@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+@end
+
+
+@interface AnotherObject : NSObject<FooAsDouble, FooAsID,FooAsDouble, FooAsID, FooAsDouble,FooAsID>
+@end
+
+@implementation AnotherObject
+@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+@end
+
+
+@interface YetAnotherObject : NSObject<FooAsID,FooAsShort, FooAsDouble,FooAsID, FooAsShort>
+@end
+
+@implementation YetAnotherObject
+@synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+@end
+
+double func(YetAnotherObject *object) {
+  return [object foo]; // expected-error {{returning 'id' from a function with incompatible result type 'double'}}
+}