]> granicus.if.org Git - clang/commitdiff
This patch introduces the ObjcCategoryImplDecl class and does the checking related to
authorFariborz Jahanian <fjahanian@apple.com>
Tue, 2 Oct 2007 16:38:50 +0000 (16:38 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Tue, 2 Oct 2007 16:38:50 +0000 (16:38 +0000)
unimplemented methods in category implementation.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42531 91177308-0d34-0410-b5e6-96231b3b80d8

AST/Decl.cpp
Parse/ParseObjc.cpp
Sema/Sema.h
Sema/SemaDecl.cpp
clang.xcodeproj/project.pbxproj
include/clang/AST/Decl.h
include/clang/AST/DeclObjC.h
include/clang/Parse/Action.h
test/Sema/method-undef-category-warn-1.m [new file with mode: 0644]

index ddf4187a0e3234d47618eba0508ce5ef4c2f2258..d23f3cb6f3496eaea57cf2a62f4dffd565304b02 100644 (file)
@@ -34,6 +34,7 @@ static unsigned nForwardProtocolDecls = 0;
 static unsigned nCategoryDecls = 0;
 static unsigned nIvarDecls = 0;
 static unsigned nObjcImplementationDecls = 0;
+static unsigned nObjcCategoryImpl = 0;
 
 static bool StatSwitch = false;
 
@@ -136,6 +137,10 @@ void Decl::PrintStats() {
          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, "Total bytes = %d\n", 
          int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+
              nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+
@@ -199,6 +204,9 @@ void Decl::addDeclKind(const Kind k) {
     case ObjcImplementation: 
       nObjcImplementationDecls++;
       break;
+    case ObjcCategoryImpl:
+      nObjcCategoryImpl++;
+      break;
   }
 }
 
@@ -344,7 +352,7 @@ void ObjcProtocolDecl::ObjcAddProtoMethods(ObjcMethodDecl **insMethods,
 }
 
 /// ObjcAddCat - Insert instance and methods declarations into
-/// ObjcProtocolDecl's CatInsMethods and CatClsMethods fields.
+/// ObjcCategoryDecl's CatInsMethods and CatClsMethods fields.
 ///
 void ObjcCategoryDecl::ObjcAddCatMethods(ObjcMethodDecl **insMethods, 
                                         unsigned numInsMembers,
@@ -362,6 +370,25 @@ void ObjcCategoryDecl::ObjcAddCatMethods(ObjcMethodDecl **insMethods,
   }
 }
 
+/// ObjcAddCatImplMethods - Insert instance and methods declarations into
+/// ObjcCategoryImplDecl's CatInsMethods and CatClsMethods fields.
+///
+void ObjcCategoryImplDecl::ObjcAddCatImplMethods(ObjcMethodDecl **insMethods, 
+                                                unsigned numInsMembers,
+                                                ObjcMethodDecl **clsMethods,
+                                                unsigned numClsMembers) {
+  NumCatInsMethods = numInsMembers;
+  if (numInsMembers) {
+    CatInsMethods = new ObjcMethodDecl*[numInsMembers];
+    memcpy(CatInsMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*));
+  }
+  NumCatClsMethods = numClsMembers;
+  if (numClsMembers) {
+    CatClsMethods = new ObjcMethodDecl*[numClsMembers];
+    memcpy(CatClsMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*));
+  }
+}
+
 /// ObjcAddImplMethods - Insert instance and methods declarations into
 /// ObjcImplementationDecl's InsMethods and ClsMethods fields.
 ///
index ea536599ff605e8d6bb6587e67880380af053fea..cda2ab5fe69441c7c04c48c51f1da5a24a9c8e16 100644 (file)
@@ -934,7 +934,10 @@ Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration(
       return 0;
     }
     rparenLoc = ConsumeParen();
-    return 0;
+    DeclTy *ImplCatType = Actions.ObjcStartCategoryImplementation(CurScope,
+                                    atLoc, nameId, nameLoc, categoryId, 
+                                    categoryLoc);
+    return ImplCatType;
   }
   // We have a class implementation
   SourceLocation superClassLoc;
