| //===--- Decl.cpp - Declaration AST Node Implementation -------------------===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file was developed by Chris Lattner and is distributed under | 
 | // the University of Illinois Open Source License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This file implements the Decl class and subclasses. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "clang/AST/Decl.h" | 
 | #include "clang/AST/DeclObjC.h" | 
 | #include "clang/Basic/IdentifierTable.h" | 
 | using namespace clang; | 
 |  | 
 | // temporary statistics gathering | 
 | static unsigned nFuncs = 0; | 
 | static unsigned nBlockVars = 0; | 
 | static unsigned nFileVars = 0; | 
 | static unsigned nParmVars = 0; | 
 | static unsigned nSUC = 0; | 
 | static unsigned nEnumConst = 0; | 
 | static unsigned nEnumDecls = 0; | 
 | static unsigned nTypedef = 0; | 
 | static unsigned nFieldDecls = 0; | 
 | static unsigned nInterfaceDecls = 0; | 
 | static unsigned nClassDecls = 0; | 
 | static unsigned nMethodDecls = 0; | 
 | static unsigned nProtocolDecls = 0; | 
 | static unsigned nForwardProtocolDecls = 0; | 
 | static unsigned nCategoryDecls = 0; | 
 | static unsigned nIvarDecls = 0; | 
 | static unsigned nObjcImplementationDecls = 0; | 
 | static unsigned nObjcCategoryImpl = 0; | 
 | static unsigned nObjcCompatibleAlias = 0; | 
 |  | 
 | static bool StatSwitch = false; | 
 |  | 
 | const char *Decl::getDeclKindName() const { | 
 |   switch (DeclKind) { | 
 |   default: assert(0 && "Unknown decl kind!"); | 
 |   case Typedef: | 
 |     return "Typedef"; | 
 |   case Function: | 
 |     return "Function"; | 
 |   case BlockVar: | 
 |     return "BlockVar"; | 
 |   case FileVar: | 
 |     return "FileVar"; | 
 |   case ParmVar: | 
 |     return "ParmVar"; | 
 |   case EnumConstant: | 
 |     return "EnumConstant"; | 
 |   case ObjcInterface: | 
 |     return "ObjcInterface"; | 
 |   case ObjcClass: | 
 |     return "ObjcClass"; | 
 |   case ObjcMethod: | 
 |     return "ObjcMethod"; | 
 |   case ObjcProtocol: | 
 |     return "ObjcProtocol"; | 
 |   case ObjcForwardProtocol: | 
 |     return "ObjcForwardProtocol";  | 
 |   case Struct: | 
 |     return "Struct"; | 
 |   case Union: | 
 |     return "Union"; | 
 |   case Class: | 
 |     return "Class"; | 
 |   case Enum: | 
 |     return "Enum"; | 
 |   } | 
 | } | 
 |  | 
 | bool Decl::CollectingStats(bool enable) { | 
 |   if (enable) StatSwitch = true; | 
 |     return StatSwitch; | 
 | } | 
 |  | 
 | void Decl::PrintStats() { | 
 |   fprintf(stderr, "*** Decl Stats:\n"); | 
 |   fprintf(stderr, "  %d decls total.\n",  | 
 | 	  int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+ | 
 | 	      nEnumDecls+nEnumConst+nTypedef+nInterfaceDecls+nClassDecls+ | 
 | 	      nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls)); | 
 |   fprintf(stderr, "    %d function decls, %d each (%d bytes)\n",  | 
 | 	  nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl))); | 
 |   fprintf(stderr, "    %d block variable decls, %d each (%d bytes)\n",  | 
 | 	  nBlockVars, (int)sizeof(BlockVarDecl),  | 
 | 	  int(nBlockVars*sizeof(BlockVarDecl))); | 
 |   fprintf(stderr, "    %d file variable decls, %d each (%d bytes)\n",  | 
 | 	  nFileVars, (int)sizeof(FileVarDecl),  | 
 | 	  int(nFileVars*sizeof(FileVarDecl))); | 
 |   fprintf(stderr, "    %d parameter variable decls, %d each (%d bytes)\n",  | 
 | 	  nParmVars, (int)sizeof(ParmVarDecl), | 
 | 	  int(nParmVars*sizeof(ParmVarDecl))); | 
 |   fprintf(stderr, "    %d field decls, %d each (%d bytes)\n",  | 
 | 	  nFieldDecls, (int)sizeof(FieldDecl), | 
 | 	  int(nFieldDecls*sizeof(FieldDecl))); | 
 |   fprintf(stderr, "    %d struct/union/class decls, %d each (%d bytes)\n",  | 
 | 	  nSUC, (int)sizeof(RecordDecl), | 
 | 	  int(nSUC*sizeof(RecordDecl))); | 
 |   fprintf(stderr, "    %d enum decls, %d each (%d bytes)\n",  | 
 | 	  nEnumDecls, (int)sizeof(EnumDecl),  | 
 | 	  int(nEnumDecls*sizeof(EnumDecl))); | 
 |   fprintf(stderr, "    %d enum constant decls, %d each (%d bytes)\n",  | 
 | 	  nEnumConst, (int)sizeof(EnumConstantDecl), | 
 | 	  int(nEnumConst*sizeof(EnumConstantDecl))); | 
 |   fprintf(stderr, "    %d typedef decls, %d each (%d bytes)\n",  | 
 | 	  nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl))); | 
 |   // Objective-C decls... | 
 |   fprintf(stderr, "    %d interface decls, %d each (%d bytes)\n",  | 
 | 	  nInterfaceDecls, (int)sizeof(ObjcInterfaceDecl), | 
 | 	  int(nInterfaceDecls*sizeof(ObjcInterfaceDecl))); | 
 |   fprintf(stderr, "    %d instance variable decls, %d each (%d bytes)\n",  | 
 | 	  nIvarDecls, (int)sizeof(ObjcIvarDecl), | 
 | 	  int(nIvarDecls*sizeof(ObjcIvarDecl))); | 
 |   fprintf(stderr, "    %d class decls, %d each (%d bytes)\n",  | 
 | 	  nClassDecls, (int)sizeof(ObjcClassDecl), | 
 | 	  int(nClassDecls*sizeof(ObjcClassDecl))); | 
 |   fprintf(stderr, "    %d method decls, %d each (%d bytes)\n",  | 
 | 	  nMethodDecls, (int)sizeof(ObjcMethodDecl), | 
 | 	  int(nMethodDecls*sizeof(ObjcMethodDecl))); | 
 |   fprintf(stderr, "    %d protocol decls, %d each (%d bytes)\n",  | 
 | 	  nProtocolDecls, (int)sizeof(ObjcProtocolDecl), | 
 | 	  int(nProtocolDecls*sizeof(ObjcProtocolDecl))); | 
 |   fprintf(stderr, "    %d forward protocol decls, %d each (%d bytes)\n",  | 
 | 	  nForwardProtocolDecls, (int)sizeof(ObjcForwardProtocolDecl), | 
 | 	  int(nForwardProtocolDecls*sizeof(ObjcForwardProtocolDecl))); | 
 |   fprintf(stderr, "    %d category decls, %d each (%d bytes)\n",  | 
 | 	  nCategoryDecls, (int)sizeof(ObjcCategoryDecl), | 
 | 	  int(nCategoryDecls*sizeof(ObjcCategoryDecl))); | 
 |  | 
 |   fprintf(stderr, "    %d class implementation decls, %d each (%d bytes)\n",  | 
 | 	  nObjcImplementationDecls, (int)sizeof(ObjcImplementationDecl), | 
 | 	  int(nObjcImplementationDecls*sizeof(ObjcImplementationDecl))); | 
 |  | 
 |   fprintf(stderr, "    %d class implementation decls, %d each (%d bytes)\n",  | 
 | 	  nObjcCategoryImpl, (int)sizeof(ObjcCategoryImplDecl), | 
 | 	  int(nObjcCategoryImpl*sizeof(ObjcCategoryImplDecl))); | 
 |  | 
 |   fprintf(stderr, "    %d compatibility alias decls, %d each (%d bytes)\n",  | 
 | 	  nObjcCompatibleAlias, (int)sizeof(ObjcCompatibleAliasDecl), | 
 | 	  int(nObjcCompatibleAlias*sizeof(ObjcCompatibleAliasDecl))); | 
 |    | 
 |   fprintf(stderr, "Total bytes = %d\n",  | 
 | 	  int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+ | 
 | 	      nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+ | 
 | 	      nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+ | 
 | 	      nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+ | 
 | 	      nTypedef*sizeof(TypedefDecl)) /* FIXME: add Objc decls */); | 
 | } | 
 |  | 
 | void Decl::addDeclKind(const Kind k) { | 
 |   switch (k) { | 
 |     case Typedef: | 
 |       nTypedef++; | 
 |       break; | 
 |     case Function: | 
 |       nFuncs++; | 
 |       break; | 
 |     case BlockVar: | 
 |       nBlockVars++; | 
 |       break; | 
 |     case FileVar: | 
 |       nFileVars++; | 
 |       break; | 
 |     case ParmVar: | 
 |       nParmVars++; | 
 |       break; | 
 |     case EnumConstant: | 
 |       nEnumConst++; | 
 |       break; | 
 |     case Field: | 
 |       nFieldDecls++; | 
 |       break; | 
 |     case Struct: | 
 |     case Union: | 
 |     case Class: | 
 |       nSUC++; | 
 |       break; | 
 |     case Enum: | 
 |       nEnumDecls++; | 
 |       break; | 
 |     case ObjcInterface: | 
 |       nInterfaceDecls++; | 
 |       break; | 
 |     case ObjcClass: | 
 |       nClassDecls++; | 
 |       break; | 
 |     case ObjcMethod: | 
 |       nMethodDecls++; | 
 |       break; | 
 |     case ObjcProtocol: | 
 |       nProtocolDecls++; | 
 |       break; | 
 |     case ObjcForwardProtocol: | 
 |       nForwardProtocolDecls++; | 
 |       break; | 
 |     case ObjcCategory: | 
 |      nCategoryDecls++; | 
 |      break; | 
 |     case ObjcIvar: | 
 |       nIvarDecls++; | 
 |       break; | 
 |     case ObjcImplementation:  | 
 |       nObjcImplementationDecls++; | 
 |       break; | 
 |     case ObjcCategoryImpl: | 
 |       nObjcCategoryImpl++; | 
 |       break; | 
 |     case CompatibleAlias: | 
 |       nObjcCompatibleAlias++; | 
 |       break; | 
 |   } | 
 | } | 
 |  | 
 | // Out-of-line virtual method providing a home for Decl. | 
 | Decl::~Decl() { | 
 | } | 
 |  | 
 | const char *NamedDecl::getName() const { | 
 |   if (const IdentifierInfo *II = getIdentifier()) | 
 |     return II->getName(); | 
 |   return ""; | 
 | } | 
 |  | 
 |  | 
 | FunctionDecl::~FunctionDecl() { | 
 |   delete[] ParamInfo; | 
 | } | 
 |  | 
 | unsigned FunctionDecl::getNumParams() const { | 
 |   return cast<FunctionTypeProto>(getType().getTypePtr())->getNumArgs(); | 
 | } | 
 |  | 
 | void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { | 
 |   assert(ParamInfo == 0 && "Already has param info!"); | 
 |   assert(NumParams == getNumParams() && "Parameter count mismatch!"); | 
 |    | 
 |   // Zero params -> null pointer. | 
 |   if (NumParams) { | 
 |     ParamInfo = new ParmVarDecl*[NumParams]; | 
 |     memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); | 
 |   } | 
 | } | 
 |  | 
 |  | 
 | /// defineBody - When created, RecordDecl's correspond to a forward declared | 
 | /// record.  This method is used to mark the decl as being defined, with the | 
 | /// specified contents. | 
 | void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) { | 
 |   assert(!isDefinition() && "Cannot redefine record!"); | 
 |   setDefinition(true); | 
 |   NumMembers = numMembers; | 
 |   if (numMembers) { | 
 |     Members = new FieldDecl*[numMembers]; | 
 |     memcpy(Members, members, numMembers*sizeof(Decl*)); | 
 |   } | 
 | } | 
 |  | 
 | FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { | 
 |   if (Members == 0 || NumMembers < 0) | 
 |     return 0; | 
 |    | 
 |   // linear search. When C++ classes come along, will likely need to revisit. | 
 |   for (int i = 0; i < NumMembers; ++i) { | 
 |     if (Members[i]->getIdentifier() == name) | 
 |       return Members[i]; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | void ObjcMethodDecl::setMethodParams(ParmVarDecl **NewParamInfo, | 
 |                                      unsigned NumParams) { | 
 |   assert(ParamInfo == 0 && "Already has param info!"); | 
 |  | 
 |   // Zero params -> null pointer. | 
 |   if (NumParams) { | 
 |     ParamInfo = new ParmVarDecl*[NumParams]; | 
 |     memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); | 
 |     NumMethodParams = NumParams; | 
 |   } | 
 | } | 
 |  | 
 | ObjcMethodDecl::~ObjcMethodDecl() { | 
 |   delete[] ParamInfo; | 
 | } | 
 |  | 
 | /// ObjcAddInstanceVariablesToClass - Inserts instance variables | 
 | /// into ObjcInterfaceDecl's fields. | 
 | /// | 
 | void ObjcInterfaceDecl::ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, | 
 |                                                         unsigned numIvars) { | 
 |   NumIvars = numIvars; | 
 |   if (numIvars) { | 
 |     Ivars = new ObjcIvarDecl*[numIvars]; | 
 |     memcpy(Ivars, ivars, numIvars*sizeof(ObjcIvarDecl*)); | 
 |   } | 
 | } | 
 |  | 
 | /// ObjcAddInstanceVariablesToClassImpl - Checks for correctness of Instance  | 
 | /// Variables (Ivars) relative to what declared in @implementation;s class.  | 
 | /// Ivars into ObjcImplementationDecl's fields. | 
 | /// | 
 | void ObjcImplementationDecl::ObjcAddInstanceVariablesToClassImpl( | 
 |                                ObjcIvarDecl **ivars, unsigned numIvars) { | 
 |   NumIvars = numIvars; | 
 |   if (numIvars) { | 
 |     Ivars = new ObjcIvarDecl*[numIvars]; | 
 |     memcpy(Ivars, ivars, numIvars*sizeof(ObjcIvarDecl*)); | 
 |   } | 
 | } | 
 |  | 
 | /// addObjcMethods - Insert instance and methods declarations into | 
 | /// ObjcInterfaceDecl's InsMethods and ClsMethods fields. | 
 | /// | 
 | void ObjcInterfaceDecl::ObjcAddMethods(ObjcMethodDecl **insMethods,  | 
 |                                        unsigned numInsMembers, | 
 |                                        ObjcMethodDecl **clsMethods, | 
 |                                        unsigned numClsMembers) { | 
 |   NumInstanceMethods = numInsMembers; | 
 |   if (numInsMembers) { | 
 |     InstanceMethods = new ObjcMethodDecl*[numInsMembers]; | 
 |     memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 |   NumClassMethods = numClsMembers; | 
 |   if (numClsMembers) { | 
 |     ClassMethods = new ObjcMethodDecl*[numClsMembers]; | 
 |     memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 | } | 
 |  | 
 | /// ObjcAddProtoMethods - Insert instance and methods declarations into | 
 | /// ObjcProtocolDecl's ProtoInsMethods and ProtoClsMethods fields. | 
 | /// | 
 | void ObjcProtocolDecl::ObjcAddProtoMethods(ObjcMethodDecl **insMethods,  | 
 |                                            unsigned numInsMembers, | 
 |                                            ObjcMethodDecl **clsMethods, | 
 |                                            unsigned numClsMembers) { | 
 |   NumInstanceMethods = numInsMembers; | 
 |   if (numInsMembers) { | 
 |     InstanceMethods = new ObjcMethodDecl*[numInsMembers]; | 
 |     memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 |   NumClassMethods = numClsMembers; | 
 |   if (numClsMembers) { | 
 |     ClassMethods = new ObjcMethodDecl*[numClsMembers]; | 
 |     memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 | } | 
 |  | 
 | /// ObjcAddCat - Insert instance and methods declarations into | 
 | /// ObjcCategoryDecl's CatInsMethods and CatClsMethods fields. | 
 | /// | 
 | void ObjcCategoryDecl::ObjcAddCatMethods(ObjcMethodDecl **insMethods,  | 
 |                                          unsigned numInsMembers, | 
 |                                          ObjcMethodDecl **clsMethods, | 
 |                                          unsigned numClsMembers) { | 
 |   NumInstanceMethods = numInsMembers; | 
 |   if (numInsMembers) { | 
 |     InstanceMethods = new ObjcMethodDecl*[numInsMembers]; | 
 |     memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 |   NumClassMethods = numClsMembers; | 
 |   if (numClsMembers) { | 
 |     ClassMethods = new ObjcMethodDecl*[numClsMembers]; | 
 |     memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 | } | 
 |  | 
 | /// ObjcAddCatImplMethods - Insert instance and methods declarations into | 
 | /// ObjcCategoryImplDecl's CatInsMethods and CatClsMethods fields. | 
 | /// | 
 | void ObjcCategoryImplDecl::ObjcAddCatImplMethods(ObjcMethodDecl **insMethods,  | 
 |                                                  unsigned numInsMembers, | 
 |                                                  ObjcMethodDecl **clsMethods, | 
 |                                                  unsigned numClsMembers) { | 
 |   NumInstanceMethods = numInsMembers; | 
 |   if (numInsMembers) { | 
 |     InstanceMethods = new ObjcMethodDecl*[numInsMembers]; | 
 |     memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 |   NumClassMethods = numClsMembers; | 
 |   if (numClsMembers) { | 
 |     ClassMethods = new ObjcMethodDecl*[numClsMembers]; | 
 |     memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 | } | 
 |  | 
 | /// ObjcAddImplMethods - Insert instance and methods declarations into | 
 | /// ObjcImplementationDecl's InsMethods and ClsMethods fields. | 
 | /// | 
 | void ObjcImplementationDecl::ObjcAddImplMethods(ObjcMethodDecl **insMethods,  | 
 |                                                 unsigned numInsMembers, | 
 |                                                 ObjcMethodDecl **clsMethods, | 
 |                                                 unsigned numClsMembers) { | 
 |   NumInstanceMethods = numInsMembers; | 
 |   if (numInsMembers) { | 
 |     InstanceMethods = new ObjcMethodDecl*[numInsMembers]; | 
 |     memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 |   NumClassMethods = numClsMembers; | 
 |   if (numClsMembers) { | 
 |     ClassMethods = new ObjcMethodDecl*[numClsMembers]; | 
 |     memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*)); | 
 |   } | 
 | } | 
 |  | 
 | // lookupInstanceMethod - This method returns an instance method by looking in | 
 | // the class, it's categories, and it's super classes (using a linear search). | 
 | ObjcMethodDecl *ObjcInterfaceDecl::lookupInstanceMethod(Selector &Sel) { | 
 |   ObjcInterfaceDecl* ClassDecl = this; | 
 |   while (ClassDecl != NULL) { | 
 |     ObjcMethodDecl **methods = ClassDecl->getInstanceMethods(); | 
 |     int methodCount = ClassDecl->getNumInstanceMethods(); | 
 |     for (int i = 0; i < methodCount; ++i) { | 
 |       if (methods[i]->getSelector() == Sel) { | 
 |         return methods[i]; | 
 |       } | 
 |     } | 
 |     // Didn't find one yet - look through protocols. | 
 |     ObjcProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); | 
 |     int numProtocols = ClassDecl->getNumIntfRefProtocols(); | 
 |     for (int pIdx = 0; pIdx < numProtocols; pIdx++) { | 
 |       ObjcMethodDecl **methods = protocols[pIdx]->getInstanceMethods(); | 
 |       int methodCount = protocols[pIdx]->getNumInstanceMethods(); | 
 |       for (int i = 0; i < methodCount; ++i) { | 
 |         if (methods[i]->getSelector() == Sel) { | 
 |           return methods[i]; | 
 |         } | 
 |       } | 
 |     } | 
 |     // Didn't find one yet - now look through categories. | 
 |     ObjcCategoryDecl *CatDecl = ClassDecl->getCategoryList(); | 
 |     while (CatDecl) { | 
 |       ObjcMethodDecl **methods = CatDecl->getInstanceMethods(); | 
 |       int methodCount = CatDecl->getNumInstanceMethods(); | 
 |       for (int i = 0; i < methodCount; ++i) { | 
 |         if (methods[i]->getSelector() == Sel) { | 
 |           return methods[i]; | 
 |         } | 
 |       } | 
 |       CatDecl = CatDecl->getNextClassCategory(); | 
 |     } | 
 |     ClassDecl = ClassDecl->getSuperClass(); | 
 |   } | 
 |   return NULL; | 
 | } | 
 |  | 
 | // lookupClassMethod - This method returns a class method by looking in the | 
 | // class, it's categories, and it's super classes (using a linear search). | 
 | ObjcMethodDecl *ObjcInterfaceDecl::lookupClassMethod(Selector &Sel) { | 
 |   ObjcInterfaceDecl* ClassDecl = this; | 
 |   while (ClassDecl != NULL) { | 
 |     ObjcMethodDecl **methods = ClassDecl->getClassMethods(); | 
 |     int methodCount = ClassDecl->getNumClassMethods(); | 
 |     for (int i = 0; i < methodCount; ++i) { | 
 |       if (methods[i]->getSelector() == Sel) { | 
 |         return methods[i]; | 
 |       } | 
 |     } | 
 |     // Didn't find one yet - look through protocols. | 
 |     ObjcProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); | 
 |     int numProtocols = ClassDecl->getNumIntfRefProtocols(); | 
 |     for (int pIdx = 0; pIdx < numProtocols; pIdx++) { | 
 |       ObjcMethodDecl **methods = protocols[pIdx]->getClassMethods(); | 
 |       int methodCount = protocols[pIdx]->getNumClassMethods(); | 
 |       for (int i = 0; i < methodCount; ++i) { | 
 |         if (methods[i]->getSelector() == Sel) { | 
 |           return methods[i]; | 
 |         } | 
 |       } | 
 |     } | 
 |     // Didn't find one yet - now look through categories. | 
 |     ObjcCategoryDecl *CatDecl = ClassDecl->getCategoryList(); | 
 |     while (CatDecl) { | 
 |       ObjcMethodDecl **methods = CatDecl->getClassMethods(); | 
 |       int methodCount = CatDecl->getNumClassMethods(); | 
 |       for (int i = 0; i < methodCount; ++i) { | 
 |         if (methods[i]->getSelector() == Sel) { | 
 |           return methods[i]; | 
 |         } | 
 |       } | 
 |       CatDecl = CatDecl->getNextClassCategory(); | 
 |     } | 
 |     ClassDecl = ClassDecl->getSuperClass(); | 
 |   } | 
 |   return NULL; | 
 | } | 
 |  | 
 |  |