]> granicus.if.org Git - clang/commitdiff
Patch for method implementation. It populates ObjcImplementationDecl object with...
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 27 Sep 2007 18:57:03 +0000 (18:57 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 27 Sep 2007 18:57:03 +0000 (18:57 +0000)
It checks and warns on those methods declared in class interface and not implemented.

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

AST/Decl.cpp
Parse/ParseObjc.cpp
Parse/Parser.cpp
Sema/Sema.h
Sema/SemaDecl.cpp
clang.xcodeproj/project.pbxproj
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
include/clang/Parse/Parser.h
test/Sema/method-undefined-warn-1.m [new file with mode: 0644]

index 83762e946580a49015f9e45d35c0d55fab8dbf74..10da7b163eddda91afd3e2b601dcacddc18eb622 100644 (file)
@@ -364,4 +364,23 @@ void ObjcCategoryDecl::ObjcAddCatMethods(ObjcMethodDecl **insMethods,
   }
 }
 
+/// ObjcAddImplMethods - Insert instance and methods declarations into
+/// ObjcImplementationDecl's InsMethods and ClsMethods fields.
+///
+void ObjcImplementationDecl::ObjcAddImplMethods(ObjcMethodDecl **insMethods, 
+                                               unsigned numInsMembers,
+                                               ObjcMethodDecl **clsMethods,
+                                               unsigned numClsMembers) {
+  NumInsMethods = numInsMembers;
+  if (numInsMembers) {
+    InsMethods = new ObjcMethodDecl*[numInsMembers];
+    memcpy(InsMethods, insMethods, numInsMembers*sizeof(ObjcMethodDecl*));
+  }
+  NumClsMethods = numClsMembers;
+  if (numClsMembers) {
+    ClsMethods = new ObjcMethodDecl*[numClsMembers];
+    memcpy(ClsMethods, clsMethods, numClsMembers*sizeof(ObjcMethodDecl*));
+  }
+}
+
 
index 9da15fafd270a773ca2fbb95b7b6ec0c28c03688..d8361b07df129f7702cff15bc2b7dc16bc83265d 100644 (file)
@@ -882,12 +882,22 @@ Parser::DeclTy *Parser::ParseObjCAtImplementationDeclaration(
   if (Tok.getKind() == tok::l_brace)
     ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/); // we have ivars
   
-  return 0;
+  return ImplClsType;
 }
 Parser::DeclTy *Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) {
   assert(Tok.isObjCAtKeyword(tok::objc_end) &&
          "ParseObjCAtEndDeclaration(): Expected @end");
   ConsumeToken(); // the "end" identifier
+  if (ObjcImpDecl) {
+    // Checking is not necessary except that a parse error might have caused
+    // @implementation not to have been parsed to completion and ObjcImpDecl 
+    // could be 0.
+    /// Insert collected methods declarations into the @interface object.
+    Actions.ObjcAddMethodsToClass(ObjcImpDecl,
+                                  &AllImplMethods[0],AllImplMethods.size());
+    ObjcImpDecl = 0;
+    AllImplMethods.clear();
+  }
 
   return 0;
 }
@@ -1056,7 +1066,7 @@ void Parser::ParseObjCInstanceMethodDefinition() {
   assert(Tok.getKind() == tok::minus &&
          "ParseObjCInstanceMethodDefinition(): Expected '-'");
   // FIXME: @optional/@protocol??
-  ParseObjCMethodPrototype(ObjcImpDecl);
+  AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
   // parse optional ';'
   if (Tok.getKind() == tok::semi)
     ConsumeToken();
@@ -1075,7 +1085,7 @@ void Parser::ParseObjCClassMethodDefinition() {
   assert(Tok.getKind() == tok::plus &&
          "ParseObjCClassMethodDefinition(): Expected '+'");
   // FIXME: @optional/@protocol??
-  ParseObjCMethodPrototype(ObjcImpDecl);
+  AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl));
   // parse optional ';'
   if (Tok.getKind() == tok::semi)
     ConsumeToken();
