From f0e00046711280d494f3ef2d85ae67a442b97406 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 16 Jan 2013 18:47:38 +0000 Subject: [PATCH] Teach global selector lookup to ignore hidden methods, which occur when the methods are declared in a submodule that has not yet been imported. Part of . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172635 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclObjC.cpp | 112 ++++++++++++++++----------- test/Modules/Inputs/MethodPoolASub.h | 3 + test/Modules/Inputs/MethodPoolBSub.h | 3 + test/Modules/Inputs/module.map | 8 ++ test/Modules/method_pool.m | 18 +++++ 5 files changed, 97 insertions(+), 47 deletions(-) create mode 100644 test/Modules/Inputs/MethodPoolASub.h create mode 100644 test/Modules/Inputs/MethodPoolBSub.h diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 870c52b6e6..e6c5d92f5e 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2167,61 +2167,79 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, if (Pos == MethodPool.end()) return 0; + // Gather the non-hidden methods. ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; + llvm::SmallVector Methods; + for (ObjCMethodList *M = &MethList; M; M = M->Next) { + if (M->Method && !M->Method->isHidden()) { + // If we're not supposed to warn about mismatches, we're done. + if (!warn) + return M->Method; - if (warn && MethList.Method && MethList.Next) { - bool issueDiagnostic = false, issueError = false; - - // We support a warning which complains about *any* difference in - // method signature. - bool strictSelectorMatch = - (receiverIdOrClass && warn && - (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, - R.getBegin()) != - DiagnosticsEngine::Ignored)); - if (strictSelectorMatch) - for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { - if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, - MMS_strict)) { - issueDiagnostic = true; - break; - } + Methods.push_back(M->Method); + } + } + + // If there aren't any visible methods, we're done. + // FIXME: Recover if there are any known-but-hidden methods? + if (Methods.empty()) + return 0; + + if (Methods.size() == 1) + return Methods[0]; + + // We found multiple methods, so we may have to complain. + bool issueDiagnostic = false, issueError = false; + + // We support a warning which complains about *any* difference in + // method signature. + bool strictSelectorMatch = + (receiverIdOrClass && warn && + (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl, + R.getBegin()) + != DiagnosticsEngine::Ignored)); + if (strictSelectorMatch) { + for (unsigned I = 1, N = Methods.size(); I != N; ++I) { + if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) { + issueDiagnostic = true; + break; } + } + } - // If we didn't see any strict differences, we won't see any loose - // differences. In ARC, however, we also need to check for loose - // mismatches, because most of them are errors. - if (!strictSelectorMatch || - (issueDiagnostic && getLangOpts().ObjCAutoRefCount)) - for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { - // This checks if the methods differ in type mismatch. - if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, - MMS_loose) && - !isAcceptableMethodMismatch(MethList.Method, Next->Method)) { - issueDiagnostic = true; - if (getLangOpts().ObjCAutoRefCount) - issueError = true; - break; - } + // If we didn't see any strict differences, we won't see any loose + // differences. In ARC, however, we also need to check for loose + // mismatches, because most of them are errors. + if (!strictSelectorMatch || + (issueDiagnostic && getLangOpts().ObjCAutoRefCount)) + for (unsigned I = 1, N = Methods.size(); I != N; ++I) { + // This checks if the methods differ in type mismatch. + if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_loose) && + !isAcceptableMethodMismatch(Methods[0], Methods[I])) { + issueDiagnostic = true; + if (getLangOpts().ObjCAutoRefCount) + issueError = true; + break; } + } - if (issueDiagnostic) { - if (issueError) - Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R; - else if (strictSelectorMatch) - Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R; - else - Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; + if (issueDiagnostic) { + if (issueError) + Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R; + else if (strictSelectorMatch) + Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R; + else + Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), - issueError ? diag::note_possibility : diag::note_using) - << MethList.Method->getSourceRange(); - for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - Diag(Next->Method->getLocStart(), diag::note_also_found) - << Next->Method->getSourceRange(); - } + Diag(Methods[0]->getLocStart(), + issueError ? diag::note_possibility : diag::note_using) + << Methods[0]->getSourceRange(); + for (unsigned I = 1, N = Methods.size(); I != N; ++I) { + Diag(Methods[I]->getLocStart(), diag::note_also_found) + << Methods[I]->getSourceRange(); + } } - return MethList.Method; + return Methods[0]; } ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) { diff --git a/test/Modules/Inputs/MethodPoolASub.h b/test/Modules/Inputs/MethodPoolASub.h new file mode 100644 index 0000000000..e0bd238567 --- /dev/null +++ b/test/Modules/Inputs/MethodPoolASub.h @@ -0,0 +1,3 @@ +@interface A (Sub) +- (char)method3; +@end diff --git a/test/Modules/Inputs/MethodPoolBSub.h b/test/Modules/Inputs/MethodPoolBSub.h new file mode 100644 index 0000000000..3404ce91fa --- /dev/null +++ b/test/Modules/Inputs/MethodPoolBSub.h @@ -0,0 +1,3 @@ +@interface B (Sub) +- (char *)method3; +@end diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 702f5c11cd..42c6c2b5d9 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -107,9 +107,17 @@ module templates_right { } module MethodPoolA { header "MethodPoolA.h" + + explicit module Sub { + header "MethodPoolASub.h" + } } module MethodPoolB { header "MethodPoolB.h" + + explicit module Sub { + header "MethodPoolBSub.h" + } } module import_decl { header "import-decl.h" diff --git a/test/Modules/method_pool.m b/test/Modules/method_pool.m index 9574caa152..1ba5abd139 100644 --- a/test/Modules/method_pool.m +++ b/test/Modules/method_pool.m @@ -28,3 +28,21 @@ void testMethod1Again(id object) { void testMethod2Again(id object) { [object method2:1]; // expected-warning{{multiple methods named 'method2:' found}} } + +void testMethod3(id object) { + [object method3]; // expected-warning{{instance method '-method3' not found (return type defaults to 'id')}} +} + +@import MethodPoolB.Sub; + +void testMethod3Again(id object) { + char *str = [object method3]; // okay: only found in MethodPoolB.Sub +} + +@import MethodPoolA.Sub; + +void testMethod3AgainAgain(id object) { + [object method3]; // expected-warning{{multiple methods named 'method3' found}} + // expected-note@2{{using}} + // expected-note@2{{also found}} +} -- 2.40.0