index 488d105ded5ea7f9e30ec2df2240c4aa8f3c8106..74f79d4f3f1766d9f747fd57f94b211b3779bb24 100644 (file)
@@ -49,6 +49,8 @@ namespace clang {
   class ObjcInterfaceDecl;
   class ObjcProtocolDecl;
   class ObjcImplementationDecl;
+  class ObjcCategoryImplDecl;
+  class ObjcCategoryDecl;
 
 /// Sema - This implements semantic analysis and AST building for C.
 class Sema : public Action {
@@ -219,6 +221,11 @@ private:
   void ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl, 
                                  ObjcInterfaceDecl* IDecl);
   
+  /// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
+  /// category interface is implemented in the category @implementation.
+  void ImplCategoryMethodsVsIntfMethods(ObjcCategoryImplDecl *CatImplDecl,
+                                         ObjcCategoryDecl *CatClassDecl);
+  
   //===--------------------------------------------------------------------===//
   // Statement Parsing Callbacks: SemaStmt.cpp.
 public:
@@ -395,6 +402,13 @@ public:
                     IdentifierInfo *SuperClassname, 
                     SourceLocation SuperClassLoc);
   
+  virtual DeclTy *ObjcStartCategoryImplementation(Scope* S,
+                                                  SourceLocation AtCatImplLoc,
+                                                  IdentifierInfo *ClassName, 
+                                                  SourceLocation ClassLoc,
+                                                  IdentifierInfo *CatName,
+                                                  SourceLocation CatLoc);
+  
   virtual DeclTy *ObjcClassDeclaration(Scope *S, SourceLocation AtClassLoc,
                                        IdentifierInfo **IdentList,
                                        unsigned NumElts);
index 20226cb9b4c85d70e41fcc74178d05f44fdf1806..f92bee64dcb617b2bd7db8ce004894e5692b3686 100644 (file)
@@ -1068,6 +1068,25 @@ Sema::DeclTy *Sema::ObjcStartCatInterface(Scope* S,
   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 @@ void Sema::ImplMethodsVsClassMethods(ObjcImplementationDecl* IMPDecl,
     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 @@ void Sema::ObjcAddMethodsToClass(Scope* S, DeclTy *ClassDecl,
     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;
index 314ed3ea3cf698d8d382b2bd0ea6ae5b1523a2b3..6389e5fbc4b52a5bf259edca2edaf14c4c7a7ad6 100644 (file)
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
                        projectDirPath = "";
index 5102a99d256676448a6dea6e9270be56411ef61e..0b0a8580cc2060fc45dfdfb393208c2bb6d5f745 100644 (file)
@@ -35,7 +35,7 @@ public:
     Function, BlockVariable, FileVariable, ParmVariable, EnumConstant,
     // Concrete sub-classes of TypeDecl
     Typedef, Struct, Union, Class, Enum, ObjcInterface, ObjcClass, ObjcMethod,
-    ObjcProtocol, ObjcForwardProtocol, ObjcCategory,
+    ObjcProtocol, ObjcForwardProtocol, ObjcCategory, ObjcCategoryImpl,
     ObjcImplementation,
     // Concrete sub-class of Decl
     Field, ObjcIvar
index 9deb1dc533fd37ffd0e227ce88f682d2b0fc74d1..c85a2f77a8fa01260ee3e93f37a592475cfd2961 100644 (file)
@@ -448,6 +448,17 @@ public:
     CatReferencedProtocols[idx] = OID;
   }
   
+  ObjcProtocolDecl **getCatReferencedProtocols() const { 
+    return CatReferencedProtocols; 
+  }
+  int getNumCatReferencedProtocols() const { return NumCatReferencedProtocols; }
+  
+  ObjcMethodDecl **getCatInsMethods() const { return CatInsMethods; }
+  int getNumCatInsMethods() const { return NumCatInsMethods; }
+  
+  ObjcMethodDecl **getCatClsMethods() const { return CatClsMethods; }
+  int getNumCatClsMethods() const { return NumCatClsMethods; }
+  
   void ObjcAddCatMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
                          ObjcMethodDecl **clsMethods, unsigned numClsMembers);
   
@@ -466,6 +477,56 @@ public:
   static bool classof(const ObjcCategoryDecl *D) { return true; }
 };
 
