From 68d331a78e655d97294e94fcfa63f92cc1f40578 Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Thu, 27 Sep 2007 14:38:14 +0000 Subject: [PATCH] Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits: #1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable. #2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%. #3: It results in many API simplifications. Here are some highlights: - Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages). - Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo). - Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured). I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later. Thanks to Chris for talking this through with me and suggesting this approach. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42395 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/Expr.cpp | 74 ++++++++-------- Lex/IdentifierTable.cpp | 23 +++++ Parse/ParseObjc.cpp | 130 +++++++++++++++++++--------- Sema/ASTStreamer.cpp | 2 +- Sema/Sema.h | 43 ++++----- Sema/SemaDecl.cpp | 64 +++----------- Sema/SemaExpr.cpp | 83 ++++-------------- include/clang/AST/ASTContext.h | 11 ++- include/clang/AST/Decl.h | 11 +-- include/clang/AST/Expr.h | 48 ++++------ include/clang/Lex/IdentifierTable.h | 63 ++++++++++++++ include/clang/Lex/Preprocessor.h | 13 ++- include/clang/Parse/Action.h | 61 +++++-------- include/clang/Parse/DeclSpec.h | 20 ----- 14 files changed, 328 insertions(+), 318 deletions(-) diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 0b1c7994ff..312d209e2d 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -15,8 +15,6 @@ #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; //===----------------------------------------------------------------------===// @@ -870,51 +868,53 @@ unsigned OCUVectorElementExpr::getEncodedElementAccess() const { return Result; } -// constructor for unary messages. -ObjCMessageExpr::ObjCMessageExpr( - IdentifierInfo *clsName, IdentifierInfo &methName, QualType retType, - SourceLocation LBrac, SourceLocation RBrac) - : Expr(ObjCMessageExprClass, retType), Selector(methName) { - ClassName = clsName; - LBracloc = LBrac; - RBracloc = RBrac; -} - -ObjCMessageExpr::ObjCMessageExpr( - Expr *fn, IdentifierInfo &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, IdentifierInfo &selInfo, ObjcKeywordMessage *keys, unsigned numargs, - QualType retType, SourceLocation LBrac, SourceLocation RBrac) +// constructor for instance messages. +ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, SelectorInfo *selInfo, + QualType retType, SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs) : 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); + unsigned numArgs = selInfo->getNumArgs(); + SubExprs = new Expr*[numArgs+1]; + SubExprs[RECEIVER] = receiver; + if (numArgs) { + for (unsigned i = 0; i != numArgs; ++i) + SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); + } LBracloc = LBrac; RBracloc = RBrac; } -ObjCMessageExpr::ObjCMessageExpr( - IdentifierInfo *clsName, IdentifierInfo &selInfo, ObjcKeywordMessage *keys, - unsigned numargs, QualType retType, SourceLocation LBrac, SourceLocation RBrac) +// constructor for class messages. +// FIXME: clsName should be typed to ObjCInterfaceType +ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo *selInfo, + QualType retType, SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs) : Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(clsName) { - SubExprs = new Expr*[numargs+1]; + unsigned numArgs = selInfo->getNumArgs(); + SubExprs = new Expr*[numArgs+1]; SubExprs[RECEIVER] = 0; - for (unsigned i = 0; i != numargs; ++i) - SubExprs[i+ARGS_START] = static_cast(keys[i].KeywordExpr); + if (numArgs) { + for (unsigned i = 0; i != numArgs; ++i) + SubExprs[i+ARGS_START] = static_cast(ArgExprs[i]); + } LBracloc = LBrac; RBracloc = RBrac; } +// The following 3 methods are defined here (instead of Epxr.h) to avoid +// importing "IdentifierTable.h" into the header. +unsigned ObjCMessageExpr::getNumArgs() const { return Selector->getNumArgs(); } + +/// getArg - Return the specified argument. +Expr *ObjCMessageExpr::getArg(unsigned Arg) { + assert(Arg < Selector->getNumArgs() && "Arg access out of range!"); + return SubExprs[Arg+ARGS_START]; +} +const Expr *ObjCMessageExpr::getArg(unsigned Arg) const { + assert(Arg < Selector->getNumArgs() && "Arg access out of range!"); + return SubExprs[Arg+ARGS_START]; +} + //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements @@ -1090,6 +1090,6 @@ Stmt::child_iterator ObjCMessageExpr::child_begin() { return reinterpret_cast(&SubExprs[0]); } Stmt::child_iterator ObjCMessageExpr::child_end() { - return reinterpret_cast(&SubExprs[NumArgs+ARGS_START]); + return reinterpret_cast(&SubExprs[getNumArgs()+ARGS_START]); } diff --git a/Lex/IdentifierTable.cpp b/Lex/IdentifierTable.cpp index d3faeb58db..6ab0ef1a69 100644 --- a/Lex/IdentifierTable.cpp +++ b/Lex/IdentifierTable.cpp @@ -33,6 +33,28 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const { return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword; } +char *SelectorInfo::getName(llvm::SmallString<128> methodName) { + int len=0; + methodName[0] = '\0'; + if (NumArgs) { + keyword_iterator KeyIter = keyword_begin(); + for (unsigned int i = 0; i < NumArgs; i++) { + if (KeyIter[i]) { + methodName += KeyIter[i]->getName(); + len += strlen(KeyIter[i]->getName()); + } + methodName += ":"; + len++; + } + } else { + IdentifierInfo **UnaryInfo = reinterpret_cast(this+1); + methodName += UnaryInfo[0]->getName(); + len += strlen(UnaryInfo[0]->getName()); + } + methodName[len] = '\0'; + return &methodName[0]; +} + //===----------------------------------------------------------------------===// // IdentifierInfo Implementation //===----------------------------------------------------------------------===// @@ -209,3 +231,4 @@ void IdentifierTable::PrintStats() const { // Compute statistics about the memory allocated for identifiers. HashTable.getAllocator().PrintStats(); } + diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index eddbb4a254..16434cdcdd 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -463,6 +463,52 @@ Parser::TypeTy *Parser::ParseObjCTypeName() { return Ty; } +static SelectorInfo *ObjcGetUnarySelectorInfo( + IdentifierInfo *unarySel, + llvm::FoldingSet &SelTab) +{ + // Unique selector, to guarantee there is one per name. + llvm::SmallVector IIV; + llvm::FoldingSetNodeID ID; + + IIV.push_back(unarySel); + SelectorInfo::Profile(ID, &IIV[0], 0); + + void *InsertPos = 0; + if (SelectorInfo *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) + return SI; + + // SelectorInfo objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + SelectorInfo *SI = + (SelectorInfo*)malloc(sizeof(SelectorInfo) + sizeof(IdentifierInfo *)); + new (SI) SelectorInfo(IIV[0]); + SelTab.InsertNode(SI, InsertPos); + return SI; +} + +static SelectorInfo *ObjcGetKeywordSelectorInfo( + llvm::SmallVectorImpl &IIV, + llvm::FoldingSet &SelTab) +{ + // Unique selector, to guarantee there is one per name. + llvm::FoldingSetNodeID ID; + SelectorInfo::Profile(ID, &IIV[0], IIV.size()); + + void *InsertPos = 0; + if (SelectorInfo *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) + return SI; + + // SelectorInfo objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + SelectorInfo *SI = + (SelectorInfo*)malloc(sizeof(SelectorInfo) + + IIV.size()*sizeof(IdentifierInfo *)); + new (SI) SelectorInfo(IIV.size(), &IIV[0]); + SelTab.InsertNode(SI, InsertPos); + return SI; +} + /// objc-method-decl: /// objc-selector /// objc-keyword-selector objc-parmlist[opt] @@ -491,9 +537,10 @@ Parser::TypeTy *Parser::ParseObjCTypeName() { /// objc-keyword-attributes: [OBJC2] /// __attribute__((unused)) /// -Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc, - tok::ObjCKeywordKind MethodImplKind) { - +Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, + SourceLocation mLoc, + tok::ObjCKeywordKind MethodImplKind) +{ TypeTy *ReturnType = 0; AttributeList *methodAttrs = 0; @@ -502,38 +549,39 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation ReturnType = ParseObjCTypeName(); IdentifierInfo *selIdent = ParseObjCSelector(); - llvm::SmallVector KeyInfo; - + llvm::SmallVector KeyIdents; + llvm::SmallVector KeyTypes; + llvm::SmallVector ArgNames; + if (Tok.getKind() == tok::colon) { + Action::TypeTy *TypeInfo; while (1) { - ObjcKeywordDecl KeyInfoDecl; - KeyInfoDecl.SelectorName = selIdent; + KeyIdents.push_back(selIdent); // Each iteration parses a single keyword argument. if (Tok.getKind() != tok::colon) { Diag(Tok, diag::err_expected_colon); break; } - KeyInfoDecl.ColonLoc = ConsumeToken(); // Eat the ':'. + ConsumeToken(); // Eat the ':'. if (Tok.getKind() == tok::l_paren) // Parse the argument type. - KeyInfoDecl.TypeInfo = ParseObjCTypeName(); - + TypeInfo = ParseObjCTypeName(); + else + TypeInfo = 0; + KeyTypes.push_back(TypeInfo); + // If attributes exist before the argument name, parse them. if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) - KeyInfoDecl.AttrList = ParseAttributes(); + ParseAttributes(); // FIXME: pass attributes through. if (Tok.getKind() != tok::identifier) { Diag(Tok, diag::err_expected_ident); // missing argument name. break; } - KeyInfoDecl.ArgumentName = Tok.getIdentifierInfo(); + ArgNames.push_back(Tok.getIdentifierInfo()); ConsumeToken(); // Eat the identifier. - // Rather than call out to the actions, package up the info locally, - // like we do for Declarator. - KeyInfo.push_back(KeyInfoDecl); - // Check for another keyword selector. selIdent = ParseObjCSelector(); if (!selIdent && Tok.getKind() != tok::colon) @@ -558,9 +606,11 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation // If attributes exist after the method, parse them. if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) methodAttrs = ParseAttributes(); - return Actions.ObjcBuildMethodDeclaration(mLoc, mType, - ReturnType, - &KeyInfo[0], KeyInfo.size(), + + SelectorInfo *SI = ObjcGetKeywordSelectorInfo(KeyIdents, + PP.getSelectorTable()); + return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, SI, + &KeyTypes[0], &ArgNames[0], methodAttrs, MethodImplKind); } else if (!selIdent) { Diag(Tok, diag::err_expected_ident); // missing selector name. @@ -569,9 +619,9 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) methodAttrs = ParseAttributes(); - return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, - selIdent, methodAttrs, - MethodImplKind); + SelectorInfo *SI = ObjcGetUnarySelectorInfo(selIdent, PP.getSelectorTable()); + return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, SI, + 0, 0, methodAttrs, MethodImplKind); } /// objc-protocol-refs: @@ -1107,19 +1157,21 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { } // Parse objc-selector IdentifierInfo *selIdent = ParseObjCSelector(); - llvm::SmallVector KeyInfo; + + llvm::SmallVector KeyIdents; + llvm::SmallVector KeyExprs; + if (Tok.getKind() == tok::colon) { while (1) { // Each iteration parses a single keyword argument. - ObjcKeywordMessage KeyInfoMess; - KeyInfoMess.SelectorName = selIdent; + KeyIdents.push_back(selIdent); if (Tok.getKind() != tok::colon) { Diag(Tok, diag::err_expected_colon); SkipUntil(tok::semi); return true; } - KeyInfoMess.ColonLoc = ConsumeToken(); // Eat the ':'. + ConsumeToken(); // Eat the ':'. /// Parse the expression after ':' ExprResult Res = ParseAssignmentExpression(); if (Res.isInvalid) { @@ -1127,11 +1179,7 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { return Res; } // We have a valid expression. - KeyInfoMess.KeywordExpr = Res.Val; - - // Rather than call out to the actions, package up the info locally, - // like we do for Declarator. - KeyInfo.push_back(KeyInfoMess); + KeyExprs.push_back(Res.Val); // Check for another keyword selector. selIdent = ParseObjCSelector(); @@ -1157,20 +1205,22 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() { } SourceLocation RBracloc = ConsumeBracket(); // consume ']' - if (KeyInfo.size()) { + if (KeyIdents.size()) { + SelectorInfo *SI = ObjcGetKeywordSelectorInfo(KeyIdents, + PP.getSelectorTable()); // We've just parsed a keyword message. if (ReceiverName) - return Actions.ActOnKeywordMessage(ReceiverName, - &KeyInfo[0], KeyInfo.size(), - LBracloc, RBracloc); - return Actions.ActOnKeywordMessage(ReceiverExpr, - &KeyInfo[0], KeyInfo.size(), - LBracloc, RBracloc); + return Actions.ActOnClassMessage(ReceiverName, SI, LBracloc, RBracloc, + &KeyExprs[0]); + return Actions.ActOnInstanceMessage(ReceiverExpr, SI, LBracloc, RBracloc, + &KeyExprs[0]); } + SelectorInfo *SI = ObjcGetUnarySelectorInfo(selIdent, PP.getSelectorTable()); + // We've just parsed a unary message (a message with no arguments). if (ReceiverName) - return Actions.ActOnUnaryMessage(ReceiverName, selIdent, LBracloc,RBracloc); - return Actions.ActOnUnaryMessage(ReceiverExpr, selIdent, LBracloc,RBracloc); + return Actions.ActOnClassMessage(ReceiverName, SI, LBracloc, RBracloc, 0); + return Actions.ActOnInstanceMessage(ReceiverExpr, SI, LBracloc, RBracloc, 0); } Parser::ExprResult Parser::ParseObjCStringLiteral() { diff --git a/Sema/ASTStreamer.cpp b/Sema/ASTStreamer.cpp index 9dce95afb3..8e5adcad51 100644 --- a/Sema/ASTStreamer.cpp +++ b/Sema/ASTStreamer.cpp @@ -98,7 +98,7 @@ void clang::ParseAST(Preprocessor &PP, unsigned MainFileID, } ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(), - PP.getIdentifierTable()); + PP.getIdentifierTable(), PP.getSelectorTable()); ASTStreamer Streamer(PP, Context, MainFileID); diff --git a/Sema/Sema.h b/Sema/Sema.h index bb83b0e6ae..a486d4fa73 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -391,32 +391,25 @@ public: DeclTy **Fields, unsigned NumFields); virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, - ObjcKeywordDecl *Keywords, unsigned NumKeywords, - AttributeList *AttrList, - tok::ObjCKeywordKind MethodImplKind); - virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, - IdentifierInfo *SelectorName, AttributeList *AttrList, - tok::ObjCKeywordKind MethodImplKind); + tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + TypeTy **ArgTypes, IdentifierInfo **ArgNames, + AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind); - // This actions handles keyword message to classes. - 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, - 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); + // ActOnClassMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from Sel.getNumArgs(). + virtual ExprResult ActOnClassMessage( + IdentifierInfo *receivingClassName, SelectorInfo *Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs); + + // ActOnInstanceMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from Sel.getNumArgs(). + virtual ExprResult ActOnInstanceMessage( + ExprTy *receiver, SelectorInfo *Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs); 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 1fb4142796..ae9c719471 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -1567,65 +1567,25 @@ void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl, } Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, - ObjcKeywordDecl *Keywords, unsigned NumKeywords, - AttributeList *AttrList, - tok::ObjCKeywordKind MethodDeclKind) { - assert(NumKeywords && "Selector must be specified"); - - // 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'; - IdentifierInfo &SelName = Context.Idents.get(&methodName[0], - &methodName[0]+len); + tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + TypeTy **ArgTypes, IdentifierInfo **ArgNames, + AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind) { llvm::SmallVector Params; - for (unsigned i = 0; i < NumKeywords; i++) { - ObjcKeywordDecl *arg = &Keywords[i]; + for (unsigned i = 0; i < Sel->getNumArgs(); i++) { // FIXME: arg->AttrList must be stored too! - ParmVarDecl* Param = new ParmVarDecl(arg->ColonLoc, arg->ArgumentName, - QualType::getFromOpaquePtr(arg->TypeInfo), + ParmVarDecl* Param = new ParmVarDecl(SourceLocation(/*FIXME*/), ArgNames[i], + QualType::getFromOpaquePtr(ArgTypes[i]), VarDecl::None, 0); - // FIXME: 'InvalidType' does not get set by caller yet. - if (arg->InvalidType) - Param->setInvalidDecl(); Params.push_back(Param); } QualType resultDeclType = QualType::getFromOpaquePtr(ReturnType); - ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, - SelName, resultDeclType, - 0, -1, AttrList, MethodType == tok::minus); - ObjcMethod->setMethodParams(&Params[0], NumKeywords); - if (MethodDeclKind == tok::objc_optional) - ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); - else - ObjcMethod->setDeclImplementation(ObjcMethodDecl::Required); - return ObjcMethod; -} - -Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, - IdentifierInfo *SelectorName, AttributeList *AttrList, - tok::ObjCKeywordKind MethodDeclKind) { - const char *methodName = SelectorName->getName(); - IdentifierInfo &SelName = Context.Idents.get(methodName, - methodName+strlen(methodName)); - QualType resultDeclType = QualType::getFromOpaquePtr(ReturnType); - ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, - SelName, resultDeclType, 0, -1, - AttrList, MethodType == tok::minus); + ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, Sel, + resultDeclType, 0, -1, AttrList, + MethodType == tok::minus); + ObjcMethod->setMethodParams(&Params[0], Sel->getNumArgs()); if (MethodDeclKind == tok::objc_optional) ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); else diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 15bf4fd0cb..67aa04de99 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1871,76 +1871,31 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc); } -static IdentifierInfo &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.Idents.get(&methodName[0], &methodName[0]+len); -} - -// This actions handles keyword message to classes. -Sema::ExprResult Sema::ActOnKeywordMessage( - IdentifierInfo *receivingClassName, - ObjcKeywordMessage *Keywords, unsigned NumKeywords, - SourceLocation lbrac, SourceLocation rbrac) +// ActOnClassMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::ExprResult Sema::ActOnClassMessage( + IdentifierInfo *receivingClassName, SelectorInfo *Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args) { - IdentifierInfo &SelName = DeriveSelector(Keywords, NumKeywords, Context); assert(receivingClassName && "missing receiver class name"); - return new ObjCMessageExpr(receivingClassName, SelName, Keywords, NumKeywords, - Context.IntTy/*FIXME*/, lbrac, rbrac); + Expr **ArgExprs = reinterpret_cast(Args); + return new ObjCMessageExpr(receivingClassName, Sel, + Context.IntTy/*FIXME*/, lbrac, rbrac, ArgExprs); } -// This action handles keyword messages to instances. -Sema::ExprResult Sema::ActOnKeywordMessage( - ExprTy *receiver, ObjcKeywordMessage *Keywords, unsigned NumKeywords, - SourceLocation lbrac, SourceLocation rbrac) { - IdentifierInfo &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 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... - IdentifierInfo &SName = Context.Idents.get( - selName->getName(), selName->getName()+strlen(selName->getName())); - return new ObjCMessageExpr(receivingClassName, SName, - Context.IntTy/*FIXME*/, lbrac, rbrac); -} - -// This action handles unary messages to instances. -Sema::ExprResult Sema::ActOnUnaryMessage( - ExprTy *receiver, IdentifierInfo *selName, - SourceLocation lbrac, SourceLocation rbrac) { +// ActOnInstanceMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::ExprResult Sema::ActOnInstanceMessage( + ExprTy *receiver, SelectorInfo *Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args) +{ assert(receiver && "missing receiver expression"); Expr *RExpr = static_cast(receiver); - // FIXME: this should be passed in... - IdentifierInfo &SName = Context.Idents.get( - selName->getName(), selName->getName()+strlen(selName->getName())); - return new ObjCMessageExpr(RExpr, SName, - Context.IntTy/*FIXME*/, lbrac, rbrac); + Expr **ArgExprs = reinterpret_cast(Args); + return new ObjCMessageExpr(RExpr, Sel, + Context.IntTy/*FIXME*/, lbrac, rbrac, ArgExprs); } - diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 91fa2abd97..f06f702dfd 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -14,17 +14,19 @@ #ifndef LLVM_CLANG_AST_ASTCONTEXT_H #define LLVM_CLANG_AST_ASTCONTEXT_H +#include "clang/Lex/IdentifierTable.h" // FIXME: Move IdentifierTable to Basic #include "clang/AST/Builtins.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/FoldingSet.h" #include namespace clang { class TargetInfo; - + /// ASTContext - This class holds long-lived AST nodes (such as types and /// decls) that can be referred to throughout the semantic analysis of a file. class ASTContext { @@ -46,6 +48,7 @@ public: SourceManager &SourceMgr; TargetInfo &Target; IdentifierTable &Idents; + llvm::FoldingSet &Selectors; Builtin::Context BuiltinInfo; // Builtin Types. @@ -58,8 +61,10 @@ public: QualType FloatTy, DoubleTy, LongDoubleTy; QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; - ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents) : - CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t), Idents(idents) { + ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents, + llvm::FoldingSet &sels) : + CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t), + Idents(idents), Selectors(sels) { InitBuiltinTypes(); BuiltinInfo.InitializeBuiltins(idents, Target); } diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index b420c1da81..ea8121326e 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -20,6 +20,7 @@ namespace clang { class IdentifierInfo; +class SelectorInfo; class Expr; class Stmt; class FunctionDecl; @@ -665,7 +666,7 @@ public: enum ImplementationControl { None, Required, Optional }; private: // A unigue name for this method. - IdentifierInfo &Selector; + SelectorInfo *Selector; // Type of this method. QualType MethodDeclType; @@ -683,14 +684,14 @@ private: ImplementationControl DeclImplementation : 2; public: - ObjcMethodDecl(SourceLocation L, IdentifierInfo &SelId, QualType T, + ObjcMethodDecl(SourceLocation L, SelectorInfo *SelInfo, QualType T, ParmVarDecl **paramInfo = 0, int numParams=-1, AttributeList *M = 0, bool isInstance = true, Decl *PrevDecl = 0) - : Decl(ObjcMethod), Selector(SelId), MethodDeclType(T), + : Decl(ObjcMethod), Selector(SelInfo), MethodDeclType(T), ParamInfo(paramInfo), NumMethodParams(numParams), MethodAttrs(M), IsInstance(isInstance) {} - +#if 0 ObjcMethodDecl(Kind DK, SourceLocation L, IdentifierInfo &SelId, QualType T, ParmVarDecl **paramInfo = 0, int numParams=-1, AttributeList *M = 0, bool isInstance = true, @@ -698,7 +699,7 @@ public: : Decl(DK), Selector(SelId), MethodDeclType(T), ParamInfo(paramInfo), NumMethodParams(numParams), MethodAttrs(M), IsInstance(isInstance) {} - +#endif virtual ~ObjcMethodDecl(); QualType getMethodType() const { return MethodDeclType; } unsigned getNumMethodParams() const { return NumMethodParams; } diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 73f730ef64..046c73a44c 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -22,9 +22,9 @@ namespace clang { class IdentifierInfo; + class SelectorInfo; 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 @@ -1073,36 +1073,25 @@ public: 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. - IdentifierInfo &Selector; - - IdentifierInfo **KeyIdents; + SelectorInfo *Selector; - IdentifierInfo *ClassName; + IdentifierInfo *ClassName; // optional - 0 for instance messages. SourceLocation LBracloc, RBracloc; public: - // constructor for unary messages. + // constructor for class messages. // FIXME: clsName should be typed to ObjCInterfaceType - ObjCMessageExpr(IdentifierInfo *clsName, IdentifierInfo &selInfo, - QualType retType, SourceLocation LBrac, SourceLocation RBrac); - ObjCMessageExpr(Expr *receiver, IdentifierInfo &selInfo, - QualType retType, SourceLocation LBrac, SourceLocation RBrac); - - // constructor for keyword messages. - // FIXME: clsName should be typed to ObjCInterfaceType - ObjCMessageExpr(IdentifierInfo *clsName, IdentifierInfo &selInfo, - ObjcKeywordMessage *keys, unsigned numargs, QualType retType, - SourceLocation LBrac, SourceLocation RBrac); - ObjCMessageExpr(Expr *receiver, IdentifierInfo &selInfo, - ObjcKeywordMessage *keys, unsigned numargs, QualType retType, - SourceLocation LBrac, SourceLocation RBrac); + ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo *selInfo, + QualType retType, SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs); + // constructor for instance messages. + ObjCMessageExpr(Expr *receiver, SelectorInfo *selInfo, + QualType retType, SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs); ~ObjCMessageExpr() { delete [] SubExprs; } @@ -1112,17 +1101,12 @@ public: /// getNumArgs - Return the number of actual arguments to this call. /// - unsigned getNumArgs() const { return NumArgs; } + unsigned getNumArgs() const; /// 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]; - } + Expr *getArg(unsigned Arg); + const Expr *getArg(unsigned Arg) const; + SourceRange getSourceRange() const { return SourceRange(LBracloc, RBracloc); } static bool classof(const Stmt *T) { diff --git a/include/clang/Lex/IdentifierTable.h b/include/clang/Lex/IdentifierTable.h index fd2cb6ae71..9b08202988 100644 --- a/include/clang/Lex/IdentifierTable.h +++ b/include/clang/Lex/IdentifierTable.h @@ -14,8 +14,12 @@ #ifndef LLVM_CLANG_LEX_IDENTIFIERTABLE_H #define LLVM_CLANG_LEX_IDENTIFIERTABLE_H +// FIXME: Move this header header/module to the "Basic" library. Unlike Lex, +// this data is long-lived. #include "clang/Basic/TokenKinds.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallString.h" #include #include @@ -166,6 +170,65 @@ private: void AddKeywords(const LangOptions &LangOpts); }; +/// SelectorInfo - One of these variable length records is kept for each parsed +/// selector (similar in spirit to IdentifierInfo). We use a folding set to +/// unique aggregate names (keyword selectors in ObjC parlance). +class SelectorInfo : public llvm::FoldingSetNode { + unsigned NumArgs; + void *ActionInfo; // Managed by the ObjC actions module. +public: + // Constructor for keyword selectors. + SelectorInfo(unsigned nKeys, IdentifierInfo **IIV) { + assert(nKeys && "SelectorInfo(): not a keyword selector"); + NumArgs = nKeys; + // Fill in the trailing keyword array. + IdentifierInfo **KeyInfo = reinterpret_cast(this+1); + for (unsigned i = 0; i != nKeys; ++i) + KeyInfo[i] = IIV[i]; + } + // Constructor for unary selectors (no colons/arguments). + SelectorInfo(IdentifierInfo *unarySelector) { + NumArgs = 0; + IdentifierInfo **UnaryInfo = reinterpret_cast(this+1); + UnaryInfo[0] = unarySelector; + } + // Derive the full selector name, placing the result into methodBuffer. + // As a convenience, a pointer to the first character is returned. + char *getName(llvm::SmallString<128> methodBuffer); + + unsigned getNumArgs() const { return NumArgs; } + + // Predicates to identify the selector type. + bool isKeywordSelector() const { return NumArgs > 0; } + bool isUnarySelector() const { return NumArgs == 0; } + + /// getActionInfo/setActionInfo - The actions module is allowed to + /// associate arbitrary metadata with this selector. + template + T *getActionInfo() const { return static_cast(ActionInfo); } + void setActionInfo(void *T) { ActionInfo = T; } + + typedef const IdentifierInfo *const *keyword_iterator; + keyword_iterator keyword_begin() const { + return reinterpret_cast(this+1); + } + keyword_iterator keyword_end() const { + return keyword_begin()+NumArgs; + } + static void Profile(llvm::FoldingSetNodeID &ID, + keyword_iterator ArgTys, unsigned NumArgs) { + ID.AddInteger(NumArgs); + if (NumArgs) { // handle keyword selector. + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i]); + } else // handle unary selector. + ID.AddPointer(ArgTys[0]); + } + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, keyword_begin(), NumArgs); + } +}; + } // end namespace clang #endif diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index ff1faaa58c..b3008375d8 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -18,6 +18,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/MacroExpander.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/FoldingSet.h" namespace clang { @@ -73,6 +74,15 @@ class Preprocessor { /// the program, including program keywords. IdentifierTable Identifiers; + /// Selectors - This table contains all the selectors in the program. Unlike + /// IdentifierTable above, this table *isn't* populated by the preprocessor. + /// It is declared/instantiated here because it's role/lifetime is + /// conceptually similar the IdentifierTable. In addition, the current control + /// flow (in clang::ParseAST()), make it convenient to put here. + /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to + /// the lifetime fo the preprocessor. + llvm::FoldingSet Selectors; + /// PragmaHandlers - This tracks all of the pragmas that the client registered /// with this preprocessor. PragmaNamespace *PragmaHandlers; @@ -132,7 +142,8 @@ public: HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } IdentifierTable &getIdentifierTable() { return Identifiers; } - + llvm::FoldingSet &getSelectorTable() { return Selectors; } + /// SetCommentRetentionState - Control whether or not the preprocessor retains /// comments in output. void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) { diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index bc14226bec..3e9a687ef4 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -21,14 +21,13 @@ namespace clang { // Semantic. class DeclSpec; class Declarator; - struct ObjcKeywordDecl; - struct ObjcKeywordMessage; class AttributeList; // Parse. class Scope; class Action; + class SelectorInfo; // Lex. - class IdentifierInfo; + class IdentifierInfo; // FIXME: should be in Basic, not Lex. class Token; /// Action - As the parser reads the input file and recognizes the productions @@ -472,41 +471,27 @@ public: return 0; } virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, - ObjcKeywordDecl *Keywords, unsigned NumKeywords, - AttributeList *AttrList, - tok::ObjCKeywordKind MethodImplKind) { - return 0; - } - virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, - tok::TokenKind MethodType, TypeTy *ReturnType, - IdentifierInfo *SelectorName, AttributeList *AttrList, - tok::ObjCKeywordKind MethodImplKind) { - return 0; - } - // This actions handles keyword message to classes. - 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, - SourceLocation lbrac, SourceLocation rbrac) { - return 0; - } - // This actions handles unary message to classes. - virtual ExprResult ActOnUnaryMessage( - IdentifierInfo *receivingClassName, IdentifierInfo *selName, - SourceLocation lbrac, SourceLocation rbrac) { - return 0; - } - // This action handles unary messages to instances. - virtual ExprResult ActOnUnaryMessage( - ExprTy *receiver, IdentifierInfo *sName, - SourceLocation lbrac, SourceLocation rbrac) { + tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + TypeTy **ArgTypes, IdentifierInfo **ArgNames, + AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind) { + return 0; + } + // ActOnClassMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from Sel.getNumArgs(). + virtual ExprResult ActOnClassMessage( + IdentifierInfo *receivingClassName, SelectorInfo *Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs) { + return 0; + } + // ActOnInstanceMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from Sel.getNumArgs(). + virtual ExprResult ActOnInstanceMessage( + ExprTy *receiver, SelectorInfo *Sel, + SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs) { return 0; } virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc, diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 73254cd682..c17469dd25 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -562,26 +562,6 @@ public: bool getInvalidType() { return InvalidType; } }; -/// ObjCKeyword* - The following 3 small value structures capture keyword -/// information passed from the parser to the actions. Like Declarator above, -/// instances of these structures are transient objects that live on the stack. -struct ObjcKeywordInfo { - IdentifierInfo *SelectorName; // optional - SourceLocation SelectorLoc; - SourceLocation ColonLoc; -}; - -struct ObjcKeywordDecl : ObjcKeywordInfo { - Action::TypeTy *TypeInfo; // optional - IdentifierInfo *ArgumentName; - AttributeList *AttrList; - bool InvalidType; // FIXME: is this used? -}; - -struct ObjcKeywordMessage : ObjcKeywordInfo { - Action::ExprTy *KeywordExpr; -}; - } // end namespace clang #endif -- 2.40.0