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. 

llvm-svn: 42395
This commit is contained in:
Steve Naroff 2007-09-27 14:38:14 +00:00
parent 3934961878
commit f73590dbb1
14 changed files with 324 additions and 314 deletions

View File

@ -15,8 +15,6 @@
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h" #include "clang/AST/StmtVisitor.h"
#include "clang/Lex/IdentifierTable.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; using namespace clang;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -870,51 +868,53 @@ unsigned OCUVectorElementExpr::getEncodedElementAccess() const {
return Result; return Result;
} }
// constructor for unary messages. // constructor for instance messages.
ObjCMessageExpr::ObjCMessageExpr( ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, SelectorInfo *selInfo,
IdentifierInfo *clsName, IdentifierInfo &methName, QualType retType, QualType retType, SourceLocation LBrac, SourceLocation RBrac,
SourceLocation LBrac, SourceLocation RBrac) Expr **ArgExprs)
: 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)
: Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(0) { : Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(0) {
SubExprs = new Expr*[numargs+1]; unsigned numArgs = selInfo->getNumArgs();
SubExprs[RECEIVER] = fn; SubExprs = new Expr*[numArgs+1];
for (unsigned i = 0; i != numargs; ++i) SubExprs[RECEIVER] = receiver;
SubExprs[i+ARGS_START] = static_cast<Expr *>(keys[i].KeywordExpr); if (numArgs) {
for (unsigned i = 0; i != numArgs; ++i)
SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
}
LBracloc = LBrac; LBracloc = LBrac;
RBracloc = RBrac; RBracloc = RBrac;
} }
ObjCMessageExpr::ObjCMessageExpr( // constructor for class messages.
IdentifierInfo *clsName, IdentifierInfo &selInfo, ObjcKeywordMessage *keys, // FIXME: clsName should be typed to ObjCInterfaceType
unsigned numargs, QualType retType, SourceLocation LBrac, SourceLocation RBrac) ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo *selInfo,
QualType retType, SourceLocation LBrac, SourceLocation RBrac,
Expr **ArgExprs)
: Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(clsName) { : Expr(ObjCMessageExprClass, retType), Selector(selInfo), ClassName(clsName) {
SubExprs = new Expr*[numargs+1]; unsigned numArgs = selInfo->getNumArgs();
SubExprs = new Expr*[numArgs+1];
SubExprs[RECEIVER] = 0; SubExprs[RECEIVER] = 0;
for (unsigned i = 0; i != numargs; ++i) if (numArgs) {
SubExprs[i+ARGS_START] = static_cast<Expr *>(keys[i].KeywordExpr); for (unsigned i = 0; i != numArgs; ++i)
SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
}
LBracloc = LBrac; LBracloc = LBrac;
RBracloc = RBrac; 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 // Child Iterators for iterating over subexpressions/substatements
@ -1090,6 +1090,6 @@ Stmt::child_iterator ObjCMessageExpr::child_begin() {
return reinterpret_cast<Stmt**>(&SubExprs[0]); return reinterpret_cast<Stmt**>(&SubExprs[0]);
} }
Stmt::child_iterator ObjCMessageExpr::child_end() { Stmt::child_iterator ObjCMessageExpr::child_end() {
return reinterpret_cast<Stmt**>(&SubExprs[NumArgs+ARGS_START]); return reinterpret_cast<Stmt**>(&SubExprs[getNumArgs()+ARGS_START]);
} }

View File

@ -33,6 +33,28 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const {
return specId ? specId->getObjCKeywordID() : tok::objc_not_keyword; 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<IdentifierInfo **>(this+1);
methodName += UnaryInfo[0]->getName();
len += strlen(UnaryInfo[0]->getName());
}
methodName[len] = '\0';
return &methodName[0];
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// IdentifierInfo Implementation // IdentifierInfo Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -209,3 +231,4 @@ void IdentifierTable::PrintStats() const {
// Compute statistics about the memory allocated for identifiers. // Compute statistics about the memory allocated for identifiers.
HashTable.getAllocator().PrintStats(); HashTable.getAllocator().PrintStats();
} }

