aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclObjC.h1
-rw-r--r--lib/AST/DeclObjC.cpp14
-rw-r--r--lib/Sema/SemaDeclObjC.cpp51
-rw-r--r--test/SemaObjC/no-warn-unimpl-method.m42
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