- 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/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 8dc14ee..440b0fb 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -605,6 +605,19 @@
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 @@
// 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 @@
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);
}