From: Fariborz Jahanian Date: Tue, 16 Oct 2007 20:40:23 +0000 (+0000) Subject: Patch to implement AST generation for objective-c's @selector expression. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b62f6813406a03bf8a371c4e46c9fad51d102121;p=clang Patch to implement AST generation for objective-c's @selector expression. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43038 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index 366966fec3..4c06e7c88c 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -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!"); diff --git a/AST/Expr.cpp b/AST/Expr.cpp index f2e351a177..5cd56ccbaf 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -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(&SubExprs[0]); diff --git a/AST/StmtDumper.cpp b/AST/StmtDumper.cpp index 410890c2a3..bd5c615321 100644 --- a/AST/StmtDumper.cpp +++ b/AST/StmtDumper.cpp @@ -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 //===----------------------------------------------------------------------===// diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index 9b4ad11ec6..783368ef77 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -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(); diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 3c379621bf..2747254171 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -1318,6 +1318,7 @@ Parser::ExprResult Parser::ParseObjCSelectorExpression() return 0; } + llvm::SmallVector 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 diff --git a/Sema/Sema.cpp b/Sema/Sema.cpp index 330d9dce74..dc68eb03d8 100644 --- a/Sema/Sema.cpp +++ b/Sema/Sema.cpp @@ -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(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 &prevInGroup) : PP(pp), Context(ctxt), CurFunctionDecl(0), LastInGroupList(prevInGroup) { diff --git a/Sema/Sema.h b/Sema/Sema.h index c45bbf8e5d..9d587791b4 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -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, diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index daa1a7c141..082b7182b9 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -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(). diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index b88c381faa..75d938806b 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -742,6 +742,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; + compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index bf0bf55123..ec9b91b3ae 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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; } diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 5496508cd7..0e0bdbb2ce 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -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 }; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 5c4743faa9..76eb849139 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -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 diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index bad641962b..2443be892f 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -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, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index a5e6875c3d..fdd30c0eb9 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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 index 0000000000..59717c3079 --- /dev/null +++ b/test/Sema/selector-1.m @@ -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:); +}