]> granicus.if.org Git - clang/commitdiff
Patch to implement AST generation for objective-c's @selector expression.
authorFariborz Jahanian <fjahanian@apple.com>
Tue, 16 Oct 2007 20:40:23 +0000 (20:40 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Tue, 16 Oct 2007 20:40:23 +0000 (20:40 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43038 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
AST/ASTContext.cpp
AST/Expr.cpp
AST/StmtDumper.cpp
AST/StmtPrinter.cpp
Parse/ParseObjc.cpp
Sema/Sema.cpp
Sema/Sema.h
Sema/SemaExpr.cpp
clang.xcodeproj/project.pbxproj
include/clang/AST/ASTContext.h
include/clang/AST/Expr.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
test/Sema/selector-1.m [new file with mode: 0644]

index 366966fec3c7dfb04babc6ec1f39c55743fffa5d..4c06e7c88cb4fca586e963a6e3ce4341894497fb 100644 (file)
@@ -856,6 +856,20 @@ void ASTContext::setObjcIdType(TypedefDecl *TD)
   IdStructType = rec;
 }
 
+void ASTContext::setObjcSelType(TypedefDecl *TD)
+{
+  assert(ObjcSelType.isNull() && "'SEL' type already set!");
+    
+  ObjcSelType = getTypedefType(TD);
+
+  // typedef struct objc_selector *SEL;
+  const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
+  assert(ptr && "'SEL' incorrectly typed");
+  const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
+  assert(rec && "'SEL' incorrectly typed");
+  SelStructType = rec;
+}
+
 void ASTContext::setObjcConstantStringInterface(ObjcInterfaceDecl *Decl) {
   assert(ObjcConstantStringType.isNull() && 
          "'NSConstantString' type already set!");
index f2e351a177d623e1accdcb47706b316b9b6473ed..5cd56ccbaf13bba9e21b392e46338a9f944afb4e 100644 (file)
@@ -1079,6 +1079,10 @@ Stmt::child_iterator ObjCStringLiteral::child_end() { return NULL; }
 Stmt::child_iterator ObjCEncodeExpr::child_begin() { return NULL; }
 Stmt::child_iterator ObjCEncodeExpr::child_end() { return NULL; }
 
+// ObjCSelectorExpr
+Stmt::child_iterator ObjCSelectorExpr::child_begin() { return NULL; }
+Stmt::child_iterator ObjCSelectorExpr::child_end() { return NULL; }
+
 // ObjCMessageExpr
 Stmt::child_iterator ObjCMessageExpr::child_begin() {
   return reinterpret_cast<Stmt**>(&SubExprs[0]);
index 410890c2a303c47dcfdc294f108b01c3acae2b61..bd5c615321a13d0aa6e74577551118cc6891285a 100644 (file)
@@ -128,6 +128,7 @@ namespace  {
 
     // ObjC
     void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
+    void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
   };
 }
 
@@ -406,6 +407,19 @@ void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
   DumpType(Node->getEncodedType());
 }
 
+void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
+  DumpExpr(Node);
+  
+  fprintf(F, " ");
+  Selector &selector = Node->getSelector();
+  if (selector.isUnarySelector())
+    fprintf(F, "%s", selector.getIdentifierInfoForSlot(0)->getName());
+  else {
+    for (unsigned i = 0, e = Node->getNumArgs(); i != e; ++i)
+      fprintf(F, "%s:", selector.getIdentifierInfoForSlot(i)->getName());
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Stmt method implementations
 //===----------------------------------------------------------------------===//
index 9b4ad11ec6f3bcd87331460f8e43038d5c696d7f..783368ef775609b735e9c35dc9b55c86881430ac 100644 (file)
@@ -620,6 +620,18 @@ void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
   OS << Node->getEncodedType().getAsString() << ")";
 }
 
+void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
+  OS << "@selector(";
+  Selector &selector = Node->getSelector();
+  if (selector.isUnarySelector())
+    OS << " " << selector.getIdentifierInfoForSlot(0)->getName();
+  else {
+    for (unsigned i = 0, e = Node->getNumArgs(); i != e; ++i)
+      OS << selector.getIdentifierInfoForSlot(i)->getName() << ":";
+  }
+  OS << ")";
+}
+
 void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
   OS << "[";
   Expr *receiver = Mess->getReceiver();
index 3c379621bf2f8b3c1de86099d0696ba336a0c7a6..274725417161d5ee208572af27b4d46cec68f152 100644 (file)
@@ -1318,6 +1318,7 @@ Parser::ExprResult Parser::ParseObjCSelectorExpression()
     return 0;
   }
   
+  llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
   SourceLocation LParenLoc = ConsumeParen();
   SourceLocation sLoc;
   IdentifierInfo *SelIdent = ParseObjCSelector(sLoc);
@@ -1326,6 +1327,9 @@ Parser::ExprResult Parser::ParseObjCSelectorExpression()
     Diag(Tok, diag::err_expected_ident); // missing selector name.
     return 0;
   }
