This patch introduces the ObjcCategoryImplDecl class and does the checking related to 
unimplemented methods in category implementation.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42531 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
index 20226cb..f92bee6 100644
--- a/Sema/SemaDecl.cpp
+++ b/Sema/SemaDecl.cpp
@@ -1068,6 +1068,25 @@
   return CDecl;
 }
 
+/// ObjcStartCategoryImplementation - Perform semantic checks on the
+/// category implementation declaration and build an ObjcCategoryImplDecl
+/// object.
+Sema::DeclTy *Sema::ObjcStartCategoryImplementation(Scope* S,
+                      SourceLocation AtCatImplLoc,
+                      IdentifierInfo *ClassName, SourceLocation ClassLoc,
+                      IdentifierInfo *CatName, SourceLocation CatLoc) {
+  ObjcInterfaceDecl *IDecl = getObjCInterfaceDecl(S, ClassName, ClassLoc);
+  ObjcCategoryImplDecl *CDecl = new ObjcCategoryImplDecl(AtCatImplLoc, 
+                                                         ClassName, IDecl,
+                                                         CatName);
+  /// Check that class of this category is already completely declared.
+  if (!IDecl || IDecl->getIsForwardDecl())
+    Diag(ClassLoc, diag::err_undef_interface, ClassName->getName());
+  /// TODO: Check that CatName, category name, is not used in another
+  // implementation.
+  return CDecl;
+}
+
 Sema::DeclTy *Sema::ObjcStartClassImplementation(Scope *S,
                       SourceLocation AtClassImplLoc,
                       IdentifierInfo *ClassName, SourceLocation ClassLoc,
@@ -1255,7 +1274,51 @@
     ObjcProtocolDecl* PDecl = protocols[i];
     CheckProtocolMethodDefs(PDecl, InsMap, ClsMap);
   }
-  return;
+}
+
+/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
+/// category interface is implemented in the category @implementation.
+void Sema::ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl,
+                                            ObjcCategoryDecl *CatClassDecl) {
+  llvm::DenseMap<void *, char> InsMap;
+  // Check and see if instance methods in category interface have been
+  // implemented in its implementation class.
+  ObjcMethodDecl **methods = CatImplDecl->getCatInsMethods();
+  for (int i=0; i < CatImplDecl->getNumCatInsMethods(); i++) {
+    InsMap[methods[i]->getSelector().getAsOpaquePtr()] = 'a';
+  }
+  
+  methods = CatClassDecl->getCatInsMethods();
+  for (int j = 0; j < CatClassDecl->getNumCatInsMethods(); j++)
+    if (!InsMap.count(methods[j]->getSelector().getAsOpaquePtr())) {
+      llvm::SmallString<128> buf;
+      Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
+           methods[j]->getSelector().getName(buf));
+    }
+  llvm::DenseMap<void *, char> ClsMap;
+  // Check and see if class methods in category interface have been
+  // implemented in its implementation class.
+  methods = CatImplDecl->getCatClsMethods();
+  for (int i=0; i < CatImplDecl->getNumCatClsMethods(); i++) {
+    ClsMap[methods[i]->getSelector().getAsOpaquePtr()] = 'a';
+  }
+  
+  methods = CatClassDecl->getCatClsMethods();
+  for (int j = 0; j < CatClassDecl->getNumCatClsMethods(); j++)
+    if (!ClsMap.count(methods[j]->getSelector().getAsOpaquePtr())) {
+      llvm::SmallString<128> buf;
+      Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
+           methods[j]->getSelector().getName(buf));
+    }
+  
+  // Check the protocol list for unimplemented methods in the @implementation
+  // class.
+  ObjcProtocolDecl** protocols = CatClassDecl->getCatReferencedProtocols();
+  for (int i = 0; i < CatClassDecl->getNumCatReferencedProtocols(); i++) {
+    ObjcProtocolDecl* PDecl = protocols[i];
+    CheckProtocolMethodDefs(PDecl, InsMap, ClsMap);
+  }
+  
 }
 
 /// ObjcClassDeclaration - 
@@ -1647,6 +1710,24 @@
     if (IDecl)
       ImplMethodsVsClassMethods(ImplClass, IDecl);
   }
+  else if (isa<ObjcCategoryImplDecl>(static_cast<Decl *>(ClassDecl))) {
+    ObjcCategoryImplDecl* CatImplClass = cast<ObjcCategoryImplDecl>(
+                                          static_cast<Decl*>(ClassDecl));
+    CatImplClass->ObjcAddCatImplMethods(&insMethods[0], insMethods.size(),
+                                        &clsMethods[0], clsMethods.size());
+    ObjcInterfaceDecl* IDecl = CatImplClass->getClassInterface();
+    // Find category interface decl and then check that all methods declared
+    // in this interface is implemented in the category @implementation.
+    if (IDecl) {
+      for (ObjcCategoryDecl *Categories = IDecl->getListCategories();
+           Categories; Categories = Categories->getNextClassCategory()) {
+        if (Categories->getCatName() == CatImplClass->getObjcCatName()) {
+          ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories);
+          break;
+        }
+      }
+    }
+  }
   else
     assert(0 && "Sema::ObjcAddMethodsToClass(): Unknown DeclTy");
   return;