View File

@ -463,6 +463,52 @@ Parser::TypeTy *Parser::ParseObjCTypeName() {
return Ty; return Ty;
} }
static SelectorInfo *ObjcGetUnarySelectorInfo(
IdentifierInfo *unarySel,
llvm::FoldingSet<SelectorInfo> &SelTab)
{
// Unique selector, to guarantee there is one per name.
llvm::SmallVector<IdentifierInfo *, 1> 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<IdentifierInfo *> &IIV,
llvm::FoldingSet<SelectorInfo> &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-method-decl:
/// objc-selector /// objc-selector
/// objc-keyword-selector objc-parmlist[opt] /// objc-keyword-selector objc-parmlist[opt]
@ -491,9 +537,10 @@ Parser::TypeTy *Parser::ParseObjCTypeName() {
/// objc-keyword-attributes: [OBJC2] /// objc-keyword-attributes: [OBJC2]
/// __attribute__((unused)) /// __attribute__((unused))
/// ///
Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc, Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
tok::ObjCKeywordKind MethodImplKind) { SourceLocation mLoc,
tok::ObjCKeywordKind MethodImplKind)
{
TypeTy *ReturnType = 0; TypeTy *ReturnType = 0;
AttributeList *methodAttrs = 0; AttributeList *methodAttrs = 0;
@ -502,38 +549,39 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation
ReturnType = ParseObjCTypeName(); ReturnType = ParseObjCTypeName();
IdentifierInfo *selIdent = ParseObjCSelector(); IdentifierInfo *selIdent = ParseObjCSelector();
llvm::SmallVector<ObjcKeywordDecl, 12> KeyInfo; llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
llvm::SmallVector<Action::TypeTy *, 12> KeyTypes;
llvm::SmallVector<IdentifierInfo *, 12> ArgNames;
if (Tok.getKind() == tok::colon) { if (Tok.getKind() == tok::colon) {
Action::TypeTy *TypeInfo;
while (1) { while (1) {
ObjcKeywordDecl KeyInfoDecl; KeyIdents.push_back(selIdent);
KeyInfoDecl.SelectorName = selIdent;
// Each iteration parses a single keyword argument. // Each iteration parses a single keyword argument.
if (Tok.getKind() != tok::colon) { if (Tok.getKind() != tok::colon) {
Diag(Tok, diag::err_expected_colon); Diag(Tok, diag::err_expected_colon);
break; break;
} }
KeyInfoDecl.ColonLoc = ConsumeToken(); // Eat the ':'. ConsumeToken(); // Eat the ':'.
if (Tok.getKind() == tok::l_paren) // Parse the argument type. 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 attributes exist before the argument name, parse them.
if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
KeyInfoDecl.AttrList = ParseAttributes(); ParseAttributes(); // FIXME: pass attributes through.
if (Tok.getKind() != tok::identifier) { if (Tok.getKind() != tok::identifier) {
Diag(Tok, diag::err_expected_ident); // missing argument name. Diag(Tok, diag::err_expected_ident); // missing argument name.
break; break;
} }
KeyInfoDecl.ArgumentName = Tok.getIdentifierInfo(); ArgNames.push_back(Tok.getIdentifierInfo());
ConsumeToken(); // Eat the identifier. 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. // Check for another keyword selector.
selIdent = ParseObjCSelector(); selIdent = ParseObjCSelector();
if (!selIdent && Tok.getKind() != tok::colon) 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 attributes exist after the method, parse them.
if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
methodAttrs = ParseAttributes(); methodAttrs = ParseAttributes();
return Actions.ObjcBuildMethodDeclaration(mLoc, mType,
ReturnType, SelectorInfo *SI = ObjcGetKeywordSelectorInfo(KeyIdents,
&KeyInfo[0], KeyInfo.size(), PP.getSelectorTable());
return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, SI,
&KeyTypes[0], &ArgNames[0],
methodAttrs, MethodImplKind); methodAttrs, MethodImplKind);
} else if (!selIdent) { } else if (!selIdent) {
Diag(Tok, diag::err_expected_ident); // missing selector name. 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) if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
methodAttrs = ParseAttributes(); methodAttrs = ParseAttributes();
return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, SelectorInfo *SI = ObjcGetUnarySelectorInfo(selIdent, PP.getSelectorTable());
selIdent, methodAttrs, return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, SI,
MethodImplKind); 0, 0, methodAttrs, MethodImplKind);
} }
/// objc-protocol-refs: /// objc-protocol-refs:
@ -1107,19 +1157,21 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() {
} }
// Parse objc-selector // Parse objc-selector
IdentifierInfo *selIdent = ParseObjCSelector(); IdentifierInfo *selIdent = ParseObjCSelector();
llvm::SmallVector<ObjcKeywordMessage, 12> KeyInfo;
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
llvm::SmallVector<Action::ExprTy *, 12> KeyExprs;
if (Tok.getKind() == tok::colon) { if (Tok.getKind() == tok::colon) {
while (1) { while (1) {
// Each iteration parses a single keyword argument. // Each iteration parses a single keyword argument.
ObjcKeywordMessage KeyInfoMess; KeyIdents.push_back(selIdent);
KeyInfoMess.SelectorName = selIdent;
if (Tok.getKind() != tok::colon) { if (Tok.getKind() != tok::colon) {
Diag(Tok, diag::err_expected_colon); Diag(Tok, diag::err_expected_colon);
SkipUntil(tok::semi); SkipUntil(tok::semi);
return true; return true;
} }
KeyInfoMess.ColonLoc = ConsumeToken(); // Eat the ':'. ConsumeToken(); // Eat the ':'.
/// Parse the expression after ':' /// Parse the expression after ':'
ExprResult Res = ParseAssignmentExpression(); ExprResult Res = ParseAssignmentExpression();
if (Res.isInvalid) { if (Res.isInvalid) {
@ -1127,11 +1179,7 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() {
return Res; return Res;
} }
// We have a valid expression. // We have a valid expression.
KeyInfoMess.KeywordExpr = Res.Val; KeyExprs.push_back(Res.Val);
// Rather than call out to the actions, package up the info locally,
// like we do for Declarator.
KeyInfo.push_back(KeyInfoMess);
// Check for another keyword selector. // Check for another keyword selector.
selIdent = ParseObjCSelector(); selIdent = ParseObjCSelector();
@ -1157,20 +1205,22 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() {
} }
SourceLocation RBracloc = ConsumeBracket(); // consume ']' SourceLocation RBracloc = ConsumeBracket(); // consume ']'
if (KeyInfo.size()) { if (KeyIdents.size()) {
SelectorInfo *SI = ObjcGetKeywordSelectorInfo(KeyIdents,
PP.getSelectorTable());
// We've just parsed a keyword message. // We've just parsed a keyword message.
if (ReceiverName) if (ReceiverName)
return Actions.ActOnKeywordMessage(ReceiverName, return Actions.ActOnClassMessage(ReceiverName, SI, LBracloc, RBracloc,
&KeyInfo[0], KeyInfo.size(), &KeyExprs[0]);
LBracloc, RBracloc); return Actions.ActOnInstanceMessage(ReceiverExpr, SI, LBracloc, RBracloc,
return Actions.ActOnKeywordMessage(ReceiverExpr, &KeyExprs[0]);
&KeyInfo[0], KeyInfo.size(),
LBracloc, RBracloc);
} }
SelectorInfo *SI = ObjcGetUnarySelectorInfo(selIdent, PP.getSelectorTable());
// We've just parsed a unary message (a message with no arguments). // We've just parsed a unary message (a message with no arguments).
if (ReceiverName) if (ReceiverName)
return Actions.ActOnUnaryMessage(ReceiverName, selIdent, LBracloc,RBracloc); return Actions.ActOnClassMessage(ReceiverName, SI, LBracloc, RBracloc, 0);
return Actions.ActOnUnaryMessage(ReceiverExpr, selIdent, LBracloc,RBracloc); return Actions.ActOnInstanceMessage(ReceiverExpr, SI, LBracloc, RBracloc, 0);
} }
Parser::ExprResult Parser::ParseObjCStringLiteral() { Parser::ExprResult Parser::ParseObjCStringLiteral() {

View File

@ -98,7 +98,7 @@ void clang::ParseAST(Preprocessor &PP, unsigned MainFileID,
} }
ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(), ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
PP.getIdentifierTable()); PP.getIdentifierTable(), PP.getSelectorTable());
ASTStreamer Streamer(PP, Context, MainFileID); ASTStreamer Streamer(PP, Context, MainFileID);

View File

@ -391,32 +391,25 @@ public:
DeclTy **Fields, unsigned NumFields); DeclTy **Fields, unsigned NumFields);
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType, tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel,
ObjcKeywordDecl *Keywords, unsigned NumKeywords, // optional arguments. The number of types/arguments is obtained
AttributeList *AttrList, // from the Sel.getNumArgs().
tok::ObjCKeywordKind MethodImplKind); TypeTy **ArgTypes, IdentifierInfo **ArgNames,
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind);
tok::TokenKind MethodType, TypeTy *ReturnType,
IdentifierInfo *SelectorName, AttributeList *AttrList,
tok::ObjCKeywordKind MethodImplKind);
// This actions handles keyword message to classes. // ActOnClassMessage - used for both unary and keyword messages.
virtual ExprResult ActOnKeywordMessage( // ArgExprs is optional - if it is present, the number of expressions
IdentifierInfo *receivingClassName, // is obtained from Sel.getNumArgs().
ObjcKeywordMessage *Keywords, unsigned NumKeywords, virtual ExprResult ActOnClassMessage(
SourceLocation lbrac, SourceLocation rbrac); IdentifierInfo *receivingClassName, SelectorInfo *Sel,
// This action handles keyword messages to instances. SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs);
virtual ExprResult ActOnKeywordMessage(ExprTy *receiver,
ObjcKeywordMessage *Keywords, unsigned NumKeywords, // ActOnInstanceMessage - used for both unary and keyword messages.
SourceLocation lbrac, SourceLocation rbrac); // ArgExprs is optional - if it is present, the number of expressions
// This actions handles unary message to classes. // is obtained from Sel.getNumArgs().
virtual ExprResult ActOnUnaryMessage( virtual ExprResult ActOnInstanceMessage(
IdentifierInfo *receivingClassName, IdentifierInfo *selName, ExprTy *receiver, SelectorInfo *Sel,
SourceLocation lbrac, SourceLocation rbrac); SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs);
// This action handles unary messages to instances.
virtual ExprResult ActOnUnaryMessage(
ExprTy *receiver, IdentifierInfo *sName,
SourceLocation lbrac, SourceLocation rbrac);
private: private:
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
// functions and arrays to their respective pointers (C99 6.3.2.1). // functions and arrays to their respective pointers (C99 6.3.2.1).

View File

@ -1567,65 +1567,25 @@ void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl,
} }
Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc, Sema::DeclTy *Sema::ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType, tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel,
ObjcKeywordDecl *Keywords, unsigned NumKeywords, // optional arguments. The number of types/arguments is obtained
AttributeList *AttrList, // from the Sel.getNumArgs().
tok::ObjCKeywordKind MethodDeclKind) { TypeTy **ArgTypes, IdentifierInfo **ArgNames,
assert(NumKeywords && "Selector must be specified"); AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind) {
// 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);
llvm::SmallVector<ParmVarDecl*, 16> Params; llvm::SmallVector<ParmVarDecl*, 16> Params;
for (unsigned i = 0; i < NumKeywords; i++) { for (unsigned i = 0; i < Sel->getNumArgs(); i++) {
ObjcKeywordDecl *arg = &Keywords[i];
// FIXME: arg->AttrList must be stored too! // FIXME: arg->AttrList must be stored too!
ParmVarDecl* Param = new ParmVarDecl(arg->ColonLoc, arg->ArgumentName, ParmVarDecl* Param = new ParmVarDecl(SourceLocation(/*FIXME*/), ArgNames[i],
QualType::getFromOpaquePtr(arg->TypeInfo), QualType::getFromOpaquePtr(ArgTypes[i]),
VarDecl::None, 0); VarDecl::None, 0);
// FIXME: 'InvalidType' does not get set by caller yet.
if (arg->InvalidType)
Param->setInvalidDecl();
Params.push_back(Param); Params.push_back(Param);
} }
QualType resultDeclType = QualType::getFromOpaquePtr(ReturnType); QualType resultDeclType = QualType::getFromOpaquePtr(ReturnType);
ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, ObjcMethodDecl* ObjcMethod = new ObjcMethodDecl(MethodLoc, Sel,
SelName, resultDeclType, resultDeclType, 0, -1, AttrList,
0, -1, AttrList, MethodType == tok::minus); MethodType == tok::minus);
ObjcMethod->setMethodParams(&Params[0], NumKeywords); ObjcMethod->setMethodParams(&Params[0], Sel->getNumArgs());
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);
if (MethodDeclKind == tok::objc_optional) if (MethodDeclKind == tok::objc_optional)
ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional); ObjcMethod->setDeclImplementation(ObjcMethodDecl::Optional);
else else

