]> granicus.if.org Git - clang/commitdiff
New AST node to access "implicit" setter/getter using property dor syntax.
authorFariborz Jahanian <fjahanian@apple.com>
Sat, 22 Nov 2008 18:39:36 +0000 (18:39 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Sat, 22 Nov 2008 18:39:36 +0000 (18:39 +0000)
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

13 files changed:
include/clang/AST/Expr.h
include/clang/AST/ExprObjC.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
lib/AST/Expr.cpp
lib/AST/StmtDumper.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtSerialization.cpp
lib/Analysis/CheckObjCDealloc.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaExpr.cpp

index 030a399e1d4aa177aa48bad4662a1eb576755f90..e7aab276a43387a537fd25c437cad4c80c53c45f 100644 (file)
@@ -103,7 +103,8 @@ public:
     MLV_IncompleteType,
     MLV_ConstQualified,
     MLV_ArrayType,
-    MLV_NotBlockQualified
+    MLV_NotBlockQualified,
+    MLV_ReadonlyProperty
   };
   isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx) const;
   
index 7f519a861c6c362585cd4ecd3e773b98b7f2c474..9cb9af52495d6a898ac0fc777566cb6e957b291f 100644 (file)
@@ -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;
index 6d3c172c96b731573d07e8584789fad5eeaee9cd..06e5419d9e5a9dd9fe6797e99fee443db06a302e 100644 (file)
@@ -115,6 +115,7 @@ STMT(ObjCSelectorExpr     , Expr)
 STMT(ObjCProtocolExpr     , Expr)
 STMT(ObjCIvarRefExpr      , Expr)
 STMT(ObjCPropertyRefExpr  , Expr)
+STMT(ObjCKVCRefExpr       , Expr)
 STMT(ObjCSuperExpr        , Expr)
 
 // Clang Extensions.
index 552cb75a0ec064a4d84195046ed0ba953d446c87..9e55eb37af6dcfc09b507df37800b6e640b56b86 100644 (file)
@@ -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'")
index e6a7b4114a119f58d09f1d80ca567b1f08628656..6a15ea68a52fb9f36ee9f4e28f5b65ffd1d571ba 100644 (file)
@@ -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(); }
index a992efba50ae84aa8019f9a76d8d4eba4ce4bad5..04ae2cdb19a8bf309814f6adf04109a5f9d715d0 100644 (file)
@@ -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) {
index cb5c44f9269f05550e97838ba6376e96329ad18f..94cfae9d4c9af4b083a10676bb4130c1fd0a70b9 100644 (file)
@@ -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:
index 8faef8bb6650762a3644c1711e9dfc755df97d4d..2d6f3c7e8a31d6c4a9146216e07f41834e536b8f 100644 (file)
@@ -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;
 }
 
index 8628ff122cf99b281515843b7b54993fdc6f3e6e..6fba9aeea9a484f67cfafe418ab73a37b40b9256 100644 (file)
@@ -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;
   
index 28f93c00f128f7663312414094fa0d0083fd11f4..66f3feb8cc4292b88a10cb98303264231005e445 100644 (file)
@@ -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()));
index 4739efa63df30ff14b9fcbdca4d9b20e68d57041..226ec9917c3b9762f41f5bbef2a012fffa5d4050 100644 (file)
@@ -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, 
index 85c500b95e21baacc763a8ae37804fe30b67b8f0..56a6e16e9eb5dfd0bf476327c0304651628bd26d 100644 (file)
@@ -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);
 
 
index 96b229d2a42a588a3df91423809477f38e6402cf..8474548740b0446355b1d7f0842d760951128e85 100644 (file)
@@ -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)