From 390d50a725497e99247dc104a7d2c2a255d3af14 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 17 Oct 2007 16:58:11 +0000 Subject: [PATCH] Implementation of AST for @protocol expression. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43075 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/ASTContext.cpp | 11 +++++++++ AST/Expr.cpp | 4 ++++ AST/StmtDumper.cpp | 8 +++++++ AST/StmtPrinter.cpp | 7 ++++++ Parse/ParseObjc.cpp | 7 +++--- Sema/Sema.cpp | 18 ++++++++++++++ Sema/Sema.h | 10 ++++++++ Sema/SemaExpr.cpp | 14 +++++++++++ include/clang/AST/ASTContext.h | 7 ++++++ include/clang/AST/Expr.h | 31 ++++++++++++++++++++++++- include/clang/AST/StmtNodes.def | 3 ++- include/clang/Basic/DiagnosticKinds.def | 2 ++ include/clang/Parse/Action.h | 7 ++++++ test/Sema/protocol-expr-1.m | 17 ++++++++++++++ test/Sema/protocol-expr-neg-1.m | 19 +++++++++++++++ 15 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 test/Sema/protocol-expr-1.m create mode 100644 test/Sema/protocol-expr-neg-1.m diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index 4c06e7c88c..cf617d190e 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -870,6 +870,17 @@ void ASTContext::setObjcSelType(TypedefDecl *TD) SelStructType = rec; } +void ASTContext::setObjcProtoType(TypedefDecl *TD) +{ + assert(ObjcProtoType.isNull() && "'Protocol' type already set!"); + + // typedef struct Protocol Protocol; + ObjcProtoType = TD->getUnderlyingType(); + // Protocol * type + ObjcProtoType = getPointerType(ObjcProtoType); + ProtoStructType = TD->getUnderlyingType()->getAsStructureType(); +} + void ASTContext::setObjcConstantStringInterface(ObjcInterfaceDecl *Decl) { assert(ObjcConstantStringType.isNull() && "'NSConstantString' type already set!"); diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 1b989a4a61..d69133258a 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -1084,6 +1084,10 @@ Stmt::child_iterator ObjCEncodeExpr::child_end() { return NULL; } Stmt::child_iterator ObjCSelectorExpr::child_begin() { return NULL; } Stmt::child_iterator ObjCSelectorExpr::child_end() { return NULL; } +// ObjCProtocolExpr +Stmt::child_iterator ObjCProtocolExpr::child_begin() { return NULL; } +Stmt::child_iterator ObjCProtocolExpr::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 39d2effd5a..62886981b2 100644 --- a/AST/StmtDumper.cpp +++ b/AST/StmtDumper.cpp @@ -14,6 +14,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclObjc.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceManager.h" @@ -129,6 +130,7 @@ namespace { // ObjC void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); }; } @@ -415,6 +417,12 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { fprintf(F, "%s", selector.getName().c_str()); } +void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + fprintf(F, "%s", Node->getProtocol()->getName()); +} //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index a19ad37a0c..90c5ef2159 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -14,6 +14,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclObjc.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/IdentifierTable.h" @@ -627,6 +628,12 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { OS << ")"; } +void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + OS << "@protocol("; + OS << Node->getProtocol()->getName(); + OS << ")"; +} + void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << "["; Expr *receiver = Mess->getReceiver(); diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 0b6f303a48..f7ab990d29 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -1297,14 +1297,13 @@ Parser::ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) Diag(Tok, diag::err_expected_ident); return true; } - - // FIXME: Do something with the protocol name + IdentifierInfo *protocolId = Tok.getIdentifierInfo(); ConsumeToken(); SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - // FIXME - return 0; + return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc, + LParenLoc, RParenLoc); } /// objc-selector-expression diff --git a/Sema/Sema.cpp b/Sema/Sema.cpp index dc68eb03d8..5bd5df5539 100644 --- a/Sema/Sema.cpp +++ b/Sema/Sema.cpp @@ -63,6 +63,24 @@ QualType Sema::GetObjcSelType(SourceLocation Loc) { return Context.getObjcSelType(); } +/// GetObjcProtoType - See comments for Sema::GetObjcIdType above; replace "id" +/// with "Protocol". +QualType Sema::GetObjcProtoType(SourceLocation Loc) { + assert(TUScope && "GetObjcProtoType(): Top-level scope is null"); + if (Context.getObjcProtoType().isNull()) { + IdentifierInfo *ProtoIdent = &Context.Idents.get("Protocol"); + ScopedDecl *ProtoDecl = LookupScopedDecl(ProtoIdent, Decl::IDNS_Ordinary, + SourceLocation(), TUScope); + TypedefDecl *ObjcProtoTypedef = dyn_cast_or_null(ProtoDecl); + if (!ObjcProtoTypedef) { + Diag(Loc, diag::err_missing_proto_definition); + return QualType(); + } + Context.setObjcProtoType(ObjcProtoTypedef); + } + return Context.getObjcProtoType(); +} + 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 abe9250f04..596173dda2 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -280,6 +280,9 @@ private: /// GetObjcSelType - Getter for the build-in "SEL" type. QualType GetObjcSelType(SourceLocation Loc = SourceLocation()); + /// GetObjcSelType - Getter for the build-in "Protocol *" type. + QualType GetObjcProtoType(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 @@ -452,6 +455,13 @@ public: SourceLocation LParenLoc, SourceLocation RParenLoc); + // ParseObjCProtocolExpression - Build protocol expression for @protocol + virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + // Objective-C declarations. virtual DeclTy *ActOnStartClassInterface( SourceLocation AtInterafceLoc, diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index a6a47adddb..6aebd1626a 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1929,6 +1929,20 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc); } +Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + ObjcProtocolDecl* PDecl = ObjcProtocols[ProtocolId]; + if (!PDecl) { + Diag(ProtoLoc, diag::err_undeclared_protocol, ProtocolId->getName()); + return true; + } + + QualType t = GetObjcProtoType(AtLoc); + return new ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc); +} bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, ObjcMethodDecl *Method) { diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index ec9b91b3ae..3881b6316b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -54,6 +54,10 @@ class ASTContext { QualType ObjcSelType; const RecordType *SelStructType; + /// ObjcProtoType - another psuedo built-in typedef type (set by Sema). + QualType ObjcProtoType; + const RecordType *ProtoStructType; + QualType ObjcConstantStringType; RecordDecl *CFConstantStringTypeDecl; public: @@ -175,6 +179,9 @@ public: void setObjcSelType(TypedefDecl *Decl); QualType getObjcSelType() const { return ObjcSelType; } + void setObjcProtoType(TypedefDecl *Decl); + QualType getObjcProtoType() const { return ObjcProtoType; } + void setBuiltinVaListType(QualType T); QualType getBuiltinVaListType() const { return BuiltinVaListType; } diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 64e47b4fe0..99f1775195 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1119,7 +1119,7 @@ public: static bool classof(const Stmt *T) { return T->getStmtClass() == ObjCSelectorExprClass; } - static bool classof(const ObjCEncodeExpr *) { return true; } + static bool classof(const ObjCSelectorExpr *) { return true; } // Iterators virtual child_iterator child_begin(); @@ -1127,6 +1127,35 @@ public: }; +/// ObjCProtocolExpr used for protocol in Objective-C. +class ObjCProtocolExpr : public Expr { + + ObjcProtocolDecl *Protocol; + + SourceLocation AtLoc, RParenLoc; + public: + ObjCProtocolExpr(QualType T, ObjcProtocolDecl *protocol, + SourceLocation at, SourceLocation rp) + : Expr(ObjCProtocolExprClass, T), Protocol(protocol), + AtLoc(at), RParenLoc(rp) {} + + ObjcProtocolDecl *getProtocol() const { return Protocol; } + + SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + SourceRange getSourceRange() const { return SourceRange(AtLoc, RParenLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCProtocolExprClass; + } + static bool classof(const ObjCProtocolExpr *) { 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 76eb849139..c8b822139c 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -83,8 +83,9 @@ STMT(70, ObjCStringLiteral , Expr) STMT(71, ObjCEncodeExpr , Expr) STMT(72, ObjCMessageExpr , Expr) STMT(73, ObjCSelectorExpr , Expr) +STMT(74, ObjCProtocolExpr , Expr) -LAST_EXPR(73) +LAST_EXPR(74) #undef STMT #undef FIRST_STMT diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index eae6c22b88..6581e5d7ed 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -448,6 +448,8 @@ DIAG(err_missing_sel_definition, ERROR, "cannot find definition of 'SEL'") DIAG(err_missing_id_definition, ERROR, "cannot find definition of 'id'") +DIAG(err_missing_proto_definition, ERROR, + "cannot find definition of 'Protocol'") DIAG(warn_previous_alias_decl, WARNING, "previously declared alias is ignored") DIAG(warn_previous_declaration, WARNING, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index d68850582f..e8c943d624 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -603,6 +603,13 @@ public: return 0; } + virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return 0; + } }; /// MinimalAction - Minimal actions are used by light-weight clients of the diff --git a/test/Sema/protocol-expr-1.m b/test/Sema/protocol-expr-1.m new file mode 100644 index 0000000000..23cb5dd903 --- /dev/null +++ b/test/Sema/protocol-expr-1.m @@ -0,0 +1,17 @@ +// RUN: clang -fsyntax-only -verify %s + +typedef struct Protocol Protocol; + +@protocol fproto; + +@protocol p1 +@end + +@class cl; + +int main() +{ + Protocol *proto = @protocol(p1); + Protocol *fproto = @protocol(fproto); +} + diff --git a/test/Sema/protocol-expr-neg-1.m b/test/Sema/protocol-expr-neg-1.m new file mode 100644 index 0000000000..d59d83fd78 --- /dev/null +++ b/test/Sema/protocol-expr-neg-1.m @@ -0,0 +1,19 @@ +// RUN: clang -fsyntax-only -verify %s + +typedef struct Protocol Protocol; + +@protocol fproto; + +@protocol p1 +@end + +@class cl; + +int main() +{ + Protocol *proto = @protocol(p1); + Protocol *fproto = @protocol(fproto); + Protocol *pp = @protocol(i); // expected-error {{cannot find protocol declaration for 'i'}} + Protocol *p1p = @protocol(cl); // expected-error {{cannot find protocol declaration for 'cl'}} +} + -- 2.40.0