From: Steve Naroff Date: Tue, 18 Sep 2007 23:55:05 +0000 (+0000) Subject: Progress on message expressions... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=563477da25f824e37c535131695dc4dc9b68c465;p=clang Progress on message expressions... - Add ObjcMessageExpr AST node and associated constructors. - Add SourceLocation's to ActOnKeywordMessage/ActOnUnaryMessage API. - Instantiate message expressions... - Replace alloca usage with SmallString. Next step, installing a correct type, among other tweaks... git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42116 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 620c29b095..08773e86d0 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -15,6 +15,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/IdentifierTable.h" +// is this bad layering? I (snaroff) don't think so. Want Chris to weigh in. +#include "clang/Parse/DeclSpec.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -854,6 +856,52 @@ unsigned OCUVectorElementExpr::getEncodedElementAccess() const { return Result; } +// constructor for unary messages. +ObjCMessageExpr::ObjCMessageExpr( + IdentifierInfo *clsName, SelectorInfo &methName, QualType retType, + SourceLocation LBrac, SourceLocation RBrac) + : Expr(ObjCMessageExprClass, retType), Selector(methName) { + ClassName = clsName; + LBracloc = LBrac; + RBracloc = RBrac; +} + +ObjCMessageExpr::ObjCMessageExpr( + Expr *fn, SelectorInfo &methName, QualType retType, + SourceLocation LBrac, SourceLocation RBrac) + : Expr(ObjCMessageExprClass, retType), Selector(methName), ClassName(0) { + SubExprs = new Expr*[1]; + SubExprs[RECEIVER] = fn; + LBracloc = LBrac; + RBracloc = RBrac; +} + +// constructor for keyword messages. +ObjCMessageExpr::ObjCMessageExpr( + Expr *fn, SelectorInfo &selInfo, ObjcKeywordMessage *keys, unsigned numargs, + QualType retType, SourceLocation LBrac, SourceLocation RBrac) + : Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(0) { + SubExprs = new Expr*[numargs+1]; + SubExprs[RECEIVER] = fn; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = static_cast(keys[i].KeywordExpr); + LBracloc = LBrac; + RBracloc = RBrac; +} + +ObjCMessageExpr::ObjCMessageExpr( + IdentifierInfo *clsName, SelectorInfo &selInfo, ObjcKeywordMessage *keys, + unsigned numargs, QualType retType, SourceLocation LBrac, SourceLocation RBrac) + : Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(clsName) { + SubExprs = new Expr*[numargs+1]; + SubExprs[RECEIVER] = 0; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = static_cast(keys[i].KeywordExpr); + LBracloc = LBrac; + RBracloc = RBrac; +} + + //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// @@ -1023,3 +1071,11 @@ Stmt::child_iterator ObjCStringLiteral::child_end() { return NULL; } Stmt::child_iterator ObjCEncodeExpr::child_begin() { return NULL; } Stmt::child_iterator ObjCEncodeExpr::child_end() { return NULL; } +// ObjCMessageExpr +Stmt::child_iterator ObjCMessageExpr::child_begin() { + return reinterpret_cast(&SubExprs[0]); +} +Stmt::child_iterator ObjCMessageExpr::child_end() { + return reinterpret_cast(&SubExprs[NumArgs+ARGS_START]); +} + diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index 9e8f3e9b20..11dd2ef767 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -612,6 +612,17 @@ void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { OS << Node->getEncodedType().getAsString() << ")"; } +void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { + OS << "["; + PrintExpr(Mess->getReceiver()); + for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) { + // FIXME: get/print keyword... + PrintExpr(Mess->getArg(i)); + } + OS << "]"; +} + + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 224b826374..356c7a7fd4 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -1007,7 +1007,7 @@ Parser::ExprResult Parser::ParseObjCExpression() { /// Parser::ExprResult Parser::ParseObjCMessageExpression() { assert(Tok.getKind() == tok::l_square && "'[' expected"); - SourceLocation Loc = ConsumeBracket(); // consume '[' + SourceLocation LBracloc = ConsumeBracket(); // consume '[' IdentifierInfo *ReceiverName = 0; ExprTy *ReceiverExpr = 0; // Parse receiver @@ -1073,20 +1073,22 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { SkipUntil(tok::semi); return 0; } - ConsumeBracket(); // consume ']' + SourceLocation RBracloc = ConsumeBracket(); // consume ']' if (KeyInfo.size()) { // We've just parsed a keyword message. if (ReceiverName) return Actions.ActOnKeywordMessage(ReceiverName, - &KeyInfo[0], KeyInfo.size()); + &KeyInfo[0], KeyInfo.size(), + LBracloc, RBracloc); return Actions.ActOnKeywordMessage(ReceiverExpr, - &KeyInfo[0], KeyInfo.size()); + &KeyInfo[0], KeyInfo.size(), + LBracloc, RBracloc); } // We've just parsed a unary message (a message with no arguments). if (ReceiverName) - return Actions.ActOnUnaryMessage(ReceiverName, selIdent); - return Actions.ActOnUnaryMessage(ReceiverExpr, selIdent); + return Actions.ActOnUnaryMessage(ReceiverName, selIdent, LBracloc,RBracloc); + return Actions.ActOnUnaryMessage(ReceiverExpr, selIdent, LBracloc,RBracloc); } Parser::ExprResult Parser::ParseObjCStringLiteral() { diff --git a/Sema/Sema.h b/Sema/Sema.h index 79fc111e64..29a03d1eb2 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -384,17 +384,22 @@ public: tok::ObjCKeywordKind MethodImplKind); // This actions handles keyword message to classes. - virtual ExprResult ActOnKeywordMessage(IdentifierInfo *receivingClassName, - ObjcKeywordMessage *Keywords, unsigned NumKeywords); + virtual ExprResult ActOnKeywordMessage( + IdentifierInfo *receivingClassName, + ObjcKeywordMessage *Keywords, unsigned NumKeywords, + SourceLocation lbrac, SourceLocation rbrac); // This action handles keyword messages to instances. virtual ExprResult ActOnKeywordMessage(ExprTy *receiver, - ObjcKeywordMessage *Keywords, unsigned NumKeywords); - - // This actions handles keyword message to classes. - virtual ExprResult ActOnUnaryMessage(IdentifierInfo *receivingClassName, - IdentifierInfo *selName); - // This action handles keyword messages to instances. - virtual ExprResult ActOnUnaryMessage(ExprTy *receiver, IdentifierInfo *sName); + ObjcKeywordMessage *Keywords, unsigned NumKeywords, + SourceLocation lbrac, SourceLocation rbrac); + // This actions handles unary message to classes. + virtual ExprResult ActOnUnaryMessage( + IdentifierInfo *receivingClassName, IdentifierInfo *selName, + SourceLocation lbrac, SourceLocation rbrac); + // This action handles unary messages to instances. + virtual ExprResult ActOnUnaryMessage( + ExprTy *receiver, IdentifierInfo *sName, + SourceLocation lbrac, SourceLocation rbrac); private: // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 3b7d8f3467..d5ca796934 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -23,6 +23,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Config/config.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallSet.h" #if !defined(LLVM_ON_WIN32) #include @@ -1298,21 +1299,21 @@ Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, // Derive the selector name from the keyword declarations. int len=0; - char *methodName; for (unsigned int i = 0; i < NumKeywords; i++) { if (Keywords[i].SelectorName) len += strlen(Keywords[i].SelectorName->getName()); len++; } - methodName = (char *) alloca (len + 1); + llvm::SmallString<128> methodName; methodName[0] = '\0'; for (unsigned int i = 0; i < NumKeywords; i++) { if (Keywords[i].SelectorName) - strcat(methodName, Keywords[i].SelectorName->getName()); - strcat(methodName, ":"); + methodName += Keywords[i].SelectorName->getName(); + methodName += ":"; } - SelectorInfo &SelName = Context.getSelectorInfo(methodName, methodName+len); - + methodName[len] = '\0'; + SelectorInfo &SelName = Context.getSelectorInfo(&methodName[0], + &methodName[0]+len); llvm::SmallVector Params; for (unsigned i = 0; i < NumKeywords; i++) { @@ -1332,9 +1333,9 @@ Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, 0, -1, AttrList, MethodType == tok::minus); ObjcMethod->setMethodParams(&Params[0], NumKeywords); if (MethodDeclKind == tok::objc_optional) - ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); + ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); else - ObjcMethod->setDeclImplementation(ObjcMethodDecl::Required); + ObjcMethod->setDeclImplementation(ObjcMethodDecl::Required); return ObjcMethod; } @@ -1350,9 +1351,9 @@ Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, SelName, resultDeclType, 0, -1, AttrList, MethodType == tok::minus); if (MethodDeclKind == tok::objc_optional) - ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); + ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); else - ObjcMethod->setDeclImplementation(ObjcMethodDecl::Required); + ObjcMethod->setDeclImplementation(ObjcMethodDecl::Required); return ObjcMethod; } diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index d7136a387a..886b3dd5bd 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/Parse/DeclSpec.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Basic/SourceManager.h" @@ -1856,28 +1857,76 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc); } +static SelectorInfo &DeriveSelector(ObjcKeywordMessage *Keywords, + unsigned NumKeywords, + ASTContext &Context) { + // Derive the selector name from the keyword declarations. + int len=0; + for (unsigned int i = 0; i < NumKeywords; i++) { + if (Keywords[i].SelectorName) + len += strlen(Keywords[i].SelectorName->getName()); + len++; + } + llvm::SmallString<128> methodName; + methodName[0] = '\0'; + for (unsigned int i = 0; i < NumKeywords; i++) { + if (Keywords[i].SelectorName) + methodName += Keywords[i].SelectorName->getName(); + methodName += ":"; + } + methodName[len] = '\0'; + return Context.getSelectorInfo(&methodName[0], &methodName[0]+len); +} + // This actions handles keyword message to classes. -Sema::ExprResult Sema::ActOnKeywordMessage(IdentifierInfo *receivingClassName, - ObjcKeywordMessage *Keywords, unsigned NumKeywords) +Sema::ExprResult Sema::ActOnKeywordMessage( + IdentifierInfo *receivingClassName, + ObjcKeywordMessage *Keywords, unsigned NumKeywords, + SourceLocation lbrac, SourceLocation rbrac) { - return 0; + SelectorInfo &SelName = DeriveSelector(Keywords, NumKeywords, Context); + assert(receivingClassName && "missing receiver class name"); + + return new ObjCMessageExpr(receivingClassName, SelName, Keywords, NumKeywords, + Context.IntTy/*FIXME*/, lbrac, rbrac); } // This action handles keyword messages to instances. -Sema::ExprResult Sema::ActOnKeywordMessage(ExprTy *receiver, - ObjcKeywordMessage *Keywords, unsigned NumKeywords) { - return 0; +Sema::ExprResult Sema::ActOnKeywordMessage( + ExprTy *receiver, ObjcKeywordMessage *Keywords, unsigned NumKeywords, + SourceLocation lbrac, SourceLocation rbrac) { + SelectorInfo &SelName = DeriveSelector(Keywords, NumKeywords, Context); + assert(receiver && "missing receiver expression"); + + Expr *RExpr = static_cast(receiver); + return new ObjCMessageExpr(RExpr, SelName, Keywords, NumKeywords, + Context.IntTy/*FIXME*/, lbrac, rbrac); } -// This actions handles keyword message to classes. -Sema::ExprResult Sema::ActOnUnaryMessage(IdentifierInfo *receivingClassName, - IdentifierInfo *selName) { - return 0; +// This actions handles unary message to classes. +Sema::ExprResult Sema::ActOnUnaryMessage( + IdentifierInfo *receivingClassName, IdentifierInfo *selName, + SourceLocation lbrac, SourceLocation rbrac) { + assert(receivingClassName && "missing receiver class name"); + + // FIXME: this should be passed in... + SelectorInfo &SName = Context.getSelectorInfo( + selName->getName(), selName->getName()+strlen(selName->getName())); + return new ObjCMessageExpr(receivingClassName, SName, + Context.IntTy/*FIXME*/, lbrac, rbrac); } -// This action handles keyword messages to instances. -Sema::ExprResult Sema::ActOnUnaryMessage(ExprTy *receiver, - IdentifierInfo *selName) { - return 0; +// This action handles unary messages to instances. +Sema::ExprResult Sema::ActOnUnaryMessage( + ExprTy *receiver, IdentifierInfo *selName, + SourceLocation lbrac, SourceLocation rbrac) { + assert(receiver && "missing receiver expression"); + + Expr *RExpr = static_cast(receiver); + // FIXME: this should be passed in... + SelectorInfo &SName = Context.getSelectorInfo( + selName->getName(), selName->getName()+strlen(selName->getName())); + return new ObjCMessageExpr(RExpr, SName, + Context.IntTy/*FIXME*/, lbrac, rbrac); } diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index efd8ad6d16..0bf3c3b32e 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -708,7 +708,6 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; - compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index ecf6eb025c..84d9a791b9 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -23,6 +23,7 @@ namespace clang { class IdentifierInfo; class Decl; class ASTContext; + struct ObjcKeywordMessage; /// Expr - This represents one expression. Note that Expr's are subclasses of /// Stmt. This allows an expression to be transparently used any place a Stmt @@ -1058,6 +1059,70 @@ public: virtual child_iterator child_end(); }; +class ObjCMessageExpr : public Expr { + enum { RECEIVER=0, ARGS_START=1 }; + + // The following 3 slots are only used for keyword messages. + // Adding a subclass could save us some space. For now, we keep it simple. + Expr **SubExprs; + unsigned NumArgs; + + // A unigue name for this message. + SelectorInfo &Selector; + + IdentifierInfo **KeyIdents; + + IdentifierInfo *ClassName; + + SourceLocation LBracloc, RBracloc; +public: + // constructor for unary messages. + // FIXME: clsName should be typed to ObjCInterfaceType + ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo &selInfo, + QualType retType, SourceLocation LBrac, SourceLocation RBrac); + ObjCMessageExpr(Expr *receiver, SelectorInfo &selInfo, + QualType retType, SourceLocation LBrac, SourceLocation RBrac); + + // constructor for keyword messages. + // FIXME: clsName should be typed to ObjCInterfaceType + ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo &selInfo, + ObjcKeywordMessage *keys, unsigned numargs, QualType retType, + SourceLocation LBrac, SourceLocation RBrac); + ObjCMessageExpr(Expr *receiver, SelectorInfo &selInfo, + ObjcKeywordMessage *keys, unsigned numargs, QualType retType, + SourceLocation LBrac, SourceLocation RBrac); + ~ObjCMessageExpr() { + delete [] SubExprs; + } + + const Expr *getReceiver() const { return SubExprs[RECEIVER]; } + Expr *getReceiver() { return SubExprs[RECEIVER]; } + + /// getNumArgs - Return the number of actual arguments to this call. + /// + unsigned getNumArgs() const { return NumArgs; } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return SubExprs[Arg+ARGS_START]; + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return SubExprs[Arg+ARGS_START]; + } + SourceRange getSourceRange() const { return SourceRange(LBracloc, RBracloc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCMessageExprClass; + } + static bool classof(const ObjCMessageExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + } // end namespace clang #endif diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 54be80e040..d505312aad 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -80,8 +80,9 @@ STMT(61, CXXBoolLiteralExpr , Expr) // Obj-C Expressions. STMT(70, ObjCStringLiteral , Expr) STMT(71, ObjCEncodeExpr , Expr) +STMT(72, ObjCMessageExpr , Expr) -LAST_EXPR(71) +LAST_EXPR(72) #undef STMT #undef FIRST_STMT diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index f7a7809c7b..fab3bfe73d 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -473,22 +473,28 @@ public: return 0; } // This actions handles keyword message to classes. - virtual ExprResult ActOnKeywordMessage(IdentifierInfo *receivingClassName, - ObjcKeywordMessage *Keywords, unsigned NumKeywords) { + virtual ExprResult ActOnKeywordMessage( + IdentifierInfo *receivingClassName, + ObjcKeywordMessage *Keywords, unsigned NumKeywords, + SourceLocation lbrac, SourceLocation rbrac) { return 0; } // This action handles keyword messages to instances. virtual ExprResult ActOnKeywordMessage(ExprTy *receiver, - ObjcKeywordMessage *Keywords, unsigned NumKeywords) { + ObjcKeywordMessage *Keywords, unsigned NumKeywords, + SourceLocation lbrac, SourceLocation rbrac) { return 0; } - // This actions handles keyword message to classes. - virtual ExprResult ActOnUnaryMessage(IdentifierInfo *receivingClassName, - IdentifierInfo *selName) { + // This actions handles unary message to classes. + virtual ExprResult ActOnUnaryMessage( + IdentifierInfo *receivingClassName, IdentifierInfo *selName, + SourceLocation lbrac, SourceLocation rbrac) { return 0; } - // This action handles keyword messages to instances. - virtual ExprResult ActOnUnaryMessage(ExprTy *receiver,IdentifierInfo *sName) { + // This action handles unary messages to instances. + virtual ExprResult ActOnUnaryMessage( + ExprTy *receiver, IdentifierInfo *sName, + SourceLocation lbrac, SourceLocation rbrac) { return 0; } virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,