From: Chris Lattner Date: Sun, 1 Mar 2009 00:56:52 +0000 (+0000) Subject: "This patch uses the new ObjCImplDecl class to merge Sema::ImplMethodsVsClassMethods... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cddc88800bbd1213ec70ae5153c6a7f2e380fd8d;p=clang "This patch uses the new ObjCImplDecl class to merge Sema::ImplMethodsVsClassMethods and Sema::ImplCategoryMethodsVsIntfMethods methods. And now, when clang check a class implementation to find unimplemented methods, it also checks all methods from the class extensions (unnamed categories). There is also a test case to check this warning. This patch contains also a minor update for ObjCImplDecl . getNameAsCString and getNameAsString now returns an empty string instead of crashing for unnamed categories." Patch by Jean-Daniel Dupas! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65744 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index bdb8759b58..33662b287d 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -757,13 +757,16 @@ class ObjCImplDecl : public Decl, public DeclContext { llvm::SmallVector PropertyImplementations; SourceLocation EndLoc; + protected: ObjCImplDecl(Kind DK, DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *classInterface) - : Decl(DK, DC, L), DeclContext(DK), - ClassInterface(classInterface) {} + : Decl(DK, DC, L), DeclContext(DK), + ClassInterface(classInterface) {} public: + virtual ~ObjCImplDecl() {} + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } @@ -849,12 +852,12 @@ public: /// interface associated with this implementation as a C string /// (const char*). const char *getNameAsCString() const { - return Id->getName(); + return Id ? Id->getName() : ""; } /// @brief Get the name of the class associated with this interface. std::string getNameAsString() const { - return Id->getName(); + return Id ? Id->getName() : ""; } static bool classof(const Decl *D) { return D->getKind() == ObjCCategoryImpl;} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3e9d07aefb..6e0b935b88 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -68,6 +68,7 @@ namespace clang { class ObjCInterfaceDecl; class ObjCCompatibleAliasDecl; class ObjCProtocolDecl; + class ObjCImplDecl; class ObjCImplementationDecl; class ObjCCategoryImplDecl; class ObjCCategoryDecl; @@ -930,14 +931,11 @@ public: SourceLocation Loc); /// ImplMethodsVsClassMethods - This is main routine to warn if any method - /// remains unimplemented in the @implementation class. - 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); + /// remains unimplemented in the class or category @implementation. + void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool IncompleteImpl = false); + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 654891d5ab..f1f03844a2 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -814,8 +814,9 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl); } -void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, - ObjCInterfaceDecl* IDecl) { +void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* CDecl, + bool IncompleteImpl) { llvm::DenseSet InsMap; // Check and see if instance methods in class interface have been // implemented in the implementation class. @@ -823,9 +824,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, E = IMPDecl->instmeth_end(); I != E; ++I) InsMap.insert((*I)->getSelector()); - bool IncompleteImpl = false; - for (ObjCInterfaceDecl::instmeth_iterator I = IDecl->instmeth_begin(), - E = IDecl->instmeth_end(); I != E; ++I) { + for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(), + E = CDecl->instmeth_end(); I != E; ++I) { if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) { WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); continue; @@ -834,7 +834,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, ObjCMethodDecl *ImpMethodDecl = IMPDecl->getInstanceMethod((*I)->getSelector()); ObjCMethodDecl *IntfMethodDecl = - IDecl->getInstanceMethod((*I)->getSelector()); + CDecl->getInstanceMethod((*I)->getSelector()); assert(IntfMethodDecl && "IntfMethodDecl is null in ImplMethodsVsClassMethods"); // ImpMethodDecl may be null as in a @dynamic property. @@ -849,82 +849,41 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl, E = IMPDecl->classmeth_end(); I != E; ++I) ClsMap.insert((*I)->getSelector()); - for (ObjCInterfaceDecl::classmeth_iterator I = IDecl->classmeth_begin(), - E = IDecl->classmeth_end(); I != E; ++I) + for (ObjCInterfaceDecl::classmeth_iterator I = CDecl->classmeth_begin(), + E = CDecl->classmeth_end(); I != E; ++I) if (!ClsMap.count((*I)->getSelector())) WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod((*I)->getSelector()); ObjCMethodDecl *IntfMethodDecl = - IDecl->getClassMethod((*I)->getSelector()); + CDecl->getClassMethod((*I)->getSelector()); WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); } // Check the protocol list for unimplemented methods in the @implementation // class. - const ObjCList &Protocols = - IDecl->getReferencedProtocols(); - for (ObjCList::iterator I = Protocols.begin(), - E = Protocols.end(); I != E; ++I) - CheckProtocolMethodDefs(IMPDecl->getLocation(), *I, - IncompleteImpl, InsMap, ClsMap, IDecl); -} - -/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the -/// category interface are implemented in the category @implementation. -void Sema::ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl, - ObjCCategoryDecl *CatClassDecl) { - llvm::DenseSet InsMap; - // Check and see if instance methods in category interface have been - // implemented in its implementation class. - for (ObjCCategoryImplDecl::instmeth_iterator I =CatImplDecl->instmeth_begin(), - E = CatImplDecl->instmeth_end(); I != E; ++I) - InsMap.insert((*I)->getSelector()); - - bool IncompleteImpl = false; - for (ObjCCategoryDecl::instmeth_iterator I = CatClassDecl->instmeth_begin(), - E = CatClassDecl->instmeth_end(); I != E; ++I) - if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) - WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl); - else { - ObjCMethodDecl *ImpMethodDecl = - CatImplDecl->getInstanceMethod((*I)->getSelector()); - ObjCMethodDecl *IntfMethodDecl = - CatClassDecl->getInstanceMethod((*I)->getSelector()); - assert(IntfMethodDecl && - "IntfMethodDecl is null in ImplCategoryMethodsVsIntfMethods"); - // ImpMethodDecl may be null as in a @dynamic property. - if (ImpMethodDecl) - WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); - } - - llvm::DenseSet ClsMap; - // Check and see if class methods in category interface have been - // implemented in its implementation class. - for (ObjCCategoryImplDecl::classmeth_iterator - I = CatImplDecl->classmeth_begin(), E = CatImplDecl->classmeth_end(); - I != E; ++I) - ClsMap.insert((*I)->getSelector()); - - for (ObjCCategoryDecl::classmeth_iterator I = CatClassDecl->classmeth_begin(), - E = CatClassDecl->classmeth_end(); I != E; ++I) - if (!ClsMap.count((*I)->getSelector())) - WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl); - else { - ObjCMethodDecl *ImpMethodDecl = - CatImplDecl->getClassMethod((*I)->getSelector()); - ObjCMethodDecl *IntfMethodDecl = - CatClassDecl->getClassMethod((*I)->getSelector()); - WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); + if (ObjCInterfaceDecl *I = dyn_cast (CDecl)) { + for (ObjCCategoryDecl::protocol_iterator PI = I->protocol_begin(), + E = I->protocol_end(); PI != E; ++PI) + CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, + InsMap, ClsMap, I); + // Check class extensions (unnamed categories) + for (ObjCCategoryDecl *Categories = I->getCategoryList(); + Categories; Categories = Categories->getNextClassCategory()) { + if (!Categories->getIdentifier()) { + ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); + break; + } } - // Check the protocol list for unimplemented methods in the @implementation - // class. - for (ObjCCategoryDecl::protocol_iterator PI = CatClassDecl->protocol_begin(), - E = CatClassDecl->protocol_end(); PI != E; ++PI) - CheckProtocolMethodDefs(CatImplDecl->getLocation(), *PI, IncompleteImpl, - InsMap, ClsMap, CatClassDecl->getClassInterface()); + } else if (ObjCCategoryDecl *C = dyn_cast(CDecl)) { + for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), + E = C->protocol_end(); PI != E; ++PI) + CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, + InsMap, ClsMap, C->getClassInterface()); + } else + assert(false && "invalid ObjCContainerDecl type."); } /// ActOnForwardClassDeclaration - @@ -1302,7 +1261,7 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl, for (ObjCCategoryDecl *Categories = IDecl->getCategoryList(); Categories; Categories = Categories->getNextClassCategory()) { if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { - ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories); + ImplMethodsVsClassMethods(CatImplClass, Categories); break; } } diff --git a/test/SemaObjC/method-undef-extension-warn-1.m b/test/SemaObjC/method-undef-extension-warn-1.m new file mode 100644 index 0000000000..00201c88a4 --- /dev/null +++ b/test/SemaObjC/method-undef-extension-warn-1.m @@ -0,0 +1,25 @@ +// RUN: clang -fsyntax-only -verify %s + +@interface MyClass +@end + +@protocol P +- (void)Pmeth; +- (void)Pmeth1; +@end + +// Class extension +@interface MyClass ()

+- (void)meth2; +@end + +// Add a category to test that clang does not emit warning for this method. +@interface MyClass (Category) +- (void)categoryMethod; +@end + +@implementation MyClass // expected-warning {{incomplete implementation}} \ + expected-warning {{method definition for 'meth2' not found}} \ + expected-warning {{method definition for 'Pmeth1' not found}} +- (void)Pmeth {} +@end