index b9bcc929a5f6957e0511e7451c2b7a7c5a7d78b3..362ca35512da950e2e41bd5220b887e217848081 100644 (file)
@@ -23,6 +23,7 @@ Parser::Parser(Preprocessor &pp, Action &actions)
   NumCachedScopes = 0;
   ParenCount = BracketCount = BraceCount = 0;
   ObjcImpDecl = 0;
+  AllImplMethods.clear();
 }
 
 ///  Out-of-line virtual destructor to provide home for Action class.
index a486d4fa73a25e7ed51280c84865e9114e49b935..45d1a2dc33dc3f7802364dff275ee25754cad6c4 100644 (file)
@@ -390,6 +390,8 @@ public:
   virtual void ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
                                           DeclTy **Fields, unsigned NumFields);
   
+  virtual void ActOnImplMethodsVsClassMethods(DeclTy *ImplClass, DeclTy *Class);
+
   virtual DeclTy *ObjcBuildMethodDeclaration(SourceLocation MethodLoc, 
     tok::TokenKind MethodType, TypeTy *ReturnType, SelectorInfo *Sel,
     // optional arguments. The number of types/arguments is obtained
index dd8fe22cc9420800b8155b86b895ac7bfa30f38a..381003f86afd81622a6f06cc1f68f74c234127aa 100644 (file)
@@ -1174,6 +1174,49 @@ void Sema::ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl,
       
 }
 
+void Sema::ActOnImplMethodsVsClassMethods(DeclTy* ImplClassDecl, 
+                                          DeclTy* ClassDecl) {
+  ObjcImplementationDecl* IMPDecl = 
+    cast<ObjcImplementationDecl>(static_cast<Decl*>(ImplClassDecl));
+  assert(IMPDecl && "missing implmentation class decl");
+  
+  ObjcInterfaceDecl* IDecl = 
+    cast<ObjcInterfaceDecl>(static_cast<Decl*>(ClassDecl));
+  assert(IDecl && "missing interface class decl");
+  
+  llvm::DenseMap<const SelectorInfo*, char> Map;
+  // Check and see if instance methods in class interface have been
+  // implemented in the implementation class.
+  ObjcMethodDecl **methods = IMPDecl->getInsMethods();
+  for (int i=0; i < IMPDecl->getNumInsMethods(); i++) {
+    Map[methods[i]->getSelector()] = 'a';
+  }
+  
+  methods = IDecl->getInsMethods();
+  for (int j = 0; j < IDecl->getNumInsMethods(); j++)
+    if (!Map.count(methods[j]->getSelector())) {
+      llvm::SmallString<128> buf;
+      Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
+           methods[j]->getSelector()->getName(buf));
+    }
+  Map.clear();
+  // Check and see if class methods in class interface have been
+  // implemented in the implementation class.
+  methods = IMPDecl->getClsMethods();
+  for (int i=0; i < IMPDecl->getNumClsMethods(); i++) {
+    Map[methods[i]->getSelector()] = 'a';
+  }
+  
+  methods = IDecl->getClsMethods();
+  for (int j = 0; j < IDecl->getNumClsMethods(); j++)
+    if (!Map.count(methods[j]->getSelector())) {
+      llvm::SmallString<128> buf;
+      Diag(methods[j]->getLocation(), diag::warn_undef_method_impl,
+           methods[j]->getSelector()->getName(buf));
+    }
+  return;
+}
+
 /// ObjcClassDeclaration - 
 /// Scope will always be top level file scope. 
 Action::DeclTy *
@@ -1560,7 +1603,17 @@ void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl,
                                         static_cast<Decl*>(ClassDecl));
     Category->ObjcAddCatMethods(&insMethods[0], insMethods.size(),
                                 &clsMethods[0], clsMethods.size());
