diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2008-11-22 18:39:36 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2008-11-22 18:39:36 +0000 |
commit | 5daf570d0ce027e18ed5f9d66e6b2a14a40b720d (patch) | |
tree | e554d26d58de550daf74b397b4e2e894927080df | |
parent | e4c452c4c7b9124fe94a96f559ff077d59cdf996 (diff) |
New AST node to access "implicit" setter/getter using property dor syntax.
Issuing diagnostics when assigning to read-only properties.
This is work in progress.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59874 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Expr.h | 3 | ||||
-rw-r--r-- | include/clang/AST/ExprObjC.h | 109 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 1 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 16 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 23 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 8 | ||||
-rw-r--r-- | lib/AST/StmtSerialization.cpp | 34 | ||||
-rw-r--r-- | lib/Analysis/CheckObjCDealloc.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 13 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 33 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 42 |
13 files changed, 148 insertions, 141 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 030a399e1d..e7aab276a4 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -103,7 +103,8 @@ public: MLV_IncompleteType, MLV_ConstQualified, MLV_ArrayType, - MLV_NotBlockQualified + MLV_NotBlockQualified, + MLV_ReadonlyProperty }; isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx) const; diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 7f519a861c..9cb9af5249 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -195,68 +195,21 @@ public: }; /// 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 { @@ -281,6 +234,60 @@ public: 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; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 6d3c172c96..06e5419d9e 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -115,6 +115,7 @@ STMT(ObjCSelectorExpr , Expr) STMT(ObjCProtocolExpr , Expr) STMT(ObjCIvarRefExpr , Expr) STMT(ObjCPropertyRefExpr , Expr) +STMT(ObjCKVCRefExpr , Expr) STMT(ObjCSuperExpr , Expr) // Clang Extensions. diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 552cb75a0e..9e55eb37af 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -541,6 +541,8 @@ DIAG(error_synthesize_category_decl, ERROR, "@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'") diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index e6a7b4114a..6a15ea68a5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -463,6 +463,8 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { 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: @@ -545,6 +547,16 @@ 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()) { + ObjCPropertyDecl::PropertyAttributeKind Pkind = + PDecl->getPropertyAttributes(); + if (Pkind == ObjCPropertyDecl::OBJC_PR_readonly) + return MLV_ReadonlyProperty; + } + } return MLV_Valid; } @@ -1353,6 +1365,10 @@ Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; } 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(); } diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index a992efba50..04ae2cdb19 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -139,6 +139,7 @@ namespace { void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); + void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); void VisitObjCSuperExpr(ObjCSuperExpr *Node); }; @@ -470,16 +471,18 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *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) { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index cb5c44f926..94cfae9d4c 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -502,6 +502,14 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *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: diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 8faef8bb66..2d6f3c7e8a 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -1150,14 +1150,14 @@ ObjCIvarRefExpr* ObjCIvarRefExpr::CreateImpl(Deserializer& D, ASTContext& C) { 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, @@ -1165,13 +1165,17 @@ 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; } diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp index 8628ff122c..6fba9aeea9 100644 --- a/lib/Analysis/CheckObjCDealloc.cpp +++ b/lib/Analysis/CheckObjCDealloc.cpp @@ -72,8 +72,7 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, 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; diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 28f93c00f1..66f3feb8cc 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -87,6 +87,7 @@ public: EmitAggLoadOfLValue(E); } void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E); + void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E); void VisitConditionalOperator(const ConditionalOperator *CO); void VisitInitListExpr(InitListExpr *E); @@ -170,6 +171,18 @@ void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *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())); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 4739efa63d..226ec9917c 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -278,40 +278,21 @@ llvm::Value *CodeGenFunction::LoadObjCSelf() { 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, diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 85c500b95e..56a6e16e9e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -524,7 +524,7 @@ public: 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); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 96b229d2a4..8474548740 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1090,20 +1090,6 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, 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, @@ -1212,27 +1198,10 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, } 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. @@ -2550,6 +2519,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { 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) |