From b33f3ad379f497c5fc6d0ada618745dd46d0e717 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Fri, 1 May 2009 20:07:12 +0000 Subject: [PATCH] Check for method type conflict between declaration in class/protocol and implementation which could be an imm. implementation or down in the inheritance hierarchy. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70568 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 11 +++ lib/Sema/SemaDeclObjC.cpp | 122 ++++++++++++++++++++--------- test/Analysis/PR2978.m | 2 +- test/SemaObjC/method-typecheck-2.m | 25 ++++++ test/SemaObjC/props-on-prots.m | 4 +- test/SemaObjC/protocol-lookup.m | 2 +- test/SemaObjCXX/protocol-lookup.mm | 2 +- 7 files changed, 126 insertions(+), 42 deletions(-) create mode 100644 test/SemaObjC/method-typecheck-2.m diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e4746372a5..b323d0ebe9 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1114,6 +1114,17 @@ public: const ObjCMethodDecl *PrevMethod, bool matchBasedOnSizeAndAlignment = false); + /// MatchAllMethodDeclarations - Check methods declaraed in interface or + /// or protocol against those declared in their implementations. + void MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, + const llvm::DenseSet &ClsMap, + llvm::DenseSet &InsMapSeen, + llvm::DenseSet &ClsMapSeen, + ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool &IncompleteImpl, + bool ImmediateClass); + /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate /// a selector with a method declaraation for purposes of typechecking diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 0c98a5f44b..80b30bdb74 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -885,6 +885,79 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl); } +/// MatchAllMethodDeclarations - Check methods declaraed in interface or +/// or protocol against those declared in their implementations. +/// +void Sema::MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, + const llvm::DenseSet &ClsMap, + llvm::DenseSet &InsMapSeen, + llvm::DenseSet &ClsMapSeen, + ObjCImplDecl* IMPDecl, + ObjCContainerDecl* CDecl, + bool &IncompleteImpl, + bool ImmediateClass) +{ + // Check and see if instance methods in class interface have been + // implemented in the implementation class. If so, their types match. + for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(Context), + E = CDecl->instmeth_end(Context); I != E; ++I) { + if (InsMapSeen.count((*I)->getSelector())) + continue; + InsMapSeen.insert((*I)->getSelector()); + if (!(*I)->isSynthesized() && + !InsMap.count((*I)->getSelector())) { + if (ImmediateClass) + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + continue; + } + else { + ObjCMethodDecl *ImpMethodDecl = + IMPDecl->getInstanceMethod(Context, (*I)->getSelector()); + ObjCMethodDecl *IntfMethodDecl = + CDecl->getInstanceMethod(Context, (*I)->getSelector()); + assert(IntfMethodDecl && + "IntfMethodDecl is null in ImplMethodsVsClassMethods"); + // ImpMethodDecl may be null as in a @dynamic property. + if (ImpMethodDecl) + WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); + } + } + + // Check and see if class methods in class interface have been + // implemented in the implementation class. If so, their types match. + for (ObjCInterfaceDecl::classmeth_iterator + I = CDecl->classmeth_begin(Context), + E = CDecl->classmeth_end(Context); + I != E; ++I) { + if (ClsMapSeen.count((*I)->getSelector())) + continue; + ClsMapSeen.insert((*I)->getSelector()); + if (!ClsMap.count((*I)->getSelector())) { + if (ImmediateClass) + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + } + else { + ObjCMethodDecl *ImpMethodDecl = + IMPDecl->getClassMethod(Context, (*I)->getSelector()); + ObjCMethodDecl *IntfMethodDecl = + CDecl->getClassMethod(Context, (*I)->getSelector()); + WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); + } + } + if (ObjCInterfaceDecl *I = dyn_cast (CDecl)) { + // Check for any implementation of a methods declared in protocol. + for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), + E = I->protocol_end(); PI != E; ++PI) + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, + (*PI), IncompleteImpl, false); + if (I->getSuperClass()) + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, + I->getSuperClass(), IncompleteImpl, false); + } +} + void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { @@ -933,51 +1006,26 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, } } - for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(Context), - E = CDecl->instmeth_end(Context); I != E; ++I) { - if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) { - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); - continue; - } - - ObjCMethodDecl *ImpMethodDecl = - IMPDecl->getInstanceMethod(Context, (*I)->getSelector()); - ObjCMethodDecl *IntfMethodDecl = - CDecl->getInstanceMethod(Context, (*I)->getSelector()); - assert(IntfMethodDecl && - "IntfMethodDecl is null in ImplMethodsVsClassMethods"); - // ImpMethodDecl may be null as in a @dynamic property. - if (ImpMethodDecl) - WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); - } - llvm::DenseSet ClsMap; - // Check and see if class methods in class interface have been - // implemented in the implementation class. for (ObjCImplementationDecl::classmeth_iterator - I = IMPDecl->classmeth_begin(Context), - E = IMPDecl->classmeth_end(Context); I != E; ++I) + I = IMPDecl->classmeth_begin(Context), + E = IMPDecl->classmeth_end(Context); I != E; ++I) ClsMap.insert((*I)->getSelector()); - for (ObjCInterfaceDecl::classmeth_iterator - I = CDecl->classmeth_begin(Context), - E = CDecl->classmeth_end(Context); - I != E; ++I) - if (!ClsMap.count((*I)->getSelector())) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); - else { - ObjCMethodDecl *ImpMethodDecl = - IMPDecl->getClassMethod(Context, (*I)->getSelector()); - ObjCMethodDecl *IntfMethodDecl = - CDecl->getClassMethod(Context, (*I)->getSelector()); - WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); - } - + // Check for type conflict of methods declared in a class/protocol and + // its implementation; if any. + llvm::DenseSet InsMapSeen, ClsMapSeen; + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, CDecl, + IncompleteImpl, true); // Check the protocol list for unimplemented methods in the @implementation // class. + // Check and see if class methods in class interface have been + // implemented in the implementation class. + if (ObjCInterfaceDecl *I = dyn_cast (CDecl)) { - for (ObjCCategoryDecl::protocol_iterator PI = I->protocol_begin(), + for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), E = I->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, I); diff --git a/test/Analysis/PR2978.m b/test/Analysis/PR2978.m index 2b4c917774..7bc90b8d03 100644 --- a/test/Analysis/PR2978.m +++ b/test/Analysis/PR2978.m @@ -44,7 +44,7 @@ -(id) O{ return 0; } -(void) setO:(id)arg { } -- (void)dealloc +- (id)dealloc { [_X release]; [_Z release]; diff --git a/test/SemaObjC/method-typecheck-2.m b/test/SemaObjC/method-typecheck-2.m new file mode 100644 index 0000000000..d0a091d856 --- /dev/null +++ b/test/SemaObjC/method-typecheck-2.m @@ -0,0 +1,25 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +@protocol P +- (void) doSomethingInProtocol: (float) x; // expected-note {{previous definition is here}} ++ (void) doSomethingClassyInProtocol: (float) x; // expected-note {{previous definition is here}} +- (void) doNothingInProtocol : (float) x; ++ (void) doNothingClassyInProtocol : (float) x; +@end + +@interface I

