r182316 - Objective-C [qoi]: When an class conforms to multiple
Fariborz Jahanian
fjahanian at apple.com
Mon May 20 14:20:25 PDT 2013
Author: fjahanian
Date: Mon May 20 16:20:24 2013
New Revision: 182316
URL: http://llvm.org/viewvc/llvm-project?rev=182316&view=rev
Log:
Objective-C [qoi]: When an class conforms to multiple
protocols that declare the same property of incompatible
types, issue a warning when class implementation synthesizes
the property. // rdar://13075400
Added:
cfe/trunk/test/SemaObjC/property-ambiguous-synthesis.m
Modified:
cfe/trunk/include/clang/AST/DeclObjC.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/DeclObjC.cpp
cfe/trunk/lib/Sema/SemaObjCProperty.cpp
Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=182316&r1=182315&r2=182316&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Mon May 20 16:20:24 2013
@@ -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; }
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=182316&r1=182315&r2=182316&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon May 20 16:20:24 2013
@@ -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<
Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=182316&r1=182315&r2=182316&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Mon May 20 16:20:24 2013
@@ -1493,6 +1493,30 @@ void ObjCProtocolDecl::collectProperties
}
}
+
+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
Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=182316&r1=182315&r2=182316&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Mon May 20 16:20:24 2013
@@ -714,6 +714,58 @@ static void setImpliedPropertyAttributeF
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
}
}
}
+ if (Synthesize && isa<ObjCProtocolDecl>(property->getDeclContext()))
+ DiagnosePropertyMismatchDeclInProtocols(*this, AtLoc, IDecl, property);
DiagnoseClassAndClassExtPropertyMismatch(*this, IDecl, property);
Added: cfe/trunk/test/SemaObjC/property-ambiguous-synthesis.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-ambiguous-synthesis.m?rev=182316&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/property-ambiguous-synthesis.m (added)
+++ cfe/trunk/test/SemaObjC/property-ambiguous-synthesis.m Mon May 20 16:20:24 2013
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://13075400
+
+ at protocol FooAsID
+ at 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}}
+ at end
+
+ at protocol FooAsDouble
+ at 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}}
+ at end
+
+ at protocol FooAsShort
+ at property short foo; // expected-note {{it could also be property of type 'short' declared here}}
+ at end
+
+ at interface NSObject @end
+
+ at interface AnObject : NSObject<FooAsDouble,FooAsID>
+ at end
+
+ at interface Sub : AnObject
+ at end
+
+ at implementation Sub
+ at synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+ at end
+
+
+ at interface AnotherObject : NSObject<FooAsDouble, FooAsID,FooAsDouble, FooAsID, FooAsDouble,FooAsID>
+ at end
+
+ at implementation AnotherObject
+ at synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+ at end
+
+
+ at interface YetAnotherObject : NSObject<FooAsID,FooAsShort, FooAsDouble,FooAsID, FooAsShort>
+ at end
+
+ at implementation YetAnotherObject
+ at synthesize foo=_MyFooIvar; // expected-note {{property synthesized here}}
+ at end
+
+double func(YetAnotherObject *object) {
+ return [object foo]; // expected-error {{returning 'id' from a function with incompatible result type 'double'}}
+}
More information about the cfe-commits
mailing list