-  }  
+  }
+  else if (isa<ObjcImplementationDecl>(static_cast<Decl *>(ClassDecl))) {
+    ObjcImplementationDecl* ImplClass = cast<ObjcImplementationDecl>(
+                                               static_cast<Decl*>(ClassDecl));
+    ImplClass->ObjcAddImplMethods(&insMethods[0], insMethods.size(),
+                                 &clsMethods[0], clsMethods.size());
+    ObjcInterfaceDecl* IDecl = 
+       Context.getObjCInterfaceDecl(ImplClass->getIdentifier());
+    if (IDecl)
+      ActOnImplMethodsVsClassMethods(ImplClass, IDecl);
+  }
   else
     assert(0 && "Sema::ObjcAddMethodsToClass(): Unknown DeclTy");
   return;
index 04dad73923642fe8370e14e246e86154e9d98bb5..fca0464b4752d414dd76727fe5bf5bd18bc2ddca 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 ea8121326e1fcdee5df25eb0c3c3159000ac5608..b3c30e5334988ecef104aec64a88bb021045a8a7 100644 (file)
@@ -591,6 +591,12 @@ public:
   ObjcIvarDecl **getIntfDeclIvars() const { return Ivars; }
   int getIntfDeclNumIvars() const { return NumIvars; }
   
+  ObjcMethodDecl** getInsMethods() const { return InsMethods; }
+  int getNumInsMethods() const { return NumInsMethods; }
+  
+  ObjcMethodDecl** getClsMethods() const { return ClsMethods; }
+  int getNumClsMethods() const { return NumClsMethods; }
+  
   void ObjcAddInstanceVariablesToClass(ObjcIvarDecl **ivars, 
                                       unsigned numIvars);
 
@@ -677,6 +683,9 @@ private:
   
   /// List of attributes for this method declaration.
   AttributeList *MethodAttrs;
+  
+  /// Loc - location of this declaration.
+  SourceLocation Loc;
 
   /// instance (true) or class (false) method.
   bool IsInstance : 1;
@@ -690,7 +699,7 @@ public:
                 Decl *PrevDecl = 0)
     : Decl(ObjcMethod), Selector(SelInfo), MethodDeclType(T), 
       ParamInfo(paramInfo), NumMethodParams(numParams),