View File

@ -1871,76 +1871,31 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc); return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc);
} }
static IdentifierInfo &DeriveSelector(ObjcKeywordMessage *Keywords, // ActOnClassMessage - used for both unary and keyword messages.
unsigned NumKeywords, // ArgExprs is optional - if it is present, the number of expressions
ASTContext &Context) { // is obtained from Sel.getNumArgs().
// Derive the selector name from the keyword declarations. Sema::ExprResult Sema::ActOnClassMessage(
int len=0; IdentifierInfo *receivingClassName, SelectorInfo *Sel,
for (unsigned int i = 0; i < NumKeywords; i++) { SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args)
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)
{ {
IdentifierInfo &SelName = DeriveSelector(Keywords, NumKeywords, Context);
assert(receivingClassName && "missing receiver class name"); assert(receivingClassName && "missing receiver class name");
return new ObjCMessageExpr(receivingClassName, SelName, Keywords, NumKeywords, Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
Context.IntTy/*FIXME*/, lbrac, rbrac); return new ObjCMessageExpr(receivingClassName, Sel,
Context.IntTy/*FIXME*/, lbrac, rbrac, ArgExprs);
} }
// This action handles keyword messages to instances. // ActOnInstanceMessage - used for both unary and keyword messages.
Sema::ExprResult Sema::ActOnKeywordMessage( // ArgExprs is optional - if it is present, the number of expressions
ExprTy *receiver, ObjcKeywordMessage *Keywords, unsigned NumKeywords, // is obtained from Sel.getNumArgs().
SourceLocation lbrac, SourceLocation rbrac) { Sema::ExprResult Sema::ActOnInstanceMessage(
IdentifierInfo &SelName = DeriveSelector(Keywords, NumKeywords, Context); ExprTy *receiver, SelectorInfo *Sel,
SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args)
{
assert(receiver && "missing receiver expression"); assert(receiver && "missing receiver expression");
Expr *RExpr = static_cast<Expr *>(receiver); Expr *RExpr = static_cast<Expr *>(receiver);
return new ObjCMessageExpr(RExpr, SelName, Keywords, NumKeywords, Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
Context.IntTy/*FIXME*/, lbrac, rbrac); return new ObjCMessageExpr(RExpr, Sel,
Context.IntTy/*FIXME*/, lbrac, rbrac, ArgExprs);
} }
// 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) {
assert(receiver && "missing receiver expression");
Expr *RExpr = static_cast<Expr *>(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);
}

