[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