]> granicus.if.org Git - clang/commitdiff
Support for implicit property assignment. Error assigning to
authorFariborz Jahanian <fjahanian@apple.com>
Sat, 22 Nov 2008 20:25:50 +0000 (20:25 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Sat, 22 Nov 2008 20:25:50 +0000 (20:25 +0000)
'implicit' property with no 'setter'.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59878 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
include/clang/AST/ExprObjC.h
include/clang/Basic/DiagnosticKinds.def
lib/AST/Expr.cpp
lib/AST/StmtSerialization.cpp
lib/Sema/SemaExpr.cpp
test/SemaObjC/property-error-readonly-assign.m

index e7aab276a43387a537fd25c437cad4c80c53c45f..387ff7111b03327ddab57f5953efa85ef14ec27e 100644 (file)
@@ -104,7 +104,8 @@ public:
     MLV_ConstQualified,
     MLV_ArrayType,
     MLV_NotBlockQualified,
-    MLV_ReadonlyProperty
+    MLV_ReadonlyProperty,
+    MLV_NoSetterProperty
   };
   isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx) const;
   
index 9cb9af52495d6a898ac0fc777566cb6e957b291f..25a3b5fcec85efa16bf76be76ed56ed259ed5b70 100644 (file)
@@ -251,17 +251,15 @@ private:
 public:
   ObjCKVCRefExpr(ObjCMethodDecl *getter,
                  QualType t, 
+                 ObjCMethodDecl *setter,
                  SourceLocation l, Expr *base)
-    : Expr(ObjCKVCRefExprClass, t), Setter(0), 
+    : Expr(ObjCKVCRefExprClass, t), Setter(setter),
       Getter(getter), Loc(l), Base(base) {
     }
   
   ObjCMethodDecl *getGetterMethod() const {
       return Getter;
   }
-  void setSetterMethod(ObjCMethodDecl *setter) {
-    Setter = setter;
-  }
   ObjCMethodDecl *getSetterMethod() const {
     return Setter;
   }
index 9e55eb37af6dcfc09b507df37800b6e640b56b86..48cdb1f85afac008ab1a514e64e633fb2c3ba305 100644 (file)
@@ -543,6 +543,9 @@ 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(error_nosetter_property_assignment, ERROR,
+     "setter method is needed to assign to object using property"
+     " assignment syntax")
 DIAG(warn_readonly_property, WARNING,
      "attribute 'readonly' of property '%0' restricts attribute "
      "'readwrite' of property inherited from '%1'")
index 6a15ea68a52fb9f36ee9f4e28f5b65ffd1d571ba..0ff345a1a8d957227c90db2ee03b2f1ed60d427b 100644 (file)
@@ -557,6 +557,12 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx) const {
         return MLV_ReadonlyProperty;
     }
   }
+  // Assigning to an 'implicit' property?
+  if (getStmtClass() == ObjCKVCRefExprClass) {
+    const ObjCKVCRefExpr* KVCExpr = cast<ObjCKVCRefExpr>(this);
+    if (KVCExpr->getSetterMethod() == 0)
+      return MLV_NoSetterProperty;
+  }
   return MLV_Valid;    
 }
 
index 2d6f3c7e8a31d6c4a9146216e07f41834e536b8f..8bf70396856abaddb5ac9387a7550fb60043683a 100644 (file)
@@ -1173,7 +1173,7 @@ 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);
+  ObjCKVCRefExpr* dr = new ObjCKVCRefExpr(NULL,T,NULL,Loc,0);
   D.ReadPtr(dr->Setter,false);
   D.ReadPtr(dr->Getter,false);
   return dr;
index 8474548740b0446355b1d7f0842d760951128e85..ef3ead4fa2c34c47dfbdde87c8447e9d4425bfac 100644 (file)
@@ -1090,6 +1090,20 @@ 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,
@@ -1198,9 +1212,30 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
     }
     if (Getter) {
       // If we found a getter then this may be a valid dot-reference, we
-      // will look for the matching setter, if it is needed. But we don't
-      // know this yet.
-      return new ObjCKVCRefExpr(Getter, Getter->getResultType(), 
+      // will look for the matching setter, in case it is needed.
+      IdentifierInfo *SetterName = constructSetterName(PP.getIdentifierTable(),
+                                                       &Member);
+      Selector SetterSel = PP.getSelectorTable().getUnarySelector(SetterName);
+      ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
+      if (!Setter) {
+        // If this reference is in an @implementation, also check for 'private' 
+        // methods.
+        if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
+          if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
+            if (ObjCImplementationDecl *ImpDecl = 
+                  ObjCImplementations[ClassDecl->getIdentifier()])
+              Setter = ImpDecl->getInstanceMethod(SetterSel);
+      }
+      // Look through local category implementations associated with the class.
+      if (!Setter) {
+        for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) {
+          if (ObjCCategoryImpls[i]->getClassInterface() == IFace)
+            Setter = ObjCCategoryImpls[i]->getInstanceMethod(SetterSel);
+        }
+      }
+      
+      // FIXME: we must check that the setter has property type.      
+      return new ObjCKVCRefExpr(Getter, Getter->getResultType(), Setter,
                                 MemberLoc, BaseExpr);
     }
   }
@@ -2522,6 +2557,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
   case Expr::MLV_ReadonlyProperty:
     Diag = diag::error_readonly_property_assignment;
     break;
+  case Expr::MLV_NoSetterProperty:
+    Diag = diag::error_nosetter_property_assignment;
+    break;
   }
 
   if (NeedType)
index 0a49ee480950df057e9c2a9cd8e4752a74889aa7..673dc25aa8120dc6254c0c9f978c61eda42f6593 100644 (file)
@@ -6,8 +6,16 @@
 @property int ok;
 @end
 
-void f0(A *a) {
+@interface B
+ -(void) setOk:(int)arg;
+ -(int) x;
+ -(int) ok;
+@end
+
+void f0(A *a, B* b) {
   a.x = 10;  // expected-error {{assigning to property with 'readonly' attribute not allowed}}
   a.ok = 20;
+  b.x = 10;  // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+  b.ok = 20;
 }