+/// ObjcCategoryImplDecl - An object of this class encapsulates a category 
+/// @implementation declaration.
+class ObjcCategoryImplDecl : public Decl {
+  /// Class interface for this category implementation
+  ObjcInterfaceDecl *ClassInterface;
+
+  /// Category name
+  IdentifierInfo *ObjcCatName;
+      
+  /// category instance methods being implemented
+  ObjcMethodDecl **CatInsMethods; // Null if category is not implementing any
+  int NumCatInsMethods;           // -1 if category is not implementing any
+  
+  /// category class methods being implemented
+  ObjcMethodDecl **CatClsMethods; // Null if category is not implementing any
+  int NumCatClsMethods;  // -1 if category is not implementing any
+  
+  public:
+    ObjcCategoryImplDecl(SourceLocation L, IdentifierInfo *Id,
+                         ObjcInterfaceDecl *classInterface,
+                         IdentifierInfo *catName)
+    : Decl(ObjcCategoryImpl),
+    ClassInterface(classInterface),
+    ObjcCatName(catName),
+    CatInsMethods(0), NumCatInsMethods(-1),
+    CatClsMethods(0), NumCatClsMethods(-1) {}
+        
+    ObjcInterfaceDecl *getClassInterface() const { 
+      return ClassInterface; 
+    }
+  
+  IdentifierInfo *getObjcCatName() const { return ObjcCatName; }
+  
+  ObjcMethodDecl **getCatInsMethods() const { return CatInsMethods; }
+  int getNumCatInsMethods() const { return NumCatInsMethods; }
+  
+  ObjcMethodDecl **getCatClsMethods() const { return CatClsMethods; }
+  int getNumCatClsMethods() const { return NumCatClsMethods; }
+  
+  
+  void ObjcAddCatImplMethods(
+        ObjcMethodDecl **insMethods, unsigned numInsMembers,
+        ObjcMethodDecl **clsMethods, unsigned numClsMembers);
+  
+  static bool classof(const Decl *D) {
+    return D->getKind() == ObjcCategoryImpl;
+  }
+  static bool classof(const ObjcCategoryImplDecl *D) { return true; }
+};
+
 /// ObjcImplementationDecl - Represents a class definition - this is where
 /// method definitions are specified. For example:
 ///
index 34561f7a2e41df1716cf3480d868d68056e73bc1..0376860160b414715dac036c11e57690ae2abffd 100644 (file)
@@ -472,6 +472,14 @@ public:
                     SourceLocation SuperClassLoc) {
     return 0;
   }
+  virtual DeclTy *ObjcStartCategoryImplementation(Scope* S,
+                                                  SourceLocation AtCatImplLoc,
+                                                  IdentifierInfo *ClassName, 
+                                                  SourceLocation ClassLoc,
+                                                  IdentifierInfo *CatName,
+                                                  SourceLocation CatLoc) {
+    return 0;
+  }  
   virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, 
     tok::TokenKind MethodType, TypeTy *ReturnType, Selector Sel,
     // optional arguments. The number of types/arguments is obtained
diff --git a/test/Sema/method-undef-category-warn-1.m b/test/Sema/method-undef-category-warn-1.m
new file mode 100644 (file)
index 0000000..e71cfdb
--- /dev/null
@@ -0,0 +1,26 @@
+@interface MyClass1 
+@end
+
+@protocol P
+- (void) Pmeth;        // expected-warning {{method definition for 'Pmeth' not found}}
+- (void) Pmeth1; // expected-warning {{method definition for 'Pmeth1' not found}}
+@end
+
+@interface MyClass1(CAT) <P>
+- (void) meth2;        // expected-warning {{method definition for 'meth2' not found}}
+@end
+
+@implementation MyClass1(CAT)
+- (void) Pmeth1{}
+@end
+
+@interface MyClass1(DOG) <P>
+- (void)ppp;  // expected-warning {{method definition for 'ppp' not found}}
+@end
+
+@implementation MyClass1(DOG)
+- (void) Pmeth {}
+@end
+
+@implementation MyClass1(CAT1)
+@end