forked from OSchip/llvm-project
ObjC class properties: add diagnostics for unimplemented class properties.
rdar://24711047 llvm-svn: 266146
This commit is contained in:
parent
0a385532dd
commit
16a7d637dd
|
@ -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.
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
@property int z;
|
||||
@property(readonly) int ro, ro2;
|
||||
@property (class) int c;
|
||||
@property (class) int c2;
|
||||
@end
|
||||
|
||||
@implementation A
|
||||
|
|
|
@ -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'}}
|
||||
|
|
Loading…
Reference in New Issue