diff options
-rw-r--r-- | include/clang/AST/DeclObjC.h | 1 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 51 | ||||
-rw-r--r-- | test/SemaObjC/no-warn-unimpl-method.m | 42 |
4 files changed, 91 insertions, 17 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index e8c554b67b..6e89a7ae7b 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -486,6 +486,7 @@ public: // found, we search referenced protocols and class categories. ObjCMethodDecl *lookupInstanceMethod(ASTContext &Context, Selector Sel); ObjCMethodDecl *lookupClassMethod(ASTContext &Context, Selector Sel); + ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName); // Location information, modeled after the Stmt API. SourceLocation getLocStart() const { return getLocation(); } // '@'interface diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index bcd2e08f6d..f4bb895730 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -161,6 +161,20 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable( return NULL; } +/// lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super +/// class whose name is passed as argument. If it is not one of the super classes +/// the it returns NULL. +ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( + const IdentifierInfo*ICName) { + ObjCInterfaceDecl* ClassDecl = this; + while (ClassDecl != NULL) { + if (ClassDecl->getIdentifier() == ICName) + return ClassDecl; + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + /// lookupInstanceMethod - This method returns an instance method by looking in /// the class, its categories, and its super classes (using a linear search). ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(ASTContext &Context, diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 35faa4a5ea..8f580341bd 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -866,29 +866,46 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, const llvm::DenseSet<Selector> &ClsMap, ObjCInterfaceDecl *IDecl) { ObjCInterfaceDecl *Super = IDecl->getSuperClass(); - + ObjCInterfaceDecl *NSIDecl = 0; + if (getLangOptions().NeXTRuntime) { + // check to see if class implements forwardInvocation method and objects + // of this class are derived from 'NSProxy' so that to forward requests + // from one object to another. + // Under such conditions, which means that every method possible is + // implemented in the class, we should not issue "Method definition not + // found" warnings. + // FIXME: Use a general GetUnarySelector method for this. + IdentifierInfo* II = &Context.Idents.get("forwardInvocation"); + Selector fISelector = Context.Selectors.getSelector(1, &II); + if (InsMap.count(fISelector)) + // Is IDecl derived from 'NSProxy'? If so, no instance methods + // need be implemented in the implementation. + NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy")); + } + // If a method lookup fails locally we still need to look and see if // the method was implemented by a base class or an inherited // protocol. This lookup is slow, but occurs rarely in correct code // and otherwise would terminate in a warning. // check unimplemented instance methods. - for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(Context), - E = PDecl->instmeth_end(Context); I != E; ++I) { - ObjCMethodDecl *method = *I; - if (method->getImplementationControl() != ObjCMethodDecl::Optional && - !method->isSynthesized() && !InsMap.count(method->getSelector()) && - (!Super || - !Super->lookupInstanceMethod(Context, method->getSelector()))) { - // Ugly, but necessary. Method declared in protcol might have - // have been synthesized due to a property declared in the class which - // uses the protocol. - ObjCMethodDecl *MethodInClass = - IDecl->lookupInstanceMethod(Context, method->getSelector()); - if (!MethodInClass || !MethodInClass->isSynthesized()) - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); - } - } + if (!NSIDecl) + for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(Context), + E = PDecl->instmeth_end(Context); I != E; ++I) { + ObjCMethodDecl *method = *I; + if (method->getImplementationControl() != ObjCMethodDecl::Optional && + !method->isSynthesized() && !InsMap.count(method->getSelector()) && + (!Super || + !Super->lookupInstanceMethod(Context, method->getSelector()))) { + // Ugly, but necessary. Method declared in protcol might have + // have been synthesized due to a property declared in the class which + // uses the protocol. + ObjCMethodDecl *MethodInClass = + IDecl->lookupInstanceMethod(Context, method->getSelector()); + if (!MethodInClass || !MethodInClass->isSynthesized()) + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + } + } // check unimplemented class methods for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(Context), diff --git a/test/SemaObjC/no-warn-unimpl-method.m b/test/SemaObjC/no-warn-unimpl-method.m new file mode 100644 index 0000000000..756c47b2fe --- /dev/null +++ b/test/SemaObjC/no-warn-unimpl-method.m @@ -0,0 +1,42 @@ +// RUN: clang-cc -triple x86_64-apple-darwin10 -fsyntax-only -verify %s +// This program tests that if class implements the forwardInvocation method, then +// every method possible is implemented in the class and should not issue +// warning of the "Method definition not found" kind. */ + +@interface NSObject +@end + +@interface NSInvocation +@end + +@interface NSProxy +@end + +@protocol MyProtocol + -(void) doSomething; +@end + +@interface DestinationClass : NSObject<MyProtocol> + -(void) doSomething; +@end + +@implementation DestinationClass + -(void) doSomething + { + } +@end + +@interface MyProxy : NSProxy<MyProtocol> +{ + DestinationClass *mTarget; +} + - (id) init; + - (void)forwardInvocation:(NSInvocation *)anInvocation; +@end + +@implementation MyProxy + - (void)forwardInvocation:(NSInvocation *)anInvocation + { + } + - (id) init {} +@end |