From e66f4e3e3ae9d7d11b0c302211066fad69228aba Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 3 Sep 2008 00:27:26 +0000 Subject: [PATCH] Fix ObjCPropertRefExpr to be able to encode all the information for uses which refer to methods not properties. - Not yet wired in Sema. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55681 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprObjC.h | 68 +++++++++++++++++++++++++++++++---- lib/AST/StmtDumper.cpp | 13 ++++--- lib/AST/StmtSerialization.cpp | 17 +++++++-- lib/CodeGen/CGObjC.cpp | 26 +++++++++----- lib/CodeGen/CGObjCMac.cpp | 5 ++- 5 files changed, 104 insertions(+), 25 deletions(-) diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index c572f5b56b..32c7996733 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -20,6 +20,8 @@ namespace clang { class IdentifierInfo; class ASTContext; + class ObjCMethodDecl; + class ObjCPropertyDecl; /// ObjCStringLiteral, used for Objective-C string literals /// i.e. @"foo". @@ -189,18 +191,70 @@ public: static ObjCIvarRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C); }; -/// ObjCPropertyRefExpr - A reference to an ObjC property. +/// 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. +/// +// FIXME: Consider splitting these into separate Expr classes. class ObjCPropertyRefExpr : public Expr { - class Decl *D; // an ObjCMethodDecl or ObjCPropertyDecl +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; SourceLocation Loc; Stmt *Base; public: - ObjCPropertyRefExpr(Decl *d, QualType t, SourceLocation l, Expr *base) : - Expr(ObjCPropertyRefExprClass, t), D(d), Loc(l), Base(base) {} - - Decl *getDecl() { return D; } - const Decl *getDecl() const { return D; } + 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; + } + + 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; + } virtual SourceRange getSourceRange() const { return SourceRange(getBase()->getLocStart(), Loc); diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index af19b61cd6..a0af132bc4 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -453,12 +453,15 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - - if (ObjCMethodDecl *MD = dyn_cast(Node->getDecl())) { - fprintf(F, " MethodDecl=\"%s\"", MD->getSelector().getName().c_str()); + + 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 { - ObjCPropertyDecl *PD = dyn_cast(Node->getDecl()); - fprintf(F, " PropertyDecl=\"%s\"", PD->getName()); + fprintf(F, " Kind=PropertyRef Property=\"%s\"", Node->getProperty()->getName()); } } diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 1c61b66512..23879ee63b 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -998,7 +998,14 @@ ObjCIvarRefExpr* ObjCIvarRefExpr::CreateImpl(Deserializer& D, ASTContext& C) { void ObjCPropertyRefExpr::EmitImpl(Serializer& S) const { S.Emit(Loc); S.Emit(getType()); - S.EmitPtr(getDecl()); + unsigned Kind = getKind(); + S.Emit(Kind); + if (Kind == PropertyRef) { + S.EmitPtr(getProperty()); + } else { + S.EmitPtr(getGetterMethod()); + S.EmitPtr(getSetterMethod()); + } } ObjCPropertyRefExpr* ObjCPropertyRefExpr::CreateImpl(Deserializer& D, @@ -1006,7 +1013,13 @@ ObjCPropertyRefExpr* ObjCPropertyRefExpr::CreateImpl(Deserializer& D, SourceLocation Loc = SourceLocation::ReadVal(D); QualType T = QualType::ReadVal(D); ObjCPropertyRefExpr* dr = new ObjCPropertyRefExpr(NULL,T,Loc,0); - D.ReadPtr(dr->D,false); + 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); + } return dr; } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 5376d0f3c7..af79b66106 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -16,6 +16,7 @@ #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/STLExtras.h" using namespace clang; @@ -231,10 +232,10 @@ llvm::Value *CodeGenFunction::LoadObjCSelf(void) { RValue CodeGenFunction::EmitObjCPropertyGet(const ObjCPropertyRefExpr *E) { // Determine getter selector. Selector S; - if (const ObjCMethodDecl *MD = dyn_cast(E->getDecl())) { - S = MD->getSelector(); + if (E->getKind() == ObjCPropertyRefExpr::MethodRef) { + S = E->getGetterMethod()->getSelector(); } else { - S = cast(E->getDecl())->getGetterName(); + S = E->getProperty()->getGetterName(); } return CGM.getObjCRuntime(). @@ -246,12 +247,21 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const ObjCPropertyRefExpr *E) { void CodeGenFunction::EmitObjCPropertySet(const ObjCPropertyRefExpr *E, RValue Src) { Selector S; - if (const ObjCPropertyDecl *PD = dyn_cast(E->getDecl())) { - S = PD->getSetterName(); + if (E->getKind() == ObjCPropertyRefExpr::MethodRef) { + ObjCMethodDecl *Setter = E->getSetterMethod(); + + if (Setter) { + S = Setter->getSelector(); + } else { + // FIXME: This should be diagnosed by sema. + SourceRange Range = E->getSourceRange(); + CGM.getDiags().Report(getContext().getFullLoc(E->getLocStart()), + diag::err_typecheck_assign_const, 0, 0, + &Range, 1); + return; + } } else { - // FIXME: How can we have a method decl here? - ErrorUnsupported(E, "Objective-C property setter call"); - return; + S = E->getProperty()->getSetterName(); } CallArgList Args; diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 798c9d3c4b..d1a1651277 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -499,9 +499,8 @@ CodeGen::RValue CGObjCMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); // FIXME: This is a hack, we are implicitly coordinating with - // EmitCallExprExt, which will move the return type to the first - // parameter and set the structure return flag. See - // getMessageSendFn(). + // EmitCall, which will move the return type to the first parameter + // and set the structure return flag. See getMessageSendFn(). const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(ResultType); return CGF.EmitCall(ObjCTypes.getMessageSendFn(IsSuper, ReturnTy), -- 2.40.0