| //===--- Decl.cpp - Declaration AST Node Implementation -------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file 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/AST/ASTContext.h" |
| #include "clang/AST/Attr.h" |
| #include "clang/Basic/IdentifierTable.h" |
| #include "llvm/ADT/DenseMap.h" |
| using namespace clang; |
| |
| //===----------------------------------------------------------------------===// |
| // Statistics |
| //===----------------------------------------------------------------------===// |
| |
| // 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 unsigned nObjCPropertyDecl = 0; |
| static unsigned nLinkageSpecDecl = 0; |
| static unsigned nFileScopeAsmDecl = 0; |
| |
| static bool StatSwitch = false; |
| |
| // This keeps track of all decl attributes. Since so few decls have attrs, we |
| // keep them in a hash map instead of wasting space in the Decl class. |
| typedef llvm::DenseMap<const Decl*, Attr*> DeclAttrMapTy; |
| |
| static DeclAttrMapTy *DeclAttrs = 0; |
| |
| 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, " %d property decls, %d each (%d bytes)\n", |
| nObjCPropertyDecl, (int)sizeof(ObjCPropertyDecl), |
| int(nObjCPropertyDecl*sizeof(ObjCPropertyDecl))); |
| |
| 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)+ |
| nInterfaceDecls*sizeof(ObjCInterfaceDecl)+ |
| nIvarDecls*sizeof(ObjCIvarDecl)+ |
| nClassDecls*sizeof(ObjCClassDecl)+ |
| nMethodDecls*sizeof(ObjCMethodDecl)+ |
| nProtocolDecls*sizeof(ObjCProtocolDecl)+ |
| nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl)+ |
| nCategoryDecls*sizeof(ObjCCategoryDecl)+ |
| nObjCImplementationDecls*sizeof(ObjCImplementationDecl)+ |
| nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl)+ |
| nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl)+ |
| nObjCPropertyDecl*sizeof(ObjCPropertyDecl)+ |
| nLinkageSpecDecl*sizeof(LinkageSpecDecl)+ |
| nFileScopeAsmDecl*sizeof(FileScopeAsmDecl))); |
| |
| } |
| |
| void Decl::addDeclKind(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; |
| case PropertyDecl: nObjCPropertyDecl++; break; |
| case LinkageSpec: nLinkageSpecDecl++; break; |
| case FileScopeAsm: nFileScopeAsmDecl++; break; |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Decl Allocation/Deallocation Method Implementations |
| //===----------------------------------------------------------------------===// |
| |
| BlockVarDecl *BlockVarDecl::Create(ASTContext &C, SourceLocation L, |
| IdentifierInfo *Id, QualType T, |
| StorageClass S, ScopedDecl *PrevDecl) { |
| void *Mem = C.getAllocator().Allocate<BlockVarDecl>(); |
| return new (Mem) BlockVarDecl(L, Id, T, S, PrevDecl); |
| } |
| |
| |
| FileVarDecl *FileVarDecl::Create(ASTContext &C, SourceLocation L, |
| IdentifierInfo *Id, QualType T, StorageClass S, |
| ScopedDecl *PrevDecl) { |
| void *Mem = C.getAllocator().Allocate<FileVarDecl>(); |
| return new (Mem) FileVarDecl(L, Id, T, S, PrevDecl); |
| } |
| |
| ParmVarDecl *ParmVarDecl::Create(ASTContext &C, SourceLocation L, |
| IdentifierInfo *Id, QualType T, StorageClass S, |
| ScopedDecl *PrevDecl) { |
| void *Mem = C.getAllocator().Allocate<ParmVarDecl>(); |
| return new (Mem) ParmVarDecl(L, Id, T, S, PrevDecl); |
| } |
| |
| FunctionDecl *FunctionDecl::Create(ASTContext &C, SourceLocation L, |
| IdentifierInfo *Id, QualType T, |
| StorageClass S, bool isInline, |
| ScopedDecl *PrevDecl) { |
| void *Mem = C.getAllocator().Allocate<FunctionDecl>(); |
| return new (Mem) FunctionDecl(L, Id, T, S, isInline, PrevDecl); |
| } |
| |
| |
| EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, SourceLocation L, |
| IdentifierInfo *Id, QualType T, |
| Expr *E, const llvm::APSInt &V, |
| ScopedDecl *PrevDecl){ |
| void *Mem = C.getAllocator().Allocate<EnumConstantDecl>(); |
| return new (Mem) EnumConstantDecl(L, Id, T, E, V, PrevDecl); |
| } |
| |
| TypedefDecl *TypedefDecl::Create(ASTContext &C, SourceLocation L, |
| IdentifierInfo *Id, QualType T, |
| ScopedDecl *PD) { |
| void *Mem = C.getAllocator().Allocate<TypedefDecl>(); |
| return new (Mem) TypedefDecl(L, Id, T, PD); |
| } |
| |
| EnumDecl *EnumDecl::Create(ASTContext &C, SourceLocation L, IdentifierInfo *Id, |
| ScopedDecl *PrevDecl) { |
| void *Mem = C.getAllocator().Allocate<EnumDecl>(); |
| return new (Mem) EnumDecl(L, Id, PrevDecl); |
| } |
| |
| RecordDecl *RecordDecl::Create(ASTContext &C, Kind DK, SourceLocation L, |
| IdentifierInfo *Id, ScopedDecl *PrevDecl) { |
| void *Mem = C.getAllocator().Allocate<RecordDecl>(); |
| return new (Mem) RecordDecl(DK, L, Id, PrevDecl); |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Decl Implementation |
| //===----------------------------------------------------------------------===// |
| |
| // Out-of-line virtual method providing a home for Decl. |
| Decl::~Decl() { |
| if (!HasAttrs) |
| return; |
| |
| DeclAttrMapTy::iterator it = DeclAttrs->find(this); |
| assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!"); |
| |
| delete it->second; |
| DeclAttrs->erase(it); |
| if (DeclAttrs->empty()) { |
| delete DeclAttrs; |
| DeclAttrs = 0; |
| } |
| } |
| |
| void Decl::addAttr(Attr *NewAttr) { |
| if (!DeclAttrs) |
| DeclAttrs = new llvm::DenseMap<const Decl*, Attr*>(); |
| |
| Attr *&ExistingAttr = (*DeclAttrs)[this]; |
| |
| NewAttr->setNext(ExistingAttr); |
| ExistingAttr = NewAttr; |
| |
| HasAttrs = true; |
| } |
| |
| const Attr *Decl::getAttrs() const { |
| if (!HasAttrs) |
| return 0; |
| |
| return (*DeclAttrs)[this]; |
| } |
| |
| const char *NamedDecl::getName() const { |
| if (const IdentifierInfo *II = getIdentifier()) |
| return II->getName(); |
| return ""; |
| } |
| |
| FunctionDecl::~FunctionDecl() { |
| delete[] ParamInfo; |
| } |
| |
| unsigned FunctionDecl::getNumParams() const { |
| if (isa<FunctionTypeNoProto>(getCanonicalType())) |
| return 0; |
| return cast<FunctionTypeProto>(getCanonicalType())->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; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Objective-C Decl Implementation |
| //===----------------------------------------------------------------------===// |
| |
| 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::addInstanceVariablesToClass(ObjCIvarDecl **ivars, |
| unsigned numIvars, |
| SourceLocation RBrac) { |
| NumIvars = numIvars; |
| if (numIvars) { |
| Ivars = new ObjCIvarDecl*[numIvars]; |
| memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*)); |
| } |
| setLocEnd(RBrac); |
| } |
| |
| /// 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*)); |
| } |
| } |
| |
| /// addMethods - Insert instance and methods declarations into |
| /// ObjCInterfaceDecl's InsMethods and ClsMethods fields. |
| /// |
| void ObjCInterfaceDecl::addMethods(ObjCMethodDecl **insMethods, |
| unsigned numInsMembers, |
| ObjCMethodDecl **clsMethods, |
| unsigned numClsMembers, |
| SourceLocation endLoc) { |
| 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*)); |
| } |
| AtEndLoc = endLoc; |
| } |
| |
| /// addMethods - Insert instance and methods declarations into |
| /// ObjCProtocolDecl's ProtoInsMethods and ProtoClsMethods fields. |
| /// |
| void ObjCProtocolDecl::addMethods(ObjCMethodDecl **insMethods, |
| unsigned numInsMembers, |
| ObjCMethodDecl **clsMethods, |
| unsigned numClsMembers, |
| SourceLocation endLoc) { |
| 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*)); |
| } |
| AtEndLoc = endLoc; |
| } |
| |
| /// addMethods - Insert instance and methods declarations into |
| /// ObjCCategoryDecl's CatInsMethods and CatClsMethods fields. |
| /// |
| void ObjCCategoryDecl::addMethods(ObjCMethodDecl **insMethods, |
| unsigned numInsMembers, |
| ObjCMethodDecl **clsMethods, |
| unsigned numClsMembers, |
| SourceLocation endLoc) { |
| 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*)); |
| } |
| AtEndLoc = endLoc; |
| } |
| |
| ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable( |
| IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { |
| ObjCInterfaceDecl* ClassDecl = this; |
| while (ClassDecl != NULL) { |
| for (ivar_iterator I = ClassDecl->ivar_begin(), E = ClassDecl->ivar_end(); |
| I != E; ++I) { |
| if ((*I)->getIdentifier() == ID) { |
| clsDeclared = ClassDecl; |
| return *I; |
| } |
| } |
| ClassDecl = ClassDecl->getSuperClass(); |
| } |
| return NULL; |
| } |
| |
| /// lookupInstanceMethod - This method returns an instance method by looking in |
| /// the class, its categories, and its super classes (using a linear search). |
| ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) { |
| ObjCInterfaceDecl* ClassDecl = this; |
| ObjCMethodDecl *MethodDecl = 0; |
| |
| while (ClassDecl != NULL) { |
| if ((MethodDecl = ClassDecl->getInstanceMethod(Sel))) |
| return MethodDecl; |
| |
| // Didn't find one yet - look through protocols. |
| ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); |
| int numProtocols = ClassDecl->getNumIntfRefProtocols(); |
| for (int pIdx = 0; pIdx < numProtocols; pIdx++) { |
| if ((MethodDecl = protocols[pIdx]->getInstanceMethod(Sel))) |
| return MethodDecl; |
| } |
| // Didn't find one yet - now look through categories. |
| ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); |
| while (CatDecl) { |
| if ((MethodDecl = CatDecl->getInstanceMethod(Sel))) |
| return MethodDecl; |
| CatDecl = CatDecl->getNextClassCategory(); |
| } |
| ClassDecl = ClassDecl->getSuperClass(); |
| } |
| return NULL; |
| } |
| |
| // lookupClassMethod - This method returns a class method by looking in the |
| // class, its categories, and its super classes (using a linear search). |
| ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { |
| ObjCInterfaceDecl* ClassDecl = this; |
| ObjCMethodDecl *MethodDecl = 0; |
| |
| while (ClassDecl != NULL) { |
| if ((MethodDecl = ClassDecl->getClassMethod(Sel))) |
| return MethodDecl; |
| |
| // Didn't find one yet - look through protocols. |
| ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); |
| int numProtocols = ClassDecl->getNumIntfRefProtocols(); |
| for (int pIdx = 0; pIdx < numProtocols; pIdx++) { |
| if ((MethodDecl = protocols[pIdx]->getClassMethod(Sel))) |
| return MethodDecl; |
| } |
| // Didn't find one yet - now look through categories. |
| ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); |
| while (CatDecl) { |
| if ((MethodDecl = CatDecl->getClassMethod(Sel))) |
| return MethodDecl; |
| CatDecl = CatDecl->getNextClassCategory(); |
| } |
| ClassDecl = ClassDecl->getSuperClass(); |
| } |
| return NULL; |
| } |
| |
| /// lookupInstanceMethod - This method returns an instance method by looking in |
| /// the class implementation. Unlike interfaces, we don't look outside the |
| /// implementation. |
| ObjCMethodDecl *ObjCImplementationDecl::getInstanceMethod(Selector Sel) { |
| for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) |
| if ((*I)->getSelector() == Sel) |
| return *I; |
| return NULL; |
| } |
| |
| /// lookupClassMethod - This method returns a class method by looking in |
| /// the class implementation. Unlike interfaces, we don't look outside the |
| /// implementation. |
| ObjCMethodDecl *ObjCImplementationDecl::getClassMethod(Selector Sel) { |
| for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); |
| I != E; ++I) |
| if ((*I)->getSelector() == Sel) |
| return *I; |
| return NULL; |
| } |
| |
| // lookupInstanceMethod - This method returns an instance method by looking in |
| // the class implementation. Unlike interfaces, we don't look outside the |
| // implementation. |
| ObjCMethodDecl *ObjCCategoryImplDecl::getInstanceMethod(Selector Sel) { |
| for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) |
| if ((*I)->getSelector() == Sel) |
| return *I; |
| return NULL; |
| } |
| |
| // lookupClassMethod - This method returns an instance method by looking in |
| // the class implementation. Unlike interfaces, we don't look outside the |
| // implementation. |
| ObjCMethodDecl *ObjCCategoryImplDecl::getClassMethod(Selector Sel) { |
| for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); |
| I != E; ++I) |
| if ((*I)->getSelector() == Sel) |
| return *I; |
| return NULL; |
| } |
| |
| // lookupInstanceMethod - Lookup a instance method in the protocol and protocols |
| // it inherited. |
| ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) { |
| ObjCMethodDecl *MethodDecl = NULL; |
| |
| if ((MethodDecl = getInstanceMethod(Sel))) |
| return MethodDecl; |
| |
| if (getNumReferencedProtocols() > 0) { |
| ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); |
| |
| for (unsigned i = 0; i < getNumReferencedProtocols(); i++) { |
| if ((MethodDecl = RefPDecl[i]->getInstanceMethod(Sel))) |
| return MethodDecl; |
| } |
| } |
| return NULL; |
| } |
| |
| // lookupInstanceMethod - Lookup a class method in the protocol and protocols |
| // it inherited. |
| ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { |
| ObjCMethodDecl *MethodDecl = NULL; |
| |
| if ((MethodDecl = getClassMethod(Sel))) |
| return MethodDecl; |
| |
| if (getNumReferencedProtocols() > 0) { |
| ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); |
| |
| for(unsigned i = 0; i < getNumReferencedProtocols(); i++) { |
| if ((MethodDecl = RefPDecl[i]->getClassMethod(Sel))) |
| return MethodDecl; |
| } |
| } |
| return NULL; |
| } |
| |
| /// getSynthesizedMethodSize - Compute size of synthesized method name |
| /// as done be the rewrite. |
| /// |
| unsigned ObjCMethodDecl::getSynthesizedMethodSize() const { |
| // syntesized method name is a concatenation of -/+[class-name selector] |
| // Get length of this name. |
| unsigned length = 3; // _I_ or _C_ |
| length += strlen(getClassInterface()->getName()) +1; // extra for _ |
| NamedDecl *MethodContext = getMethodContext(); |
| if (ObjCCategoryImplDecl *CID = |
| dyn_cast<ObjCCategoryImplDecl>(MethodContext)) |
| length += strlen(CID->getName()) +1; |
| length += getSelector().getName().size(); // selector name |
| return length; |
| } |
| |
| ObjCInterfaceDecl *const ObjCMethodDecl::getClassInterface() const { |
| if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(MethodContext)) |
| return ID; |
| if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(MethodContext)) |
| return CD->getClassInterface(); |
| if (ObjCImplementationDecl *IMD = |
| dyn_cast<ObjCImplementationDecl>(MethodContext)) |
| return IMD->getClassInterface(); |
| if (ObjCCategoryImplDecl *CID = |
| dyn_cast<ObjCCategoryImplDecl>(MethodContext)) |
| return CID->getClassInterface(); |
| assert(false && "unknown method context"); |
| return 0; |
| } |