View File

@ -14,12 +14,14 @@
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H #ifndef LLVM_CLANG_AST_ASTCONTEXT_H
#define 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/Builtins.h"
#include "clang/AST/Expr.h" #include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h" #include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/FoldingSet.h"
#include <vector> #include <vector>
namespace clang { namespace clang {
@ -46,6 +48,7 @@ public:
SourceManager &SourceMgr; SourceManager &SourceMgr;
TargetInfo &Target; TargetInfo &Target;
IdentifierTable &Idents; IdentifierTable &Idents;
llvm::FoldingSet<SelectorInfo> &Selectors;
Builtin::Context BuiltinInfo; Builtin::Context BuiltinInfo;
// Builtin Types. // Builtin Types.
@ -58,8 +61,10 @@ public:
QualType FloatTy, DoubleTy, LongDoubleTy; QualType FloatTy, DoubleTy, LongDoubleTy;
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents) : ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents,
CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t), Idents(idents) { llvm::FoldingSet<SelectorInfo> &sels) :
CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t),
Idents(idents), Selectors(sels) {
InitBuiltinTypes(); InitBuiltinTypes();
BuiltinInfo.InitializeBuiltins(idents, Target); BuiltinInfo.InitializeBuiltins(idents, Target);
} }

View File

@ -20,6 +20,7 @@
namespace clang { namespace clang {
class IdentifierInfo; class IdentifierInfo;
class SelectorInfo;
class Expr; class Expr;
class Stmt; class Stmt;
class FunctionDecl; class FunctionDecl;
@ -665,7 +666,7 @@ public:
enum ImplementationControl { None, Required, Optional }; enum ImplementationControl { None, Required, Optional };
private: private:
// A unigue name for this method. // A unigue name for this method.
IdentifierInfo &Selector; SelectorInfo *Selector;
// Type of this method. // Type of this method.
QualType MethodDeclType; QualType MethodDeclType;
@ -683,14 +684,14 @@ private:
ImplementationControl DeclImplementation : 2; ImplementationControl DeclImplementation : 2;
public: public:
ObjcMethodDecl(SourceLocation L, IdentifierInfo &SelId, QualType T, ObjcMethodDecl(SourceLocation L, SelectorInfo *SelInfo, QualType T,
ParmVarDecl **paramInfo = 0, int numParams=-1, ParmVarDecl **paramInfo = 0, int numParams=-1,
AttributeList *M = 0, bool isInstance = true, AttributeList *M = 0, bool isInstance = true,
Decl *PrevDecl = 0) Decl *PrevDecl = 0)
: Decl(ObjcMethod), Selector(SelId), MethodDeclType(T), : Decl(ObjcMethod), Selector(SelInfo), MethodDeclType(T),
ParamInfo(paramInfo), NumMethodParams(numParams), ParamInfo(paramInfo), NumMethodParams(numParams),
MethodAttrs(M), IsInstance(isInstance) {} MethodAttrs(M), IsInstance(isInstance) {}
#if 0
ObjcMethodDecl(Kind DK, SourceLocation L, IdentifierInfo &SelId, QualType T, ObjcMethodDecl(Kind DK, SourceLocation L, IdentifierInfo &SelId, QualType T,
ParmVarDecl **paramInfo = 0, int numParams=-1, ParmVarDecl **paramInfo = 0, int numParams=-1,
AttributeList *M = 0, bool isInstance = true, AttributeList *M = 0, bool isInstance = true,
@ -698,7 +699,7 @@ public:
: Decl(DK), Selector(SelId), MethodDeclType(T), : Decl(DK), Selector(SelId), MethodDeclType(T),
ParamInfo(paramInfo), NumMethodParams(numParams), ParamInfo(paramInfo), NumMethodParams(numParams),
MethodAttrs(M), IsInstance(isInstance) {} MethodAttrs(M), IsInstance(isInstance) {}
#endif
virtual ~ObjcMethodDecl(); virtual ~ObjcMethodDecl();
QualType getMethodType() const { return MethodDeclType; } QualType getMethodType() const { return MethodDeclType; }
unsigned getNumMethodParams() const { return NumMethodParams; } unsigned getNumMethodParams() const { return NumMethodParams; }

View File

@ -22,9 +22,9 @@
namespace clang { namespace clang {
class IdentifierInfo; class IdentifierInfo;
class SelectorInfo;
class Decl; class Decl;
class ASTContext; class ASTContext;
struct ObjcKeywordMessage;
/// Expr - This represents one expression. Note that Expr's are subclasses of /// 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 /// Stmt. This allows an expression to be transparently used any place a Stmt
@ -1074,35 +1074,24 @@ public:
class ObjCMessageExpr : public Expr { class ObjCMessageExpr : public Expr {
enum { RECEIVER=0, ARGS_START=1 }; 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; Expr **SubExprs;
unsigned NumArgs;
// A unigue name for this message. // A unigue name for this message.
IdentifierInfo &Selector; SelectorInfo *Selector;
IdentifierInfo **KeyIdents; IdentifierInfo *ClassName; // optional - 0 for instance messages.
IdentifierInfo *ClassName;
SourceLocation LBracloc, RBracloc; SourceLocation LBracloc, RBracloc;
public: public:
// constructor for unary messages. // constructor for class messages.
// FIXME: clsName should be typed to ObjCInterfaceType // FIXME: clsName should be typed to ObjCInterfaceType
ObjCMessageExpr(IdentifierInfo *clsName, IdentifierInfo &selInfo, ObjCMessageExpr(IdentifierInfo *clsName, SelectorInfo *selInfo,
QualType retType, SourceLocation LBrac, SourceLocation RBrac); QualType retType, SourceLocation LBrac, SourceLocation RBrac,
ObjCMessageExpr(Expr *receiver, IdentifierInfo &selInfo, Expr **ArgExprs);
QualType retType, SourceLocation LBrac, SourceLocation RBrac); // constructor for instance messages.
ObjCMessageExpr(Expr *receiver, SelectorInfo *selInfo,
// constructor for keyword messages. QualType retType, SourceLocation LBrac, SourceLocation RBrac,
// FIXME: clsName should be typed to ObjCInterfaceType Expr **ArgExprs);
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() { ~ObjCMessageExpr() {
delete [] SubExprs; delete [] SubExprs;
} }
@ -1112,17 +1101,12 @@ public:
/// getNumArgs - Return the number of actual arguments to this call. /// getNumArgs - Return the number of actual arguments to this call.
/// ///
unsigned getNumArgs() const { return NumArgs; } unsigned getNumArgs() const;
/// getArg - Return the specified argument. /// getArg - Return the specified argument.
Expr *getArg(unsigned Arg) { Expr *getArg(unsigned Arg);
assert(Arg < NumArgs && "Arg access out of range!"); const Expr *getArg(unsigned Arg) const;
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); } SourceRange getSourceRange() const { return SourceRange(LBracloc, RBracloc); }
static bool classof(const Stmt *T) { static bool classof(const Stmt *T) {

View File

@ -14,8 +14,12 @@
#ifndef LLVM_CLANG_LEX_IDENTIFIERTABLE_H #ifndef LLVM_CLANG_LEX_IDENTIFIERTABLE_H
#define 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 "clang/Basic/TokenKinds.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
#include <string> #include <string>
#include <cassert> #include <cassert>
@ -166,6 +170,65 @@ private:
void AddKeywords(const LangOptions &LangOpts); 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<IdentifierInfo **>(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<IdentifierInfo **>(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<typename T>
T *getActionInfo() const { return static_cast<T*>(ActionInfo); }
void setActionInfo(void *T) { ActionInfo = T; }
typedef const IdentifierInfo *const *keyword_iterator;
keyword_iterator keyword_begin() const {
return reinterpret_cast<keyword_iterator>(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 } // end namespace clang
#endif #endif

View File

@ -18,6 +18,7 @@
#include "clang/Lex/Lexer.h" #include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroExpander.h" #include "clang/Lex/MacroExpander.h"
#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/FoldingSet.h"
namespace clang { namespace clang {
@ -73,6 +74,15 @@ class Preprocessor {
/// the program, including program keywords. /// the program, including program keywords.
IdentifierTable Identifiers; 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<SelectorInfo> Selectors;
/// PragmaHandlers - This tracks all of the pragmas that the client registered /// PragmaHandlers - This tracks all of the pragmas that the client registered
/// with this preprocessor. /// with this preprocessor.
PragmaNamespace *PragmaHandlers; PragmaNamespace *PragmaHandlers;
@ -132,6 +142,7 @@ public:
HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
IdentifierTable &getIdentifierTable() { return Identifiers; } IdentifierTable &getIdentifierTable() { return Identifiers; }
llvm::FoldingSet<SelectorInfo> &getSelectorTable() { return Selectors; }
/// SetCommentRetentionState - Control whether or not the preprocessor retains /// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output. /// comments in output.

View File

@ -21,14 +21,13 @@ namespace clang {
// Semantic. // Semantic.
class DeclSpec; class DeclSpec;
class Declarator; class Declarator;
struct ObjcKeywordDecl;
struct ObjcKeywordMessage;
class AttributeList; class AttributeList;
// Parse. // Parse.
class Scope; class Scope;
class Action; class Action;
class SelectorInfo;
// Lex. // Lex.
class IdentifierInfo; class IdentifierInfo; // FIXME: should be in Basic, not Lex.
class Token; class Token;
/// Action - As the parser reads the input file and recognizes the productions /// Action - As the parser reads the input file and recognizes the productions
@ -472,41 +471,27 @@ public:
return 0; return 0;
} }
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc,
tok::TokenKind MethodType, TypeTy *ReturnType, tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel,
ObjcKeywordDecl *Keywords, unsigned NumKeywords, // optional arguments. The number of types/arguments is obtained
AttributeList *AttrList, // from the Sel.getNumArgs().
tok::ObjCKeywordKind MethodImplKind) { TypeTy **ArgTypes, IdentifierInfo **ArgNames,
AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind) {
return 0; return 0;
} }
virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, // ActOnClassMessage - used for both unary and keyword messages.
tok::TokenKind MethodType, TypeTy *ReturnType, // ArgExprs is optional - if it is present, the number of expressions
IdentifierInfo *SelectorName, AttributeList *AttrList, // is obtained from Sel.getNumArgs().
tok::ObjCKeywordKind MethodImplKind) { virtual ExprResult ActOnClassMessage(
IdentifierInfo *receivingClassName, SelectorInfo *Sel,
SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs) {
return 0; return 0;
} }
// This actions handles keyword message to classes. // ActOnInstanceMessage - used for both unary and keyword messages.
virtual ExprResult ActOnKeywordMessage( // ArgExprs is optional - if it is present, the number of expressions
IdentifierInfo *receivingClassName, // is obtained from Sel.getNumArgs().
ObjcKeywordMessage *Keywords, unsigned NumKeywords, virtual ExprResult ActOnInstanceMessage(
SourceLocation lbrac, SourceLocation rbrac) { ExprTy *receiver, SelectorInfo *Sel,
return 0; SourceLocation lbrac, SourceLocation rbrac, ExprTy **ArgExprs) {
}
// 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) {
return 0; return 0;
} }
virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc, virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,

View File

@ -562,26 +562,6 @@ public:
bool getInvalidType() { return InvalidType; } 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 } // end namespace clang
#endif #endif