-      MethodAttrs(M), IsInstance(isInstance) {}
+      MethodAttrs(M), Loc(L), IsInstance(isInstance) {}
 #if 0
   ObjcMethodDecl(Kind DK, SourceLocation L, IdentifierInfo &SelId, QualType T,
                 ParmVarDecl **paramInfo = 0, int numParams=-1,
@@ -701,6 +710,7 @@ public:
       MethodAttrs(M), IsInstance(isInstance) {}
 #endif
   virtual ~ObjcMethodDecl();
+  SelectorInfo *getSelector() const { return Selector; }
   QualType getMethodType() const { return MethodDeclType; }
   unsigned getNumMethodParams() const { return NumMethodParams; }
   ParmVarDecl *getMethodParamDecl(unsigned i) {
@@ -710,6 +720,7 @@ public:
   void setMethodParams(ParmVarDecl **NewParamInfo, unsigned NumParams);
 
   AttributeList *getMethodAttrs() const {return MethodAttrs;}
+  SourceLocation getLocation() const { return Loc; }
   bool isInstance() const { return IsInstance; }
   // Related to protocols declared in  @protocol
   void setDeclImplementation(ImplementationControl ic)
@@ -890,13 +901,19 @@ class ObjcImplementationDecl : public TypeDecl {
   void ObjcAddInstanceVariablesToClassImpl(ObjcIvarDecl **ivars, 
                                            unsigned numIvars);
     
-  void ObjcAddMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
-                        ObjcMethodDecl **clsMethods, unsigned numClsMembers);
+  void ObjcAddImplMethods(ObjcMethodDecl **insMethods, unsigned numInsMembers,
+                          ObjcMethodDecl **clsMethods, unsigned numClsMembers);
     
   ObjcInterfaceDecl *getImplSuperClass() const { return SuperClass; }
   
   void setImplSuperClass(ObjcInterfaceDecl * superCls) 
          { SuperClass = superCls; }
+  
+  ObjcMethodDecl **getInsMethods() const { return InsMethods; }
+  int getNumInsMethods() const { return NumInsMethods; }
+  
+  ObjcMethodDecl **getClsMethods() const { return ClsMethods; }
+  int getNumClsMethods() const { return NumClsMethods; }
     
   static bool classof(const Decl *D) {
     return D->getKind() == ObjcImplementation;
index c394663dd9b7c1403aaf008c295c41d73ac1661c..937684c7f6e134f429482880f26bbb54b06f7604 100644 (file)
@@ -432,7 +432,8 @@ DIAG(err_inconsistant_ivar, ERROR,
      "inconsistent instance variable specification")
 DIAG(err_conflicting_ivar_type, ERROR,
      "conflicting instance variable type")
-
+DIAG(warn_undef_method_impl, WARNING,
+     "method definition for '%0' not found")
 
 //===----------------------------------------------------------------------===//
 // Semantic Analysis
index 3e9a687ef4fd97467c456b9d569cd86cb3d99fe7..48ae4bea844fdd426211647b87e2046234e00138 100644 (file)
@@ -451,6 +451,10 @@ public:
                                           DeclTy **Fields, unsigned NumFields) {
     return;
   }
+  virtual void ActOnImplMethodsVsClassMethods(DeclTy *ImplClassDecl, 
+                                             DeclTy *ClassDecl) {
+    return;
+  }
   virtual DeclTy *ObjcStartProtoInterface(Scope* S,
                    SourceLocation AtProtoInterfaceLoc,
                     IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
index 243b88f9ff973dc5013cd2a1da1b972e16f498b1..3982028ff2c67b002f1153fc3679e2c6e9c52fd1 100644 (file)
@@ -265,6 +265,8 @@ private:
   DeclTy *ParseObjCAtProtocolDeclaration(SourceLocation atLoc);
   
   DeclTy *ObjcImpDecl;
+  /// Vector is used to collect method decls for each @implementation
+  llvm::SmallVector<DeclTy*, 32>  AllImplMethods;
   DeclTy *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
   DeclTy *ParseObjCAtEndDeclaration(SourceLocation atLoc);
   DeclTy *ParseObjCAtAliasDeclaration(SourceLocation atLoc);
diff --git a/test/Sema/method-undefined-warn-1.m b/test/Sema/method-undefined-warn-1.m
new file mode 100644 (file)
index 0000000..2c7cdad
--- /dev/null
@@ -0,0 +1,42 @@
+@interface INTF
+- (void) meth;
+- (void) meth : (int) arg1;
+- (int)  int_meth;     // expected-warning {{method definition for 'int_meth' not found}}
++ (int) cls_meth;      // expected-warning {{method definition for 'cls_meth' not found}}
++ (void) cls_meth1 : (int) arg1; // expected-warning {{method definition for 'cls_meth1:' not found}}
+@end
+
+@implementation INTF
+- (void) meth {}
+- (void) meth : (int) arg2{}
+- (void) cls_meth1 : (int) arg2{}
+@end
+
+
+@interface INTF1
+- (void) meth;
+- (void) meth : (int) arg1;
+- (int)  int_meth;      // expected-warning {{method definition for 'int_meth' not found}}
++ (int) cls_meth;       // expected-warning {{method definition for 'cls_meth' not found}}
++ (void) cls_meth1 : (int) arg1; // expected-warning {{method definition for 'cls_meth1:' not found}}
+@end
+
+@implementation INTF1
+- (void) meth {}
+- (void) meth : (int) arg2{}
+- (void) cls_meth1 : (int) arg2{}
+@end
+
+
+@interface INTF2
+- (void) meth;
+- (void) meth : (int) arg1;
+- (void) cls_meth1 : (int) arg1; 
+@end
+
+@implementation INTF2
+- (void) meth {}
+- (void) meth : (int) arg2{}
+- (void) cls_meth1 : (int) arg2{}
+@end
+