#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;
//===----------------------------------------------------------------------===//
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<Expr *>(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<Expr *>(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<Expr *>(keys[i].KeywordExpr);
+ if (numArgs) {
+ for (unsigned i = 0; i != numArgs; ++i)
+ SubExprs[i+ARGS_START] = static_cast<Expr *>(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
return reinterpret_cast<Stmt**>(&SubExprs[0]);
}
Stmt::child_iterator ObjCMessageExpr::child_end() {
- return reinterpret_cast<Stmt**>(&SubExprs[NumArgs+ARGS_START]);
+ return reinterpret_cast<Stmt**>(&SubExprs[getNumArgs()+ARGS_START]);
}
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
//===----------------------------------------------------------------------===//
// Compute statistics about the memory allocated for identifiers.
HashTable.getAllocator().PrintStats();
}
+
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-selector
/// objc-keyword-selector objc-parmlist[opt]
/// 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;
ReturnType = ParseObjCTypeName();
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) {
+ 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)
// 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.
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:
}
// Parse objc-selector
IdentifierInfo *selIdent = ParseObjCSelector();
- llvm::SmallVector<ObjcKeywordMessage, 12> KeyInfo;
+
+ llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
+ llvm::SmallVector<Action::ExprTy *, 12> 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) {
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();
}
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() {
}
ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
- PP.getIdentifierTable());
+ PP.getIdentifierTable(), PP.getSelectorTable());
ASTStreamer Streamer(PP, Context, MainFileID);
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).
}
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<ParmVarDecl*, 16> 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
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<Expr **>(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<Expr *>(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<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);
+ Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
+ return new ObjCMessageExpr(RExpr, Sel,
+ Context.IntTy/*FIXME*/, lbrac, rbrac, ArgExprs);
}
-
#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 <vector>
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 {
SourceManager &SourceMgr;
TargetInfo &Target;
IdentifierTable &Idents;
+ llvm::FoldingSet<SelectorInfo> &Selectors;
Builtin::Context BuiltinInfo;
// Builtin Types.
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<SelectorInfo> &sels) :
+ CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t),
+ Idents(idents), Selectors(sels) {
InitBuiltinTypes();
BuiltinInfo.InitializeBuiltins(idents, Target);
}
namespace clang {
class IdentifierInfo;
+class SelectorInfo;
class Expr;
class Stmt;
class FunctionDecl;
enum ImplementationControl { None, Required, Optional };
private:
// A unigue name for this method.
- IdentifierInfo &Selector;
+ SelectorInfo *Selector;
// Type of this method.
QualType MethodDeclType;
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,
: 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; }
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
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;
}
/// 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) {
#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 <string>
#include <cassert>
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
#endif
#include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroExpander.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/FoldingSet.h"
namespace clang {
/// 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<SelectorInfo> Selectors;
+
/// PragmaHandlers - This tracks all of the pragmas that the client registered
/// with this preprocessor.
PragmaNamespace *PragmaHandlers;
HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
IdentifierTable &getIdentifierTable() { return Identifiers; }
-
+ llvm::FoldingSet<SelectorInfo> &getSelectorTable() { return Selectors; }
+
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
// 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
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,
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