[cfe-commits] r66465 - in /cfe/trunk: include/clang/AST/ExprObjC.h include/clang/Basic/IdentifierTable.h include/clang/Parse/Action.h lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseObjc.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaExprObjC.cpp test/Parser/check-objc2-syntax-1.m test/SemaObjC/newproperty-class-method-1.m

Steve Naroff snaroff at apple.com
Mon Mar 9 14:12:44 PDT 2009


Author: snaroff
Date: Mon Mar  9 16:12:44 2009
New Revision: 66465

URL: http://llvm.org/viewvc/llvm-project?rev=66465&view=rev
Log:
Implement property '.' notation on Factory/Class objects. Parser changes aren't very pretty:-(

This fixes <rdar://problem/6496506> Implement class setter/getter for properties.


Added:
    cfe/trunk/test/SemaObjC/newproperty-class-method-1.m
Modified:
    cfe/trunk/include/clang/AST/ExprObjC.h
    cfe/trunk/include/clang/Basic/IdentifierTable.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/test/Parser/check-objc2-syntax-1.m

Modified: cfe/trunk/include/clang/AST/ExprObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprObjC.h?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprObjC.h (original)
+++ cfe/trunk/include/clang/AST/ExprObjC.h Mon Mar  9 16:12:44 2009
@@ -205,7 +205,6 @@
   ObjCPropertyDecl *AsProperty;
   SourceLocation IdLoc;
   Stmt *Base;
-  
 public:
   ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, 
                       SourceLocation l, Expr *base)
@@ -249,7 +248,10 @@
   ObjCMethodDecl *Setter;
   ObjCMethodDecl *Getter;
   SourceLocation Loc;
+  // FIXME: Swizzle these into a single pointer.
   Stmt *Base;
+  ObjCInterfaceDecl *ClassProp;
+  SourceLocation ClassLoc;
     
 public:
   ObjCKVCRefExpr(ObjCMethodDecl *getter,
@@ -257,7 +259,14 @@
                  ObjCMethodDecl *setter,
                  SourceLocation l, Expr *base)
     : Expr(ObjCKVCRefExprClass, t), Setter(setter),
-      Getter(getter), Loc(l), Base(base) {
+      Getter(getter), Loc(l), Base(base), ClassProp(0), ClassLoc(SourceLocation()) {
+    }
+  ObjCKVCRefExpr(ObjCMethodDecl *getter,
+                 QualType t, 
+                 ObjCMethodDecl *setter,
+                 SourceLocation l, ObjCInterfaceDecl *C, SourceLocation CL)
+    : Expr(ObjCKVCRefExprClass, t), Setter(setter),
+      Getter(getter), Loc(l), Base(0), ClassProp(C), ClassLoc(CL) {
     }
   
   ObjCMethodDecl *getGetterMethod() const {
@@ -267,8 +276,10 @@
     return Setter;
   }
     
-  virtual SourceRange getSourceRange() const { 
-    return SourceRange(getBase()->getLocStart(), Loc); 
+  virtual SourceRange getSourceRange() const {
+    if (Base)
+      return SourceRange(getBase()->getLocStart(), Loc);
+    return SourceRange(ClassLoc, Loc);
   }
   const Expr *getBase() const { return cast<Expr>(Base); }
   Expr *getBase() { return cast<Expr>(Base); }

Modified: cfe/trunk/include/clang/Basic/IdentifierTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/IdentifierTable.h?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/IdentifierTable.h (original)
+++ cfe/trunk/include/clang/Basic/IdentifierTable.h Mon Mar  9 16:12:44 2009
@@ -428,7 +428,19 @@
   Selector getNullarySelector(IdentifierInfo *ID) {
     return Selector(ID, 0);
   }
-  
+
+  /// constructSetterName - Return the setter name for the given
+  /// identifier, i.e. "set" + Name where the initial character of Name
+  /// has been capitalized.
+  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()]);
+  }
+
   // Emit - Emit a SelectorTable to bitcode.
   void Emit(llvm::Serializer& S) const;
   

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Mar  9 16:12:44 2009
@@ -1362,6 +1362,14 @@
     return 0;
   }
                                      
+  virtual OwningExprResult ActOnClassPropertyRefExpr(
+    IdentifierInfo &receiverName,
+    IdentifierInfo &propertyName,
+    SourceLocation &receiverNameLoc,
+    SourceLocation &propertyNameLoc) {
+    return ExprEmpty();
+  }
+  
   // ActOnClassMessage - used for both unary and keyword messages.
   // ArgExprs is optional - if it is present, the number of expressions
   // is obtained from NumArgs.

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar  9 16:12:44 2009
@@ -1437,6 +1437,10 @@
   default: return false;
     
   case tok::identifier:   // foo::bar
