Contains the following (related to problems found while investigting <rdar://problem/6497631> Message lookup is sometimes different than gcc's).
- Implement instance/class overloading in ObjCContainerDecl (removing a FIXME). This involved hacking NamedDecl::declarationReplaces(), which took awhile to figure out (didn't realize replace was the default).
- Changed Sema::ActOnInstanceMessage() to remove redundant warnings when dealing with protocols. For now, I've omitted the "protocol" term in the diagnostic. It simplifies the code flow and wan't always 100% accurate (e.g. "Foo<Prot>" looks in the class interface, not just the protocol).
- Changed several test cases to jive with the above changes.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65292 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 387f79a..f760852 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 @@
// 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 461bb96..a9f7922 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 @@
//===----------------------------------------------------------------------===//
// 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 e5fefd3..d8f3fd4 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -397,9 +397,6 @@
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 @@
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 @@
// 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 @@
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;