forked from OSchip/llvm-project
Patch to supprt case of readonly property being
assigned to when it has user declared setter method defined in the class implementation (but no declaration in the class itself). llvm-svn: 62098
This commit is contained in:
parent
df5598444a
commit
8e1555c7c3
|
@ -405,7 +405,6 @@ public:
|
|||
|
||||
ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const;
|
||||
ObjCIvarDecl *FindIvarDeclaration(IdentifierInfo *IvarId) const;
|
||||
bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl) const;
|
||||
|
||||
typedef ObjCList<ObjCProtocolDecl>::iterator protocol_iterator;
|
||||
protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
|
||||
|
|
|
@ -251,34 +251,6 @@ void ObjCMethodDecl::setMethodParams(ParmVarDecl **NewParamInfo,
|
|||
}
|
||||
}
|
||||
|
||||
/// isPropertyReadonly - Return true if property is readonly, by searching
|
||||
/// for the property in the class and in its categories.
|
||||
///
|
||||
bool ObjCInterfaceDecl::isPropertyReadonly(ObjCPropertyDecl *PDecl) const
|
||||
{
|
||||
// Even if property is ready only, if interface has a user defined setter,
|
||||
// it is not considered read only.
|
||||
if (!PDecl->isReadOnly() || getInstanceMethod(PDecl->getSetterName()))
|
||||
return false;
|
||||
|
||||
// Main class has the property as 'readonly'. Must search
|
||||
// through the category list to see if the property's
|
||||
// attribute has been over-ridden to 'readwrite'.
|
||||
for (ObjCCategoryDecl *Category = getCategoryList();
|
||||
Category; Category = Category->getNextClassCategory()) {
|
||||
// Even if property is ready only, if a category has a user defined setter,
|
||||
// it is not considered read only.
|
||||
if (Category->getInstanceMethod(PDecl->getSetterName()))
|
||||
return false;
|
||||
ObjCPropertyDecl *P =
|
||||
Category->FindPropertyDeclaration(PDecl->getIdentifier());
|
||||
if (P && !P->isReadOnly())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// FindCategoryDeclaration - Finds category declaration in the list of
|
||||
/// categories for this class and returns it. Name of the category is passed
|
||||
/// in 'CategoryId'. If category not found, return 0;
|
||||
|
|
|
@ -604,19 +604,7 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx) const {
|
|||
if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
|
||||
return MLV_NotBlockQualified;
|
||||
}
|
||||
// Assigning to a readonly property?
|
||||
if (getStmtClass() == ObjCPropertyRefExprClass) {
|
||||
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(this);
|
||||
if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
|
||||
QualType BaseType = PropExpr->getBase()->getType();
|
||||
if (const PointerType *PTy = BaseType->getAsPointerType())
|
||||
if (const ObjCInterfaceType *IFTy =
|
||||
PTy->getPointeeType()->getAsObjCInterfaceType())
|
||||
if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
|
||||
if (IFace->isPropertyReadonly(PDecl))
|
||||
return MLV_ReadonlyProperty;
|
||||
}
|
||||
}
|
||||
|
||||
// Assigning to an 'implicit' property?
|
||||
else if (getStmtClass() == ObjCKVCRefExprClass) {
|
||||
const ObjCKVCRefExpr* KVCExpr = cast<ObjCKVCRefExpr>(this);
|
||||
|
|
|
@ -538,6 +538,9 @@ public:
|
|||
ObjCMethodDecl *IntfMethod);
|
||||
|
||||
NamespaceDecl *GetStdNamespace();
|
||||
|
||||
bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
|
||||
ObjCInterfaceDecl *IDecl) const;
|
||||
|
||||
/// CheckProtocolMethodDefs - This routine checks unimplemented
|
||||
/// methods declared in protocol, and those referenced by it.
|
||||
|
|
|
@ -699,6 +699,51 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
|
|||
}
|
||||
}
|
||||
|
||||
/// isPropertyReadonly - Return true if property is readonly, by searching
|
||||
/// for the property in the class and in its categories and implementations
|
||||
///
|
||||
bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
|
||||
ObjCInterfaceDecl *IDecl) const {
|
||||
// by far the most common case.
|
||||
if (!PDecl->isReadOnly())
|
||||
return false;
|
||||
// Even if property is ready only, if interface has a user defined setter,
|
||||
// it is not considered read only.
|
||||
if (IDecl->getInstanceMethod(PDecl->getSetterName()))
|
||||
return false;
|
||||
|
||||
// Main class has the property as 'readonly'. Must search
|
||||
// through the category list to see if the property's
|
||||
// attribute has been over-ridden to 'readwrite'.
|
||||
for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
|
||||
Category; Category = Category->getNextClassCategory()) {
|
||||
// Even if property is ready only, if a category has a user defined setter,
|
||||
// it is not considered read only.
|
||||
if (Category->getInstanceMethod(PDecl->getSetterName()))
|
||||
return false;
|
||||
ObjCPropertyDecl *P =
|
||||
Category->FindPropertyDeclaration(PDecl->getIdentifier());
|
||||
if (P && !P->isReadOnly())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Also, check for definition of a setter method in the implementation if
|
||||
// all else failed.
|
||||
if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) {
|
||||
if (ObjCImplementationDecl *IMD =
|
||||
dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) {
|
||||
if (IMD->getInstanceMethod(PDecl->getSetterName()))
|
||||
return false;
|
||||
}
|
||||
else if (ObjCCategoryImplDecl *CIMD =
|
||||
dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) {
|
||||
if (CIMD->getInstanceMethod(PDecl->getSetterName()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// FIXME: Type hierarchies in Objective-C can be deep. We could most
|
||||
/// likely improve the efficiency of selector lookups and type
|
||||
/// checking by associating with each protocol / interface / category
|
||||
|
|
|
@ -2920,10 +2920,33 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
|
|||
return InvalidOperands(Loc, lex, rex);
|
||||
}
|
||||
|
||||
/// IsReadonlyProperty - Verify that otherwise a valid l-value expression
|
||||
/// is a read-only property; return true if so. A readonly property expression
|
||||
/// depends on various declarations and thus must be treated specially.
|
||||
///
|
||||
static bool IsReadonlyProperty(Expr *E, Sema &S)
|
||||
{
|
||||
if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
|
||||
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
|
||||
if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) {
|
||||
QualType BaseType = PropExpr->getBase()->getType();
|
||||
if (const PointerType *PTy = BaseType->getAsPointerType())
|
||||
if (const ObjCInterfaceType *IFTy =
|
||||
PTy->getPointeeType()->getAsObjCInterfaceType())
|
||||
if (ObjCInterfaceDecl *IFace = IFTy->getDecl())
|
||||
if (S.isPropertyReadonly(PDecl, IFace))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
|
||||
/// emit an error and return true. If so, return false.
|
||||
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
|
||||
Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context);
|
||||
Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context);
|
||||
if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
|
||||
IsLV = Expr::MLV_ReadonlyProperty;
|
||||
if (IsLV == Expr::MLV_Valid)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -23,3 +23,39 @@
|
|||
self.z = 2; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
|
||||
}
|
||||
@end
|
||||
|
||||
// Test when property is 'readonly' but it has a setter in
|
||||
// its implementation only.
|
||||
@interface I1 {
|
||||
}
|
||||
@property(readonly) int identifier;
|
||||
@end
|
||||
|
||||
|
||||
@implementation I1
|
||||
@dynamic identifier;
|
||||
- (void)setIdentifier:(int)ident {}
|
||||
|
||||
- (id)initWithIdentifier:(int)Arg {
|
||||
self.identifier = 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// Also in a category implementation
|
||||
@interface I1(CAT)
|
||||
@property(readonly) int rprop;
|
||||
@end
|
||||
|
||||
|
||||
@implementation I1(CAT)
|
||||
@dynamic rprop;
|
||||
- (void)setRprop:(int)ident {}
|
||||
|
||||
- (id)initWithIdentifier:(int)Arg {
|
||||
self.rprop = 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
Loading…
Reference in New Issue