+- (void) doSomething: (float) x; // expected-note {{previous definition is here}} ++ (void) doSomethingClassy: (int) x; // expected-note {{previous definition is here}} +@end + +@interface Bar : I +@end + +@implementation Bar +- (void) doSomething: (int) x {} // expected-warning {{conflicting parameter types}} ++ (void) doSomethingClassy: (float) x{} // expected-warning {{conflicting parameter types}} +- (void) doSomethingInProtocol: (id) x {} // expected-warning {{conflicting parameter types}} ++ (void) doSomethingClassyInProtocol: (id) x {} // expected-warning {{conflicting parameter types}} +@end + + diff --git a/test/SemaObjC/props-on-prots.m b/test/SemaObjC/props-on-prots.m index a0c6e41f9d..7bee8a0bc3 100644 --- a/test/SemaObjC/props-on-prots.m +++ b/test/SemaObjC/props-on-prots.m @@ -21,7 +21,7 @@ typedef float CGFloat; typedef struct _XCElementInset {} XCElementInset; @protocol XCElementP < NSObject > --(BOOL) vertical; +-(id) vertical; @end @protocol XCElementDisplayDelegateP; @@ -60,6 +60,6 @@ typedef NSObject < XCElementJustifierP > XCElementJustifier; if (_marker && _marker.variableSized) { } } -- vertical { return self; } +- (id)vertical { return self; } - (BOOL)isEqual:x { return 1; } @end diff --git a/test/SemaObjC/protocol-lookup.m b/test/SemaObjC/protocol-lookup.m index 4f928229cd..0f1860d2c8 100644 --- a/test/SemaObjC/protocol-lookup.m +++ b/test/SemaObjC/protocol-lookup.m @@ -39,7 +39,7 @@ return self; } -- (void)dealloc +- dealloc { [_foo release]; [_bar release]; diff --git a/test/SemaObjCXX/protocol-lookup.mm b/test/SemaObjCXX/protocol-lookup.mm index 4f928229cd..0f1860d2c8 100644 --- a/test/SemaObjCXX/protocol-lookup.mm +++ b/test/SemaObjCXX/protocol-lookup.mm @@ -39,7 +39,7 @@ return self; } -- (void)dealloc +- dealloc { [_foo release]; [_bar release];