+  if (!SelIdent)
+    SelIdent = &PP.getIdentifierTable().get("");
+  KeyIdents.push_back(SelIdent);
   if (Tok.isNot(tok::r_paren))
     while (1) {
       if (Tok.isNot(tok::colon)) {
@@ -1338,11 +1342,15 @@ Parser::ExprResult Parser::ParseObjCSelectorExpression()
       // Check for another keyword selector.
       SourceLocation Loc;
       SelIdent = ParseObjCSelector(Loc);
+      if (!SelIdent)
+        SelIdent = &PP.getIdentifierTable().get("");
+      KeyIdents.push_back(SelIdent);
       if (!SelIdent && Tok.isNot(tok::colon))
         break;
     }
   SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
-  
-  // FIXME 
-  return 0;
-}
\ No newline at end of file
+  Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(),
+                                                   &KeyIdents[0]);
+  return Actions.ParseObjCSelectorExpression(Sel, SelectorLoc, LParenLoc, 
+                                             RParenLoc);
+ }
\ No newline at end of file
index 330d9dce741ac2f4dc6226f4c41d668106e275bd..dc68eb03d85586b5ee98ce09200e5f5f0f60c35b 100644 (file)
@@ -45,6 +45,23 @@ QualType Sema::GetObjcIdType(SourceLocation Loc) {
   return Context.getObjcIdType();
 }
 
+/// GetObjcSelType - See comments for Sema::GetObjcIdType above; replace "id"
+/// with "SEL".
+QualType Sema::GetObjcSelType(SourceLocation Loc) {
+  assert(TUScope && "GetObjcSelType(): Top-level scope is null");
+  if (Context.getObjcSelType().isNull()) {
+    IdentifierInfo *SelIdent = &Context.Idents.get("SEL");
+    ScopedDecl *SelDecl = LookupScopedDecl(SelIdent, Decl::IDNS_Ordinary, 
+                                          SourceLocation(), TUScope);
+    TypedefDecl *ObjcSelTypedef = dyn_cast_or_null<TypedefDecl>(SelDecl);
+    if (!ObjcSelTypedef) {
+      Diag(Loc, diag::err_missing_sel_definition);
+      return QualType();
+    }
+    Context.setObjcSelType(ObjcSelTypedef);
+  }
+  return Context.getObjcSelType();
+}
 
 Sema::Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup)
   : PP(pp), Context(ctxt), CurFunctionDecl(0), LastInGroupList(prevInGroup) {
index c45bbf8e5dd4c17050dd2963d68298e4f88cc468..9d587791b4fd43ab76e1115534bd25309a2e456c 100644 (file)
@@ -277,6 +277,9 @@ private:
   /// GetObjcIdType - Getter for the build-in "id" type.
   QualType GetObjcIdType(SourceLocation Loc = SourceLocation());
   
+  /// GetObjcSelType - Getter for the build-in "SEL" type.
+  QualType GetObjcSelType(SourceLocation Loc = SourceLocation());
+  
   /// AddInstanceMethodToGlobalPool - All instance methods in a translation
   /// unit are added to a global pool. This allows us to efficiently associate
   /// a selector with a method declaraation for purposes of typechecking
@@ -441,6 +444,12 @@ public:
                                                TypeTy *Ty,
                                                SourceLocation RParenLoc);
   
+  // ParseObjCSelectorExpression - Build selector expression for @selector
+  virtual ExprResult ParseObjCSelectorExpression(Selector Sel,
+                                                 SourceLocation AtLoc,
+                                                 SourceLocation LParenLoc,
+                                                 SourceLocation RParenLoc);
+  
   // Objective-C declarations.
   virtual DeclTy *ActOnStartClassInterface(
                    SourceLocation AtInterafceLoc,
index daa1a7c141c8172b5dde9db6c5ed8ca3156acadd..082b7182b9b03c1625f3cf1a36d8bf90a2bb7967 100644 (file)
@@ -1919,6 +1919,14 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
   return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc);
 }
 
+Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
+                                                   SourceLocation AtLoc,
+                                                   SourceLocation LParenLoc,
+                                                   SourceLocation RParenLoc) {
+  QualType t = GetObjcSelType(AtLoc);
+  return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc);
+}
+
 // ActOnClassMessage - used for both unary and keyword messages.
 // ArgExprs is optional - if it is present, the number of expressions
 // is obtained from Sel.getNumArgs().
index b88c381faa0b21298a15082c3f3667bb0e3dacc7..75d938806b0068e9faf478a9935977559b88f772 100644 (file)
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
                        projectDirPath = "";
