MLV_IncompleteType,
MLV_ConstQualified,
MLV_ArrayType,
- MLV_NotBlockQualified
+ MLV_NotBlockQualified,
+ MLV_ReadonlyProperty
};
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx) const;
};
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
-/// property. Note that dot-syntax can also be used to access
-/// "implicit" properties (i.e. methods following the property naming
-/// convention). Additionally, sema is not yet smart enough to know if
-/// a property reference is to a getter or a setter, so the expr must
-/// have access to both methods.
+/// property.
///
-// FIXME: Consider splitting these into separate Expr classes.
class ObjCPropertyRefExpr : public Expr {
-public:
- enum Kind {
- PropertyRef, // This expressions references a declared property.
- MethodRef // This expressions references methods.
- };
-
private:
- // A dot-syntax reference via methods must always have a getter. We
- // avoid storing the kind explicitly by relying on this invariant
- // and assuming this is a MethodRef iff Getter is non-null. Setter
- // can be null in situations which access a read-only property.
- union {
- ObjCPropertyDecl *AsProperty;
- struct {
- ObjCMethodDecl *Setter;
- ObjCMethodDecl *Getter;
- } AsMethod;
- } Referent;
+ ObjCPropertyDecl *AsProperty;
SourceLocation Loc;
Stmt *Base;
public:
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
SourceLocation l, Expr *base)
- : Expr(ObjCPropertyRefExprClass, t), Loc(l), Base(base) {
- Referent.AsMethod.Getter = Referent.AsMethod.Setter = NULL;
- Referent.AsProperty = PD;
- }
- ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
- QualType t,
- SourceLocation l, Expr *base)
- : Expr(ObjCPropertyRefExprClass, t), Loc(l), Base(base) {
- Referent.AsMethod.Getter = Getter;
- Referent.AsMethod.Setter = Setter;
- }
-
- Kind getKind() const {
- return Referent.AsMethod.Getter ? MethodRef : PropertyRef;
+ : Expr(ObjCPropertyRefExprClass, t), AsProperty(PD), Loc(l), Base(base) {
}
-
ObjCPropertyDecl *getProperty() const {
- assert(getKind() == PropertyRef &&
- "Cannot get property from an ObjCPropertyRefExpr using methods");
- return Referent.AsProperty;
- }
- ObjCMethodDecl *getGetterMethod() const {
- assert(getKind() == MethodRef &&
- "Cannot get method from an ObjCPropertyRefExpr using a property");
- return Referent.AsMethod.Getter;
- }
- ObjCMethodDecl *getSetterMethod() const {
- assert(getKind() == MethodRef &&
- "Cannot get method from an ObjCPropertyRefExpr using a property");
- return Referent.AsMethod.Setter;
+ return AsProperty;
}
virtual SourceRange getSourceRange() const {
static ObjCPropertyRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
+/// ObjCKVCRefExpr - A dot-syntax expression to access "implicit" properties
+/// (i.e. methods following the property naming convention). KVC stands for
+/// Key Value Encoding, a generic concept for accessing or setting a 'Key'
+/// value for an object.
+///
+
+class ObjCKVCRefExpr : public Expr {
+private:
+
+ ObjCMethodDecl *Setter;
+ ObjCMethodDecl *Getter;
+ SourceLocation Loc;
+ Stmt *Base;
+
+public:
+ ObjCKVCRefExpr(ObjCMethodDecl *getter,
+ QualType t,
+ SourceLocation l, Expr *base)
+ : Expr(ObjCKVCRefExprClass, t), Setter(0),
+ Getter(getter), Loc(l), Base(base) {
+ }
+
+ ObjCMethodDecl *getGetterMethod() const {
+ return Getter;
+ }
+ void setSetterMethod(ObjCMethodDecl *setter) {
+ Setter = setter;
+ }
+ ObjCMethodDecl *getSetterMethod() const {
+ return Setter;
+ }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(getBase()->getLocStart(), Loc);
+ }
+ const Expr *getBase() const { return cast<Expr>(Base); }
+ Expr *getBase() { return cast<Expr>(Base); }
+ void setBase(Expr * base) { Base = base; }
+
+ SourceLocation getLocation() const { return Loc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ObjCKVCRefExprClass;
+ }
+ static bool classof(const ObjCKVCRefExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+
+ virtual void EmitImpl(llvm::Serializer& S) const;
+ static ObjCKVCRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
class ObjCMessageExpr : public Expr {
// SubExprs - The receiver and arguments of the message expression.
Stmt **SubExprs;
STMT(ObjCProtocolExpr , Expr)
STMT(ObjCIvarRefExpr , Expr)
STMT(ObjCPropertyRefExpr , Expr)
+STMT(ObjCKVCRefExpr , Expr)
STMT(ObjCSuperExpr , Expr)
// Clang Extensions.
"@synthesize not allowed in a category's implementation")
DIAG(error_property_ivar_type, ERROR,
"type of property '%0' does not match type of ivar '%1'")
+DIAG(error_readonly_property_assignment, ERROR,
+ "assigning to property with 'readonly' attribute not allowed")
DIAG(warn_readonly_property, WARNING,
"attribute 'readonly' of property '%0' restricts attribute "
"'readwrite' of property inherited from '%1'")
return LV_Valid;
case ObjCPropertyRefExprClass: // FIXME: check if read-only property.
return LV_Valid;
+ case ObjCKVCRefExprClass: // FIXME: check if read-only property.
+ return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
case VAArgExprClass:
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()) {
+ ObjCPropertyDecl::PropertyAttributeKind Pkind =
+ PDecl->getPropertyAttributes();
+ if (Pkind == ObjCPropertyDecl::OBJC_PR_readonly)
+ return MLV_ReadonlyProperty;
+ }
+ }
return MLV_Valid;
}
Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; }
Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; }
+// ObjCKVCRefExpr
+Stmt::child_iterator ObjCKVCRefExpr::child_begin() { return &Base; }
+Stmt::child_iterator ObjCKVCRefExpr::child_end() { return &Base+1; }
+
// ObjCSuperExpr
Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); }
Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); }
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
+ void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
void VisitObjCSuperExpr(ObjCSuperExpr *Node);
};
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
DumpExpr(Node);
- if (Node->getKind() == ObjCPropertyRefExpr::MethodRef) {
- ObjCMethodDecl *Getter = Node->getGetterMethod();
- ObjCMethodDecl *Setter = Node->getSetterMethod();
- fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"",
- Getter->getSelector().getName().c_str(),
- Setter ? Setter->getSelector().getName().c_str() : "(null)");
- } else {
- fprintf(F, " Kind=PropertyRef Property=\"%s\"",
- Node->getProperty()->getIdentifierName());
- }
+ fprintf(F, " Kind=PropertyRef Property=\"%s\"",
+ Node->getProperty()->getIdentifierName());
+}
+
+void StmtDumper::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+ DumpExpr(Node);
+
+ ObjCMethodDecl *Getter = Node->getGetterMethod();
+ ObjCMethodDecl *Setter = Node->getSetterMethod();
+ fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"",
+ Getter->getSelector().getName().c_str(),
+ Setter ? Setter->getSelector().getName().c_str() : "(null)");
}
void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
// FIXME: OS << Node->getDecl()->getName();
}
+void StmtPrinter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) {
+ if (Node->getBase()) {
+ PrintExpr(Node->getBase());
+ OS << ".";
+ }
+ // FIXME: Setter/Getter names
+}
+
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
switch (Node->getIdentType()) {
default:
void ObjCPropertyRefExpr::EmitImpl(Serializer& S) const {
S.Emit(Loc);
S.Emit(getType());
- unsigned Kind = getKind();
- S.Emit(Kind);
- if (Kind == PropertyRef) {
- S.EmitPtr(getProperty());
- } else {
- S.EmitPtr(getGetterMethod());
- S.EmitPtr(getSetterMethod());
- }
+ S.EmitPtr(getProperty());
+}
+
+void ObjCKVCRefExpr::EmitImpl(Serializer& S) const {
+ S.Emit(Loc);
+ S.Emit(getType());
+ S.EmitPtr(getGetterMethod());
+ S.EmitPtr(getSetterMethod());
}
ObjCPropertyRefExpr* ObjCPropertyRefExpr::CreateImpl(Deserializer& D,
SourceLocation Loc = SourceLocation::ReadVal(D);
QualType T = QualType::ReadVal(D);
ObjCPropertyRefExpr* dr = new ObjCPropertyRefExpr(NULL,T,Loc,0);
- unsigned Kind = D.ReadInt();
- if (Kind == PropertyRef) {
- D.ReadPtr(dr->Referent.AsProperty,false);
- } else {
- D.ReadPtr(dr->Referent.AsMethod.Setter,false);
- D.ReadPtr(dr->Referent.AsMethod.Getter,false);
- }
+ D.ReadPtr(dr->AsProperty,false);
+ return dr;
+}
+
+ObjCKVCRefExpr* ObjCKVCRefExpr::CreateImpl(Deserializer& D,
+ ASTContext& C) {
+ SourceLocation Loc = SourceLocation::ReadVal(D);
+ QualType T = QualType::ReadVal(D);
+ ObjCKVCRefExpr* dr = new ObjCKVCRefExpr(NULL,T,Loc,0);
+ D.ReadPtr(dr->Setter,false);
+ D.ReadPtr(dr->Getter,false);
return dr;
}
if (BO->isAssignmentOp())
if(ObjCPropertyRefExpr* PRE =
dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
- if(PRE->getKind() == ObjCPropertyRefExpr::PropertyRef &&
- PRE->getProperty() == PD)
+ if(PRE->getProperty() == PD)
if(BO->getRHS()->isNullPointerConstant(Ctx))
return true;
EmitAggLoadOfLValue(E);
}
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E);
+ void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
void VisitConditionalOperator(const ConditionalOperator *CO);
void VisitInitListExpr(InitListExpr *E);
CGF.EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType());
}
+void AggExprEmitter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ RValue RV = CGF.EmitObjCPropertyGet(E);
+ assert(RV.isAggregate() && "Return value must be aggregate value!");
+
+ // If the result is ignored, don't copy from the value.
+ if (DestPtr == 0)
+ // FIXME: If the source is volatile, we must read from it.
+ return;
+
+ CGF.EmitAggregateCopy(DestPtr, RV.getAggregateAddr(), E->getType());
+}
+
void AggExprEmitter::VisitOverloadExpr(const OverloadExpr *E) {
RValue RV = CGF.EmitCallExpr(E->getFn(), E->arg_begin(),
E->arg_end(CGF.getContext()));
return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self");
}
-RValue CodeGenFunction::EmitObjCPropertyGet(const ObjCPropertyRefExpr *E) {
- // Determine getter selector.
- Selector S;
- if (E->getKind() == ObjCPropertyRefExpr::MethodRef) {
- S = E->getGetterMethod()->getSelector();
- } else {
- S = E->getProperty()->getGetterName();
- }
+RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) {
+ if (const ObjCPropertyRefExpr *E = dyn_cast<ObjCPropertyRefExpr>(Exp)) {
+ Selector S = E->getProperty()->getGetterName();
- return CGM.getObjCRuntime().
+ return CGM.getObjCRuntime().
GenerateMessageSend(*this, E->getType(), S,
EmitScalarExpr(E->getBase()),
false, CallArgList());
+ }
+ assert (0);
}
void CodeGenFunction::EmitObjCPropertySet(const ObjCPropertyRefExpr *E,
RValue Src) {
- Selector S;
- if (E->getKind() == ObjCPropertyRefExpr::MethodRef) {
- ObjCMethodDecl *Setter = E->getSetterMethod();
-
- if (Setter) {
- S = Setter->getSelector();
- } else {
- // FIXME: This should be diagnosed by sema.
- CGM.getDiags().Report(getContext().getFullLoc(E->getLocStart()),
- diag::err_typecheck_assign_const)
- << E->getSourceRange();
- return;
- }
- } else {
- S = E->getProperty()->getSetterName();
- }
-
+ Selector S = E->getProperty()->getSetterName();
CallArgList Args;
Args.push_back(std::make_pair(Src, E->getType()));
CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S,
llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
RValue EmitObjCMessageExpr(const ObjCMessageExpr *E);
- RValue EmitObjCPropertyGet(const ObjCPropertyRefExpr *E);
+ RValue EmitObjCPropertyGet(const Expr *E);
void EmitObjCPropertySet(const ObjCPropertyRefExpr *E, RValue Src);
return VT; // should never get here (a typedef type should always be found).
}
-/// constructSetterName - Return the setter name for the given
-/// identifier, i.e. "set" + Name where the initial character of Name
-/// has been capitalized.
-// FIXME: Merge with same routine in Parser. But where should this
-// live?
-static IdentifierInfo *constructSetterName(IdentifierTable &Idents,
- const IdentifierInfo *Name) {
- llvm::SmallString<100> SelectorName;
- SelectorName = "set";
- SelectorName.append(Name->getName(), Name->getName()+Name->getLength());
- SelectorName[3] = toupper(SelectorName[3]);
- return &Idents.get(&SelectorName[0], &SelectorName[SelectorName.size()]);
-}
-
Action::ExprResult Sema::
ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
tok::TokenKind OpKind, SourceLocation MemberLoc,
}
if (Getter) {
// If we found a getter then this may be a valid dot-reference, we
- // need to also look for the matching setter.
- IdentifierInfo *SetterName = constructSetterName(PP.getIdentifierTable(),
- &Member);
- Selector SetterSel = PP.getSelectorTable().getUnarySelector(SetterName);
- ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
-
- if (!Setter) {
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl =
- ObjCImplementations[ClassDecl->getIdentifier()])
- Setter = ImpDecl->getInstanceMethod(SetterSel);
- }
-
- // FIXME: There are some issues here. First, we are not
- // diagnosing accesses to read-only properties because we do not
- // know if this is a getter or setter yet. Second, we are
- // checking that the type of the setter matches the type we
- // expect.
- return new ObjCPropertyRefExpr(Getter, Setter, Getter->getResultType(),
- MemberLoc, BaseExpr);
+ // will look for the matching setter, if it is needed. But we don't
+ // know this yet.
+ return new ObjCKVCRefExpr(Getter, Getter->getResultType(),
+ MemberLoc, BaseExpr);
}
}
// Handle properties on qualified "id" protocols.
case Expr::MLV_NotBlockQualified:
Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
break;
+ case Expr::MLV_ReadonlyProperty:
+ Diag = diag::error_readonly_property_assignment;
+ break;
}
if (NeedType)