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
diff --git a/AST/Expr.cpp b/AST/Expr.cpp
index 0b1c799..312d209 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 @@
   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
@@ -1090,6 +1090,6 @@
   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]);
 }