index bf0bf55123b8a01b6ca9964836b217999a5a3637..ec9b91b3aed52e0405517629eea3b8cb4e549880 100644 (file)
@@ -50,6 +50,10 @@ class ASTContext {
   QualType ObjcIdType;
   const RecordType *IdStructType;
   
+  /// ObjcSelType - another psuedo built-in typedef type (set by Sema).
+  QualType ObjcSelType;
+  const RecordType *SelStructType;
+  
   QualType ObjcConstantStringType;
   RecordDecl *CFConstantStringTypeDecl;
 public:
@@ -162,12 +166,15 @@ public:
   QualType getObjcConstantStringInterface() const { 
     return ObjcConstantStringType; 
   }
-  
+
   // This setter/getter repreents the ObjC 'id' type. It is setup lazily, by
   // Sema.
   void setObjcIdType(TypedefDecl *Decl);
   QualType getObjcIdType() const { return ObjcIdType; }
-
+  
+  void setObjcSelType(TypedefDecl *Decl);
+  QualType getObjcSelType() const { return ObjcSelType; }
+  
   void setBuiltinVaListType(QualType T);
   QualType getBuiltinVaListType() const { return BuiltinVaListType; }
     
index 5496508cd7929472591720776d0d7eec2dfcca17..0e0bdbb2ceafa1f17fd3775b35f03c891c14f432 100644 (file)
@@ -1091,6 +1091,37 @@ public:
   virtual child_iterator child_end();
 };
 
+/// ObjCSelectorExpr used for @selector in Objective-C.
+class ObjCSelectorExpr : public Expr {
+
+  Selector SelName;
+  
+  SourceLocation SelLoc, RParenLoc;
+public:
+  ObjCSelectorExpr(QualType T, Selector selInfo,
+                   SourceLocation selLoc, SourceLocation rp)
+  : Expr(ObjCSelectorExprClass, T), SelName(selInfo), 
+  SelLoc(selLoc), RParenLoc(rp) {}
+  
+  const Selector &getSelector() const { return SelName; }
+  Selector &getSelector() { return SelName; }
+  
+  /// getNumArgs - Return the number of actual arguments to this call.
+  unsigned getNumArgs() const { return SelName.getNumArgs(); }
+  
+  SourceRange getSourceRange() const { return SourceRange(SelLoc, RParenLoc); }
+  
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == ObjCSelectorExprClass;
+  }
+  static bool classof(const ObjCEncodeExpr *) { return true; }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+  
+};
+  
 class ObjCMessageExpr : public Expr {
   enum { RECEIVER=0, ARGS_START=1 };
 
index 5c4743faa98cbe24dbdba129b8df6ca758fbd734..76eb84913942bb0c047cf5b080169506d074a8d3 100644 (file)
@@ -82,8 +82,9 @@ STMT(61, CXXBoolLiteralExpr   , Expr)
 STMT(70, ObjCStringLiteral    , Expr)
 STMT(71, ObjCEncodeExpr       , Expr)
 STMT(72, ObjCMessageExpr      , Expr)
+STMT(73, ObjCSelectorExpr     , Expr)
 
-LAST_EXPR(72)
+LAST_EXPR(73)
 
 #undef STMT
 #undef FIRST_STMT
index bad641962b05d9511aba3e648e3f98fd01676df0..2443be892f95406a2b23f013e6825245a62d39e4 100644 (file)
@@ -444,6 +444,8 @@ DIAG(err_previous_declaration, ERROR,
      "previous declaration is here")
 DIAG(err_undeclared_protocol, ERROR,
      "cannot find protocol declaration for '%0'")
+DIAG(err_missing_sel_definition, ERROR,
+     "cannot find definition of 'SEL'")
 DIAG(err_missing_id_definition, ERROR,
      "cannot find definition of 'id'")
 DIAG(warn_previous_alias_decl, WARNING,
index a5e6875c3dc5dedc19c0e63b8cc07986409d915b..fdd30c0eb9f468356d1cfe0618f92530be562025 100644 (file)
@@ -594,10 +594,10 @@ public:
     return 0;
   }
   
-  virtual ExprResult ParseObjCSelectorExpression(SourceLocation EncLoc,
-                                               SourceLocation LParenLoc,
-                                               TypeTy *Ty,
-                                               SourceLocation RParenLoc) {
+  virtual ExprResult ParseObjCSelectorExpression(Selector Sel,
+                                                 SourceLocation SelLoc,
+                                                 SourceLocation LParenLoc,
+                                                 SourceLocation RParenLoc) {
     return 0;
   }
   
diff --git a/test/Sema/selector-1.m b/test/Sema/selector-1.m
new file mode 100644 (file)
index 0000000..59717c3
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: clang -verify %s 
+
+typedef struct objc_selector *SEL;
+
+int main() {
+ SEL s = @selector(retain);
+ SEL s1 = @selector(meth1:);
+ SEL s2 = @selector(retainArgument::);
+ SEL s3 = @selector(retainArgument:::::);
+ SEL s4 = @selector(retainArgument:with:);
+ SEL s5 = @selector(meth1:with:with:);
+ SEL s6 = @selector(getEnum:enum:bool:);
+ SEL s7 = @selector(char:float:double:unsigned:short:long:);
+
+ SEL s9 = @selector(:enum:bool:);
+}