diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 2 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 5 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 40 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 39 | ||||
-rw-r--r-- | test/SemaObjC/property-11.m | 5 | ||||
-rw-r--r-- | test/SemaObjC/protocol-id-test-1.m | 2 | ||||
-rw-r--r-- | test/SemaObjC/protocol-id-test-2.m | 4 |
7 files changed, 57 insertions, 40 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index fb9f36399b..2549df6b93 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -916,8 +916,6 @@ DIAG(error_no_super_class, ERROR, "no super class declared in @interface for %0") DIAG(err_invalid_receiver_to_message, ERROR, "invalid receiver to message expression") -DIAG(warn_method_not_found_in_protocol, WARNING, - "method %objcinstance0 not found in protocol (return type defaults to 'id')") DIAG(error_bad_receiver_type, ERROR, "bad receiver type %0") DIAG(error_objc_throw_expects_object, ERROR, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 387f79a013..f7608529d4 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -13,6 +13,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" @@ -194,6 +195,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { // For function declarations, we keep track of redeclarations. return FD->getPreviousDeclaration() == OldD; + // For method declarations, we keep track of redeclarations. + if (isa<ObjCMethodDecl>(this)) + return false; + // For non-function declarations, if the declarations are of the // same kind then this must be a redeclaration, or semantic analysis // would not have given us the new declaration. diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 461bb9697f..a9f7922ed0 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" +#include "llvm/ADT/STLExtras.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -42,21 +43,42 @@ void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { //===----------------------------------------------------------------------===// // Get the local instance method declared in this interface. -// FIXME: handle overloading, instance & class methods can have the same name. ObjCMethodDecl *ObjCContainerDecl::getInstanceMethod(Selector Sel) const { - lookup_const_result MethodResult = lookup(Sel); - if (MethodResult.first) - return const_cast<ObjCMethodDecl*>( - dyn_cast<ObjCMethodDecl>(*MethodResult.first)); + // Since instance & class methods can have the same name, the loop below + // ensures we get the correct method. + // + // @interface Whatever + // - (int) class_method; + // + (float) class_method; + // @end + // + lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = lookup(Sel); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod()) + return MD; + } return 0; } // Get the local class method declared in this interface. ObjCMethodDecl *ObjCContainerDecl::getClassMethod(Selector Sel) const { - lookup_const_result MethodResult = lookup(Sel); - if (MethodResult.first) - return const_cast<ObjCMethodDecl*>( - dyn_cast<ObjCMethodDecl>(*MethodResult.first)); + // Since instance & class methods can have the same name, the loop below + // ensures we get the correct method. + // + // @interface Whatever + // - (int) class_method; + // + (float) class_method; + // @end + // + lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = lookup(Sel); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isClassMethod()) + return MD; + } return 0; } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index e5fefd3e3a..d8f3fd4cf7 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -397,9 +397,6 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) break; } - if (!Method) - Diag(lbrac, diag::warn_method_not_found_in_protocol) - << Sel << RExpr->getSourceRange(); // Check for GCC extension "Class<foo>". } else if (ObjCQualifiedClassType *QIT = dyn_cast<ObjCQualifiedClassType>(ReceiverCType)) { @@ -409,9 +406,6 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) break; } - if (!Method) - Diag(lbrac, diag::warn_method_not_found_in_protocol) - << Sel << RExpr->getSourceRange(); } else if (const ObjCInterfaceType *OCIReceiver = ReceiverCType->getAsPointerToObjCInterfaceType()) { // We allow sending a message to a pointer to an interface (an object). @@ -422,19 +416,29 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, // The idea is to add class info to InstanceMethodPool. Method = ClassDecl->lookupInstanceMethod(Sel); + bool haveQualifiers = false; if (!Method) { // Search protocol qualifiers. for (ObjCQualifiedIdType::qual_iterator QI = OCIReceiver->qual_begin(), E = OCIReceiver->qual_end(); QI != E; ++QI) { + haveQualifiers = true; if ((Method = (*QI)->lookupInstanceMethod(Sel))) break; } } - - if (!Method && !OCIReceiver->qual_empty()) - Diag(lbrac, diag::warn_method_not_found_in_protocol) - << Sel << SourceRange(lbrac, rbrac); - + if (!Method) { + // If we have an implementation in scope, check "private" methods. + if (ClassDecl) + if (ObjCImplementationDecl *ImpDecl = + ObjCImplementations[ClassDecl->getIdentifier()]) + Method = ImpDecl->getInstanceMethod(Sel); + // If we still haven't found a method, look in the global pool. This + // behavior isn't very desirable, however we need it for GCC + // compatibility. FIXME: should we deviate?? + if (!Method && !haveQualifiers) + Method = LookupInstanceMethodInGlobalPool( + Sel, SourceRange(lbrac,rbrac)); + } if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) return true; } else { @@ -443,19 +447,6 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, return true; } - if (!Method) { - // If we have an implementation in scope, check "private" methods. - if (ClassDecl) - if (ObjCImplementationDecl *ImpDecl = - ObjCImplementations[ClassDecl->getIdentifier()]) - Method = ImpDecl->getInstanceMethod(Sel); - // If we still haven't found a method, look in the global pool. This - // behavior isn't very desirable, however we need it for GCC - // compatibility. - if (!Method) - Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - } if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, lbrac, rbrac, returnType)) return true; diff --git a/test/SemaObjC/property-11.m b/test/SemaObjC/property-11.m index 8038328002..d28608aecf 100644 --- a/test/SemaObjC/property-11.m +++ b/test/SemaObjC/property-11.m @@ -22,7 +22,10 @@ NSSound *x; id o; - o = [x foo]; + // GCC does *not* warn about the following. Since foo/setFoo: are not in the + // class or category interface for NSSound, the compiler shouldn't find them. + // For now, we will support GCC's behavior (sigh). + o = [x foo]; o = x.foo; [x setFoo:o]; x.foo = o; diff --git a/test/SemaObjC/protocol-id-test-1.m b/test/SemaObjC/protocol-id-test-1.m index 765500e10d..4e636d7e1c 100644 --- a/test/SemaObjC/protocol-id-test-1.m +++ b/test/SemaObjC/protocol-id-test-1.m @@ -12,5 +12,5 @@ @end @implementation INTF -- (void)IMeth {INTF<P> *pi; [pi Meth]; } // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}} +- (void)IMeth {INTF<P> *pi; [pi Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}} @end diff --git a/test/SemaObjC/protocol-id-test-2.m b/test/SemaObjC/protocol-id-test-2.m index 525d2cca9e..3b4adcfb5b 100644 --- a/test/SemaObjC/protocol-id-test-2.m +++ b/test/SemaObjC/protocol-id-test-2.m @@ -5,10 +5,8 @@ @interface INTF<P> - (void)IMeth; - - (void) Meth; @end @implementation INTF -- (void)IMeth { [(id<P>)self Meth]; } // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}} -- (void) Meth {} +- (void)IMeth { [(id<P>)self Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}} @end |