+    // Unfortunate hack to support "Class.factoryMethod" notation.
+    if (getLang().ObjC1 && NextToken().is(tok::period))
+      return false;
+
     // Annotate typenames and C++ scope specifiers.  If we get one, just
     // recurse to handle whatever we get.
     if (TryAnnotateTypeOrScopeToken())

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Mon Mar  9 16:12:44 2009
@@ -569,6 +569,28 @@
         return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
     }
 
+    // Support 'Class.property' notation.
+    // We don't use isTokObjCMessageIdentifierReceiver(), since it allows 
+    // 'super' (which is inappropriate here).
+    if (getLang().ObjC1 && 
+        Actions.getTypeName(*Tok.getIdentifierInfo(), 
+                            Tok.getLocation(), CurScope) &&
+        NextToken().is(tok::period)) {
+      IdentifierInfo &ReceiverName = *Tok.getIdentifierInfo();
+      SourceLocation IdentLoc = ConsumeToken();
+      SourceLocation DotLoc = ConsumeToken();
+      
+      if (Tok.isNot(tok::identifier)) {
+        Diag(Tok, diag::err_expected_ident);
+        return ExprError();
+      }
+      IdentifierInfo &PropertyName = *Tok.getIdentifierInfo();
+      SourceLocation PropertyLoc = ConsumeToken();
+      
+      Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName,
+                                              IdentLoc, PropertyLoc);
+      return move(Res);
+    }
     // Consume the identifier so that we can see if it is followed by a '('.
     // Function designators are allowed to be undeclared (C99 6.5.1p2), so we
     // need to know whether or not this identifier is a function designator or

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Mar  9 16:12:44 2009
@@ -199,18 +199,6 @@
   return ClsType;
 }
 
-/// constructSetterName - Return the setter name for the given
-/// identifier, i.e. "set" + Name where the initial character of Name
-/// has been capitalized.
-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()]);
-}
-
 ///   objc-interface-decl-list:
 ///     empty
 ///     objc-interface-decl-list objc-property-decl [OBJC2]
@@ -340,8 +328,9 @@
           PP.getSelectorTable().getNullarySelector(SelName);
         IdentifierInfo *SetterName = OCDS.getSetterName();
         if (!SetterName)
-          SetterName = constructSetterName(PP.getIdentifierTable(),
-                                           FD.D.getIdentifier());
+          SetterName = 
+            SelectorTable::constructSetterName(PP.getIdentifierTable(),
+                                               FD.D.getIdentifier());
         Selector SetterSel = 
           PP.getSelectorTable().getUnarySelector(SetterName);
         bool isOverridingProperty = false;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Mar  9 16:12:44 2009
@@ -1791,6 +1791,12 @@
   ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel,
                                               ObjCInterfaceDecl *ClassDecl);
   
+  virtual OwningExprResult ActOnClassPropertyRefExpr(
+    IdentifierInfo &receiverName,
+    IdentifierInfo &propertyName,
+    SourceLocation &receiverNameLoc,
+    SourceLocation &propertyNameLoc);
+  
   // ActOnClassMessage - used for both unary and keyword messages.
   // ArgExprs is optional - if it is present, the number of expressions
   // is obtained from NumArgs.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Mar  9 16:12:44 2009
@@ -1657,20 +1657,6 @@
 }
 
 
-/// 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::OwningExprResult
 Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
                                tok::TokenKind OpKind, SourceLocation MemberLoc,
@@ -1900,8 +1886,9 @@
 
       // If we found a getter then this may be a valid dot-reference, we
       // will look for the matching setter, in case it is needed.
-      IdentifierInfo *SetterName = constructSetterName(PP.getIdentifierTable(),
-                                                       &Member);
+      IdentifierInfo *SetterName = 
+        SelectorTable::constructSetterName(PP.getIdentifierTable(), &Member);
+        
       Selector SetterSel = PP.getSelectorTable().getUnarySelector(SetterName);
       ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
       if (!Setter) {

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Mon Mar  9 16:12:44 2009
@@ -16,6 +16,8 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprObjC.h"
 #include "llvm/ADT/SmallString.h"
+#include "clang/Lex/Preprocessor.h"
+
 using namespace clang;
 
 Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, 
@@ -267,6 +269,78 @@
   return Method;
 }
 
