From: Fariborz Jahanian Date: Fri, 28 Sep 2007 17:40:07 +0000 (+0000) Subject: Patch to warn on umimplemented methods coming from class's X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=00ae8d595534c0a444326204adee3486bbb43dcd;p=clang Patch to warn on umimplemented methods coming from class's protocols. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42436 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/Sema.h b/Sema/Sema.h index 45d1a2dc33..a486d4fa73 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -390,8 +390,6 @@ 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 diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 381003f86a..45762acd37 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -1174,46 +1174,76 @@ void Sema::ActOnImpleIvarVsClassIvars(DeclTy *ClassDecl, } -void Sema::ActOnImplMethodsVsClassMethods(DeclTy* ImplClassDecl, - DeclTy* ClassDecl) { - ObjcImplementationDecl* IMPDecl = - cast(static_cast(ImplClassDecl)); - assert(IMPDecl && "missing implmentation class decl"); - - ObjcInterfaceDecl* IDecl = - cast(static_cast(ClassDecl)); - assert(IDecl && "missing interface class decl"); +/// CheckProtocolMethodDefs - This routine checks unimpletented methods +/// Declared in protocol, and those referenced by it. +/// +static void CheckProtocolMethodDefs(Sema* objSema, ObjcProtocolDecl *PDecl, + const llvm::DenseMap& InsMap, + const llvm::DenseMap& ClsMap) { + // check unimplemented instance methods. + ObjcMethodDecl** methods = PDecl->getInsMethods(); + for (int j = 0; j < PDecl->getNumInsMethods(); j++) + if (!InsMap.count(methods[j]->getSelector())) { + llvm::SmallString<128> buf; + objSema->Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector()->getName(buf)); + } + // check unimplemented class methods + methods = PDecl->getClsMethods(); + for (int j = 0; j < PDecl->getNumClsMethods(); j++) + if (!ClsMap.count(methods[j]->getSelector())) { + llvm::SmallString<128> buf; + objSema->Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector()->getName(buf)); + } - llvm::DenseMap Map; + // Check on this protocols's referenced protocols, recursively + ObjcProtocolDecl** RefPDecl = PDecl->getReferencedProtocols(); + for (int i = 0; i < PDecl->getNumReferencedProtocols(); i++) + CheckProtocolMethodDefs(objSema, RefPDecl[i], InsMap, ClsMap); +} + +static void ImplMethodsVsClassMethods(Sema* objSema, + ObjcImplementationDecl* IMPDecl, + ObjcInterfaceDecl* IDecl) { + llvm::DenseMap InsMap; // 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'; + InsMap[methods[i]->getSelector()] = 'a'; } methods = IDecl->getInsMethods(); for (int j = 0; j < IDecl->getNumInsMethods(); j++) - if (!Map.count(methods[j]->getSelector())) { + if (!InsMap.count(methods[j]->getSelector())) { llvm::SmallString<128> buf; - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector()->getName(buf)); + objSema->Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, + methods[j]->getSelector()->getName(buf)); } - Map.clear(); + llvm::DenseMap ClsMap; // 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'; + ClsMap[methods[i]->getSelector()] = 'a'; } methods = IDecl->getClsMethods(); for (int j = 0; j < IDecl->getNumClsMethods(); j++) - if (!Map.count(methods[j]->getSelector())) { + if (!ClsMap.count(methods[j]->getSelector())) { llvm::SmallString<128> buf; - Diag(methods[j]->getLocation(), diag::warn_undef_method_impl, - methods[j]->getSelector()->getName(buf)); + objSema->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 = IDecl->getIntfRefProtocols(); + for (int i = 0; i < IDecl->getNumIntfRefProtocols(); i++) { + ObjcProtocolDecl* PDecl = protocols[i]; + CheckProtocolMethodDefs(objSema, PDecl, InsMap, ClsMap); + } return; } @@ -1612,7 +1642,7 @@ void Sema::ObjcAddMethodsToClass(DeclTy *ClassDecl, ObjcInterfaceDecl* IDecl = Context.getObjCInterfaceDecl(ImplClass->getIdentifier()); if (IDecl) - ActOnImplMethodsVsClassMethods(ImplClass, IDecl); + ImplMethodsVsClassMethods(this, ImplClass, IDecl); } else assert(0 && "Sema::ObjcAddMethodsToClass(): Unknown DeclTy"); diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index b3c30e5334..dddd273962 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -588,6 +588,10 @@ public: NumIntfRefProtocols = numRefProtos; } } + + ObjcProtocolDecl **getIntfRefProtocols() const { return IntfRefProtocols; } + int getNumIntfRefProtocols() const { return NumIntfRefProtocols; } + ObjcIvarDecl **getIntfDeclIvars() const { return Ivars; } int getIntfDeclNumIvars() const { return NumIvars; } @@ -776,6 +780,16 @@ public: ReferencedProtocols[idx] = OID; } + ObjcProtocolDecl** getReferencedProtocols() const { + return ReferencedProtocols; + } + int getNumReferencedProtocols() const { return NumReferencedProtocols; } + + ObjcMethodDecl** getInsMethods() const { return ProtoInsMethods; } + int getNumInsMethods() const { return NumProtoInsMethods; } + + ObjcMethodDecl** getClsMethods() const { return ProtoClsMethods; } + int getNumClsMethods() const { return NumProtoClsMethods; } bool getIsForwardProtoDecl() const { return isForwardProtoDecl; } void setIsForwardProtoDecl(bool val) { isForwardProtoDecl = val; } diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 48ae4bea84..3e9a687ef4 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -451,10 +451,6 @@ 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, diff --git a/test/Sema/undef-protocol-methods-1.m b/test/Sema/undef-protocol-methods-1.m new file mode 100644 index 0000000000..60203fcc24 --- /dev/null +++ b/test/Sema/undef-protocol-methods-1.m @@ -0,0 +1,31 @@ +@protocol P1 +- (void) P1proto; // expected-warning {{method definition for 'P1proto' not found}} ++ (void) ClsP1Proto; // expected-warning {{method definition for 'ClsP1Proto' not found}} +- (void) DefP1proto; +@end +@protocol P2 +- (void) P2proto; // expected-warning {{method definition for 'P2proto' not found}} ++ (void) ClsP2Proto; // expected-warning {{method definition for 'ClsP2Proto' not found}} +@end + +@protocol P3 +- (void) P3proto; // expected-warning {{method definition for 'P3proto' not found}} ++ (void) ClsP3Proto; // expected-warning {{method definition for 'ClsP3Proto' not found}} ++ (void) DefClsP3Proto; +@end + +@protocol PROTO +- (void) meth; // expected-warning {{method definition for 'meth' not found +- (void) meth : (int) arg1; // expected-warning {{method definition for 'meth:' not found ++ (void) cls_meth : (int) arg1; // expected-warning {{method definition for 'cls_meth:' not found +@end + +@interface INTF +@end + +@implementation INTF +- (void) DefP1proto{} + ++ (void) DefClsP3Proto{} + +@end