ObjC class properties: add diagnostics for unimplemented class properties.

rdar://24711047

llvm-svn: 266146
This commit is contained in:
Manman Ren 2016-04-12 23:01:55 +00:00
parent 0a385532dd
commit 16a7d637dd
4 changed files with 76 additions and 45 deletions

View File

@ -5649,6 +5649,16 @@ def note_parameter_here : Note<
def note_method_return_type_change : Note<
"compiler has implicitly changed method %0 return type">;
def warn_impl_required_for_class_property : Warning<
"class property %0 requires method %1 to be defined - "
"use @dynamic or provide a method implementation "
"in this class implementation">,
InGroup<ObjCPropertyImpl>;
def warn_impl_required_in_category_for_class_property : Warning<
"class property %0 requires method %1 to be defined - "
"use @dynamic or provide a method implementation in this category">,
InGroup<ObjCPropertyImpl>;
// C++ casts
// These messages adhere to the TryCast pattern: %0 is an int specifying the
// cast type, %1 is the source type, %2 is the destination type.

View File

@ -1530,37 +1530,50 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those in its super class.
static void CollectImmediateProperties(ObjCContainerDecl *CDecl,
ObjCContainerDecl::PropertyMap &PropMap,
ObjCContainerDecl::PropertyMap &SuperPropMap,
bool IncludeProtocols = true) {
static void
CollectImmediateProperties(ObjCContainerDecl *CDecl,
ObjCContainerDecl::PropertyMap &PropMap,
ObjCContainerDecl::PropertyMap &SuperPropMap,
bool CollectClassPropsOnly = false,
bool IncludeProtocols = true) {
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (auto *Prop : IDecl->properties())
for (auto *Prop : IDecl->properties()) {
if (CollectClassPropsOnly && !Prop->isClassProperty())
continue;
PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
Prop;
}
// Collect the properties from visible extensions.
for (auto *Ext : IDecl->visible_extensions())
CollectImmediateProperties(Ext, PropMap, SuperPropMap, IncludeProtocols);
CollectImmediateProperties(Ext, PropMap, SuperPropMap,
CollectClassPropsOnly, IncludeProtocols);
if (IncludeProtocols) {
// Scan through class's protocols.
for (auto *PI : IDecl->all_referenced_protocols())
CollectImmediateProperties(PI, PropMap, SuperPropMap);
CollectImmediateProperties(PI, PropMap, SuperPropMap,
CollectClassPropsOnly);
}
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (auto *Prop : CATDecl->properties())
for (auto *Prop : CATDecl->properties()) {
if (CollectClassPropsOnly && !Prop->isClassProperty())
continue;
PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
Prop;
}
if (IncludeProtocols) {
// Scan through class's protocols.
for (auto *PI : CATDecl->protocols())
CollectImmediateProperties(PI, PropMap, SuperPropMap);
CollectImmediateProperties(PI, PropMap, SuperPropMap,
CollectClassPropsOnly);
}
}
else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
for (auto *Prop : PDecl->properties()) {
if (CollectClassPropsOnly && !Prop->isClassProperty())
continue;
ObjCPropertyDecl *PropertyFromSuper =
SuperPropMap[std::make_pair(Prop->getIdentifier(),
Prop->isClassProperty())];
@ -1575,9 +1588,10 @@ static void CollectImmediateProperties(ObjCContainerDecl *CDecl,
PropEntry = Prop;
}
}
// scan through protocol's protocols.
// Scan through protocol's protocols.
for (auto *PI : PDecl->protocols())
CollectImmediateProperties(PI, PropMap, SuperPropMap);
CollectImmediateProperties(PI, PropMap, SuperPropMap,
CollectClassPropsOnly);
}
}
@ -1765,19 +1779,22 @@ static void DiagnoseUnimplementedAccessor(Sema &S,
(PrimaryClass == nullptr ||
!PrimaryClass->lookupPropertyAccessor(Method, C,
Prop->isClassProperty()))) {
S.Diag(IMPDecl->getLocation(),
isa<ObjCCategoryDecl>(CDecl) ?
diag::warn_setter_getter_impl_required_in_category :
diag::warn_setter_getter_impl_required)
<< Prop->getDeclName() << Method;
S.Diag(Prop->getLocation(),
diag::note_property_declare);
if (S.LangOpts.ObjCDefaultSynthProperties &&
S.LangOpts.ObjCRuntime.isNonFragile())
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
}
unsigned diag =
isa<ObjCCategoryDecl>(CDecl)
? (Prop->isClassProperty()
? diag::warn_impl_required_in_category_for_class_property
: diag::warn_setter_getter_impl_required_in_category)
: (Prop->isClassProperty()
? diag::warn_impl_required_for_class_property
: diag::warn_setter_getter_impl_required);
S.Diag(IMPDecl->getLocation(), diag) << Prop->getDeclName() << Method;
S.Diag(Prop->getLocation(), diag::note_property_declare);
if (S.LangOpts.ObjCDefaultSynthProperties &&
S.LangOpts.ObjCRuntime.isNonFragile())
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
}
}
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
@ -1786,25 +1803,27 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl::PropertyMap PropMap;
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
if (!SynthesizeProperties) {
ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
// Gather properties which need not be implemented in this class
// or category.
if (!IDecl)
if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For categories, no need to implement properties declared in
// its primary class (and its super classes) if property is
// declared in one of those containers.
if ((IDecl = C->getClassInterface())) {
ObjCInterfaceDecl::PropertyDeclOrder PO;
IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
}
// Since we don't synthesize class properties, we should emit diagnose even
// if SynthesizeProperties is true.
ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
// Gather properties which need not be implemented in this class
// or category.
if (!IDecl)
if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For categories, no need to implement properties declared in
// its primary class (and its super classes) if property is
// declared in one of those containers.
if ((IDecl = C->getClassInterface())) {
ObjCInterfaceDecl::PropertyDeclOrder PO;
IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
}
if (IDecl)
CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
}
if (IDecl)
CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap);
}
// When SynthesizeProperties is true, we only check class properties.
CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap,
SynthesizeProperties/*CollectClassPropsOnly*/);
// Scan the @interface to see if any of the protocols it adopts
// require an explicit implementation, via attribute
@ -1826,6 +1845,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
LazyMap.reset(new ObjCContainerDecl::PropertyMap());
CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,
/* CollectClassPropsOnly */ false,
/* IncludeProtocols */ false);
}
// Add the properties of 'PDecl' to the list of properties that
@ -1868,7 +1888,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
for (ObjCContainerDecl::PropertyMap::iterator
P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
ObjCPropertyDecl *Prop = P->second;
// Is there a matching propery synthesize/dynamic?
// Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop) ||

View File

@ -15,7 +15,6 @@
@property int z;
@property(readonly) int ro, ro2;
@property (class) int c;
@property (class) int c2;
@end
@implementation A

View File

@ -18,11 +18,13 @@
@property int z;
@property(readonly) int ro, ro2;
@property (class) int c;
@property (class) int c2;
@property (class) int c2; // expected-note {{property declared here}} \
// expected-note {{property declared here}}
@property (class) int x;
@end
@implementation A
@implementation A // expected-warning {{class property 'c2' requires method 'c2' to be defined}} \
// expected-warning {{class property 'c2' requires method 'setC2:' to be defined}}
@dynamic x; // refers to the instance property
@dynamic (class) x; // refers to the class property
@synthesize z, c2; // expected-error {{@synthesize not allowed on a class property 'c2'}}