+Action::OwningExprResult Sema::ActOnClassPropertyRefExpr(
+  IdentifierInfo &receiverName,
+  IdentifierInfo &propertyName,
+  SourceLocation &receiverNameLoc,
+  SourceLocation &propertyNameLoc) {
+  
+  ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName);
+  
+  // Search for a declared property first.
+  
+  Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
+  ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel);
+
+  // If this reference is in an @implementation, check for 'private' methods.
+  if (!Getter)
+    if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
+      if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
+        if (ObjCImplementationDecl *ImpDecl =
+            ObjCImplementations[ClassDecl->getIdentifier()])
+          Getter = ImpDecl->getClassMethod(Sel);
+
+  if (Getter) {
+    // FIXME: refactor/share with ActOnMemberReference().
+    // Check if we can reference this property.
+    if (DiagnoseUseOfDecl(Getter, propertyNameLoc))
+      return ExprError();
+  }
+  
+  // Look for the matching setter, in case it is needed.
+  IdentifierInfo *SetterName = 
+    SelectorTable::constructSetterName(PP.getIdentifierTable(), &propertyName);
+    
+  Selector SetterSel = PP.getSelectorTable().getUnarySelector(SetterName);
+  ObjCMethodDecl *Setter = IFace->lookupClassMethod(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->getClassMethod(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]->getClassMethod(SetterSel);
+    }
+  }
+
+  if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc))
+    return ExprError();
+
+  if (Getter || Setter) {
+    QualType PType;
+
+    if (Getter)
+      PType = Getter->getResultType();
+    else {
+      for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
+           E = Setter->param_end(); PI != E; ++PI)
+        PType = (*PI)->getType();
+    }
+    return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, Setter, 
+                                  propertyNameLoc, IFace, receiverNameLoc));
+  }
+  return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
+                     << &propertyName << Context.getObjCInterfaceType(IFace));
+}
+
+
 // ActOnClassMessage - used for both unary and keyword messages.
 // ArgExprs is optional - if it is present, the number of expressions
 // is obtained from Sel.getNumArgs().

Modified: cfe/trunk/test/Parser/check-objc2-syntax-1.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/check-objc2-syntax-1.m?rev=66465&r1=66464&r2=66465&view=diff

==============================================================================
--- cfe/trunk/test/Parser/check-objc2-syntax-1.m (original)
+++ cfe/trunk/test/Parser/check-objc2-syntax-1.m Mon Mar  9 16:12:44 2009
@@ -5,6 +5,6 @@
 @end
 
 int main (void) {
-  return Subclass.magicNumber; // expected-error {{unexpected interface name 'Subclass': expected expression}}
+  return Subclass.magicNumber;
 }
 

Added: cfe/trunk/test/SemaObjC/newproperty-class-method-1.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/newproperty-class-method-1.m?rev=66465&view=auto

==============================================================================
--- cfe/trunk/test/SemaObjC/newproperty-class-method-1.m (added)
+++ cfe/trunk/test/SemaObjC/newproperty-class-method-1.m Mon Mar  9 16:12:44 2009
@@ -0,0 +1,63 @@
+// RUN: clang %s -verify -fsyntax-only
+
+ at interface Subclass
++ (int)magicNumber;
++ (void)setMagicNumber:(int)value;
++ (void)setFakeSetterNumber:(int)value;
+ at end
+
+ at implementation Subclass
+int _magicNumber = 0;
++ (int)magicNumber {
+  return _magicNumber;
+}
+
++ (void)setMagicNumber:(int)value {
+  _magicNumber = value;
+}
+
++ (void)setFakeSetterNumber:(int)value {
+  _magicNumber = value;
+}
+
++ (void) classMeth
+{
+#if 0
+// FIXME: implement.
+	self.magicNumber = 10;
+	if (self.magicNumber != 10)
+	  abort ();
+#endif
+}
+ at end
+
+int main (void) {
+  
+  int a;
+  Subclass.magicNumber = 2 /*[Subclass setMagicNumber:2]*/;
+  if (Subclass.magicNumber != 0)
+    abort ();
+  if (Subclass.magicNumber != 2)
+    abort ();
+  Subclass.magicNumber += 3;
+  if (Subclass.magicNumber != 5)
+    abort ();
+  Subclass.magicNumber -= 5;
+  if (Subclass.magicNumber != 0)
+    abort ();
+  /* We only have a setter in the following case. */
+  Subclass.fakeSetterNumber = 123;
+
+  /* We read it using the other getter. */
+  if (Subclass.magicNumber != 123)
+   abort ();
+  Subclass.fakeSetterNumber = Subclass.magicNumber;
+  if (Subclass.magicNumber != 123)
+   abort ();
+
+  Subclass.fakeSetterNumberX = 123; // expected-error{{property 'fakeSetterNumberX' not found on object of type 'Subclass'}}
+
+  /* Test class methods using the new syntax. */
+  [Subclass classMeth];
+  return 0;
+}





More information about the cfe-commits mailing list