From: Argyrios Kyrtzidis Date: Tue, 21 Jul 2009 00:05:53 +0000 (+0000) Subject: - Introduce ASTContext::getObjCImplementation() and ASTContext::setObjCImplementation... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8a1d722f13df383600f36d77f842957c8adb5f1b;p=clang - Introduce ASTContext::getObjCImplementation() and ASTContext::setObjCImplementation() which use a DenseMap to associate an interface/category with its implementation (if one exists). - Introduce ObjCInterfaceDecl::get/setImplementation() and ObjCCategoryDecl::get/setImplementation() that use the above methods. - Add a compiler error for when a category is reimplemented. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76508 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 30f2308d12..2637b68097 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -97,6 +97,9 @@ class ASTContext { llvm::DenseMap ASTRecordLayouts; llvm::DenseMap ObjCLayouts; + /// \brief Mapping from ObjCContainers to their ObjCImplementations. + llvm::DenseMap ObjCImpls; + llvm::DenseMap SignedFixedWidthIntTypes; llvm::DenseMap UnsignedFixedWidthIntTypes; @@ -804,6 +807,18 @@ public: return Res; } + /// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. + ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D); + /// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. + ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D); + + /// \brief Set the implementation of ObjCInterfaceDecl. + void setObjCImplementation(ObjCInterfaceDecl *IFaceD, + ObjCImplementationDecl *ImplD); + /// \brief Set the implementation of ObjCCategoryDecl. + void setObjCImplementation(ObjCCategoryDecl *CatD, + ObjCCategoryImplDecl *ImplD); + private: ASTContext(const ASTContext&); // DO NOT IMPLEMENT void operator=(const ASTContext&); // DO NOT IMPLEMENT diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 1411c37cad..b23ad3d29b 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -427,7 +427,10 @@ public: const ObjCList &getReferencedProtocols() const { return ReferencedProtocols; } - + + ObjCImplementationDecl *getImplementation() const; + void setImplementation(ObjCImplementationDecl *ImplD); + ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; typedef ObjCList::iterator protocol_iterator; @@ -775,7 +778,10 @@ public: ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } void setClassInterface(ObjCInterfaceDecl *IDecl) { ClassInterface = IDecl; } - + + ObjCCategoryImplDecl *getImplementation() const; + void setImplementation(ObjCCategoryImplDecl *ImplD); + /// setProtocolList - Set the list of protocols that this interface /// implements. void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, @@ -828,7 +834,7 @@ public: const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } - void setClassInterface(ObjCInterfaceDecl *IFace) { ClassInterface = IFace; } + void setClassInterface(ObjCInterfaceDecl *IFace); void addInstanceMethod(ObjCMethodDecl *method) { // FIXME: Context should be set correctly before we get here. diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2864ed2ad6..cfca62acaa 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -168,6 +168,8 @@ def warn_dup_category_def : Warning< "duplicate definition of category %1 on interface %0">; def err_conflicting_super_class : Error<"conflicting super class name %0">; def err_dup_implementation_class : Error<"reimplementation of class %0">; +def err_dup_implementation_category : Error< + "reimplementation of category %1 for class %0">; def err_conflicting_ivar_type : Error< "instance variable %0 has conflicting type: %1 vs %2">; def err_conflicting_ivar_bitwidth : Error< diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 05627b47eb..304799cf91 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -824,6 +824,36 @@ unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) return count; } +/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. +ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) { + llvm::DenseMap::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast(I->second); + return 0; +} +/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. +ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { + llvm::DenseMap::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast(I->second); + return 0; +} + +/// \brief Set the implementation of ObjCInterfaceDecl. +void ASTContext::setObjCImplementation(ObjCInterfaceDecl *IFaceD, + ObjCImplementationDecl *ImplD) { + assert(IFaceD && ImplD && "Passed null params"); + ObjCImpls[IFaceD] = ImplD; +} +/// \brief Set the implementation of ObjCCategoryDecl. +void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, + ObjCCategoryImplDecl *ImplD) { + assert(CatD && ImplD && "Passed null params"); + ObjCImpls[CatD] = ImplD; +} + /// getInterfaceLayoutImpl - Get or compute information about the /// layout of the given interface. /// diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 613dc58a57..4eee28b468 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -363,6 +363,15 @@ void ObjCInterfaceDecl::Destroy(ASTContext &C) { Decl::Destroy(C); } +ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const { + return getASTContext().getObjCImplementation( + const_cast(this)); +} + +void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + /// FindCategoryDeclaration - Finds category declaration in the list of /// categories for this class and returns it. Name of the category is passed @@ -529,6 +538,16 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCCategoryDecl(DC, L, Id); } +ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { + return getASTContext().getObjCImplementation( + const_cast(this)); +} + +void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + + //===----------------------------------------------------------------------===// // ObjCCategoryImplDecl //===----------------------------------------------------------------------===// @@ -547,6 +566,23 @@ void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { addDecl(property); } +void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { + ASTContext &Ctx = getASTContext(); + + if (ObjCImplementationDecl *ImplD + = dyn_cast_or_null(this)) + if (IFace) + Ctx.setObjCImplementation(IFace, ImplD); + + else if (ObjCCategoryImplDecl *ImplD = + dyn_cast_or_null(this)) { + if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier())) + Ctx.setObjCImplementation(CD, ImplD); + } + + ClassInterface = IFace; +} + /// FindPropertyImplIvarDecl - This method lookup the ivar in the list of /// properties implemented in this category @implementation block and returns /// the implemented property that uses it. diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 8dc14eebe4..440b0fba6a 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -605,6 +605,19 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjCCategoryDecl *CatIDecl = 0; + if (IDecl) { + CatIDecl = IDecl->FindCategoryDeclaration(CatName); + if (!CatIDecl) { + // Category @implementation with no corresponding @interface. + // Create and install one. + CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(), + CatName); + CatIDecl->setClassInterface(IDecl); + CatIDecl->insertNextClassCategory(); + } + } + ObjCCategoryImplDecl *CDecl = ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName, IDecl); @@ -615,8 +628,17 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); - /// TODO: Check that CatName, category name, is not used in another - // implementation. + /// Check that CatName, category name, is not used in another implementation. + if (CatIDecl) { + if (CatIDecl->getImplementation()) { + Diag(ClassLoc, diag::err_dup_implementation_category) << ClassName + << CatName; + Diag(CatIDecl->getImplementation()->getLocation(), + diag::note_previous_definition); + } else + CatIDecl->setImplementation(CDecl); + } + ObjCCategoryImpls.push_back(CDecl); CheckObjCDeclScope(CDecl); @@ -697,8 +719,10 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( if (LookupObjCImplementation(ClassName)) // FIXME: Don't leak everything! Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName; - else // add it to the list. + else { // add it to the list. + IDecl->setImplementation(IMPDecl); PushOnScopeChains(IMPDecl, TUScope); + } return DeclPtrTy::make(IMPDecl); } diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m index 6ae775848e..077a49d2b7 100644 --- a/test/SemaObjC/category-1.m +++ b/test/SemaObjC/category-1.m @@ -53,4 +53,8 @@ @implementation XCRemoteComputerManager @end +@implementation XCRemoteComputerManager(x) // expected-note {{previous definition is here}} +@end +@implementation XCRemoteComputerManager(x) // expected-error {{reimplementation of category 'x' for class 'XCRemoteComputerManager'}} +@end