From: Fariborz Jahanian Date: Mon, 10 Sep 2007 20:33:04 +0000 (+0000) Subject: Early patch to collect objective-c methods inserts them in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e3a2ca7e30601cdd31c77a830f4cc487851e8096;p=clang Early patch to collect objective-c methods inserts them in class object. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41801 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/Decl.cpp b/AST/Decl.cpp index 5f87d93cbb..0e6c218f2d 100644 --- a/AST/Decl.cpp +++ b/AST/Decl.cpp @@ -163,3 +163,23 @@ FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { } return 0; } + +/// addObjcMethods - Insert instance and methods declarations into +/// ObjcInterfaceDecl's InsMethods and ClsMethods fields. +/// +void ObjcInterfaceDecl::ObjcAddMethods(ObjcMethodDecl **insMethods, + unsigned numInsMembers, + ObjcMethodDecl **clsMethods, + unsigned numClsMembers) { + NumInsMethods = numInsMembers; + if (numInsMembers) { + InsMethods = new ObjcMethodDecl*[numInsMembers]; + memcpy(InsMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*)); + } + NumClsMethods = numClsMembers; + if (numClsMembers) { + ClsMethods = new ObjcMethodDecl*[numClsMembers]; + memcpy(ClsMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*)); + } +} + diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 6557c41652..19594d8991 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -214,13 +214,14 @@ Parser::DeclTy *Parser::ParseObjCAtInterfaceDeclaration( /// @optional /// void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) { + llvm::SmallVector allMethods; while (1) { if (Tok.getKind() == tok::at) { SourceLocation AtLoc = ConsumeToken(); // the "@" tok::ObjCKeywordKind ocKind = Tok.getObjCKeywordID(); if (ocKind == tok::objc_end) { // terminate list - return; + break; } else if (ocKind == tok::objc_required) { // protocols only ConsumeToken(); continue; @@ -236,7 +237,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) { } } if (Tok.getKind() == tok::minus || Tok.getKind() == tok::plus) { - ParseObjCMethodPrototype(interfaceDecl); + allMethods.push_back(ParseObjCMethodPrototype(interfaceDecl)); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for // method definitions. ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "method proto"); @@ -245,13 +246,17 @@ void Parser::ParseObjCInterfaceDeclList(DeclTy *interfaceDecl) { if (Tok.getKind() == tok::semi) ConsumeToken(); else if (Tok.getKind() == tok::eof) - return; + break; else { // FIXME: as the name implies, this rule allows function definitions. // We could pass a flag or check for functions during semantic analysis. ParseDeclarationOrFunctionDefinition(); } } + + /// Insert collected methods declarations into the @interface object. + Actions.ObjcAddMethodsToClass(interfaceDecl, &allMethods[0], allMethods.size()); + return; } /// Parse property attribute declarations. @@ -364,15 +369,6 @@ Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *CDecl) { SourceLocation methodLoc = ConsumeToken(); DeclTy *MDecl = ParseObjCMethodDecl(methodType, methodLoc); - - AttributeList *methodAttrs = 0; - // If attributes exist after the method, parse them. - if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) - methodAttrs = ParseAttributes(); - - if (CDecl) - Actions.ObjcAddMethod(CDecl, MDecl, methodAttrs); - // Since this rule is used for both method declarations and definitions, // the caller is responsible for consuming the ';'. return MDecl; @@ -484,6 +480,7 @@ Parser::TypeTy *Parser::ParseObjCTypeName() { Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc) { TypeTy *ReturnType = 0; + AttributeList *methodAttrs = 0; // Parse the return type. if (Tok.getKind() == tok::l_paren) @@ -491,42 +488,42 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation IdentifierInfo *selIdent = ParseObjCSelector(); llvm::SmallVector KeyInfo; - int KeySlot = 0; if (Tok.getKind() == tok::colon) { while (1) { - KeyInfo[KeySlot].SelectorName = selIdent; + ObjcKeywordInfo KeyInfoDecl; + KeyInfoDecl.SelectorName = selIdent; // Each iteration parses a single keyword argument. if (Tok.getKind() != tok::colon) { Diag(Tok, diag::err_expected_colon); break; } - KeyInfo[KeySlot].ColonLoc = ConsumeToken(); // Eat the ':'. + KeyInfoDecl.ColonLoc = ConsumeToken(); // Eat the ':'. if (Tok.getKind() == tok::l_paren) // Parse the argument type. - KeyInfo[KeySlot].TypeInfo = ParseObjCTypeName(); + KeyInfoDecl.TypeInfo = ParseObjCTypeName(); // If attributes exist before the argument name, parse them. if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) - KeyInfo[KeySlot].AttrList = ParseAttributes(); + KeyInfoDecl.AttrList = ParseAttributes(); if (Tok.getKind() != tok::identifier) { Diag(Tok, diag::err_expected_ident); // missing argument name. break; } - KeyInfo[KeySlot].ArgumentName = Tok.getIdentifierInfo(); + KeyInfoDecl.ArgumentName = Tok.getIdentifierInfo(); ConsumeToken(); // Eat the identifier. // Rather than call out to the actions, try packaging up the info // locally, like we do for Declarator. // FIXME: add Actions.BuildObjCKeyword() + KeyInfo.push_back(KeyInfoDecl); selIdent = ParseObjCSelector(); if (!selIdent && Tok.getKind() != tok::colon) break; // We have a selector or a colon, continue parsing. - KeySlot++; } // Parse the (optional) parameter list. while (Tok.getKind() == tok::comma) { @@ -543,12 +540,21 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation ParseDeclarator(ParmDecl); } // FIXME: Add support for optional parmameter list... + // 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()); + &KeyInfo[0], KeyInfo.size(), + methodAttrs); } else if (!selIdent) { Diag(Tok, diag::err_expected_ident); // missing selector name. } - return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, selIdent); + // If attributes exist after the method, parse them. + if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute) + methodAttrs = ParseAttributes(); + + return Actions.ObjcBuildMethodDeclaration(mLoc, mType, ReturnType, selIdent, + methodAttrs); } /// objc-protocol-refs: diff --git a/Sema/Sema.h b/Sema/Sema.h index cabaae92c0..f0a072eb9b 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -156,6 +156,8 @@ private: Declarator &D, ExprTy *BitfieldWidth); virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl, DeclTy **Fields, unsigned NumFields); + virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl, + DeclTy **allMethods, unsigned allNum); virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl, DeclTy *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 50cde4e410..3315f38b0f 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -1140,6 +1140,30 @@ void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl, Record->defineBody(&RecFields[0], RecFields.size()); } +void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl, + DeclTy **allMethods, unsigned allNum) { + // FIXME: Add method insertion code here. +#if 0 + ObjcInterfaceDecl *Interface = cast( + static_cast(ClassDecl)); + llvm::SmallVector insMethods; + llvm::SmallVector clsMethods; + + for (unsigned i = 0; i < allNum; i++ ) { + ObjcMethodDecl *Method = + cast_or_null(static_cast(allMethods[i])); + if (!Method) continue; // Already issued a diagnostic. + if (Method->isInstance()) + insMethods.push_back(Method); + else + clsMethods.push_back(Method); + } + Interface->ObjcAddMethods(&insMethods[0], insMethods.size(), + &clsMethods[0], clsMethods.size()); +#endif + return; +} + Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *theEnumDecl, DeclTy *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index c588aba643..838bad4b5f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -23,6 +23,8 @@ class IdentifierInfo; class Expr; class Stmt; class FunctionDecl; +class ObjcMethodDecl; +class AttributeList; /// Decl - This represents one declaration (or definition), e.g. a variable, @@ -34,7 +36,7 @@ public: // Concrete sub-classes of ValueDecl Function, BlockVariable, FileVariable, ParmVariable, EnumConstant, // Concrete sub-classes of TypeDecl - Typedef, Struct, Union, Class, Enum, ObjcInterface, ObjcClass, + Typedef, Struct, Union, Class, Enum, ObjcInterface, ObjcClass, ObjcMethod, // Concrete sub-class of Decl Field }; @@ -508,13 +510,25 @@ class ObjcInterfaceDecl : public TypeDecl { FieldDecl **Ivars; // Null if not defined. int NumIvars; // -1 if not defined. + /// instance methods + ObjcMethodDecl **InsMethods; // Null if not defined + int NumInsMethods; // -1 if not defined + + /// class methods + ObjcMethodDecl **ClsMethods; // Null if not defined + int NumClsMethods; // -1 if not defined + bool isForwardDecl; // declared with @class. public: ObjcInterfaceDecl(SourceLocation L, IdentifierInfo *Id, bool FD = false) - : TypeDecl(ObjcInterface, L, Id, 0), Ivars(0), NumIvars(-1), + : TypeDecl(ObjcInterface, L, Id, 0), Ivars(0), NumIvars(-1), + InsMethods(0), NumInsMethods(-1), ClsMethods(0), NumClsMethods(-1), isForwardDecl(FD) { } void addInstanceVariable(FieldDecl ivar); + + void ObjcAddMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers, + ObjcMethodDecl **clsMethods, unsigned numClsMembers); static bool classof(const Decl *D) { return D->getKind() == ObjcInterface; @@ -544,6 +558,43 @@ public: static bool classof(const ObjcClassDecl *D) { return true; } }; -} // end namespace clang +/// ObjcMethodDecl - An instance of this class is created to represent an instance +/// or class method declaration. +class ObjcMethodDecl : public ValueDecl { +public: + ObjcMethodDecl(SourceLocation L, IdentifierInfo *Id, QualType T, + bool isInstance = true, Decl *PrevDecl = 0) + : ValueDecl(ObjcMethod, L, Id, T, PrevDecl), ParamInfo(0), + MethodAttrs(0), IsInstance(isInstance) {} + + virtual ~ObjcMethodDecl(); + unsigned getNumParams() const; + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams); + bool isInstance() const { return IsInstance; } + QualType getResultType() const { return getType(); } + + void setMethodAttrs(AttributeList *attrs) {MethodAttrs = attrs;} + AttributeList *getMethodAttrs() const {return MethodAttrs;} + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return D->getKind() == ObjcMethod; } + static bool classof(const ObjcMethodDecl *D) { return true; } + +private: + /// ParamInfo - new[]'d array of pointers to VarDecls for the formal + /// parameters of this Method. This is null if there are no formals. + ParmVarDecl **ParamInfo; + + /// List of attributes for this method declaration. + AttributeList *MethodAttrs; + + bool IsInstance : 1; +}; + +} // end namespace clang #endif diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 5d0262fdb3..1be6503a11 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -174,6 +174,9 @@ public: virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl, DeclTy **Fields, unsigned NumFields) {} + virtual void ObjcAddMethodsToClass(DeclTy *ClassDecl, + DeclTy **allMethods, unsigned allNum) {} + virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl, DeclTy *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, @@ -450,12 +453,13 @@ public: } virtual DeclTy *ObjcBuildMethodDeclaration( SourceLocation MethodLoc, tok::TokenKind MethodType, TypeTy *ReturnType, - ObjcKeywordInfo *Keywords, unsigned NumKeywords) { + ObjcKeywordInfo *Keywords, unsigned NumKeywords, + AttributeList *AttrList) { return 0; } virtual DeclTy *ObjcBuildMethodDeclaration( SourceLocation MethodLoc, tok::TokenKind MethodType, TypeTy *ReturnType, - IdentifierInfo *SelectorName) { + IdentifierInfo *SelectorName, AttributeList *AttrList) { return 0; } virtual void ObjCStartCategoryInterface() { // FIXME diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 40e51bf75d..7d5cd1a637 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -288,7 +288,7 @@ private: TypeTy *ParseObjCTypeName(); void ParseObjCMethodRequirement(); - DeclTy *ParseObjCMethodPrototype(DeclTy *classOrCat); + DeclTy *ParseObjCMethodPrototype(DeclTy *classOrCat); DeclTy *ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc); void ParseObjCPropertyAttribute(DeclTy *interfaceDecl); void ParseObjCPropertyDecl(DeclTy *interfaceDecl);