From 516116308007280f0dd6661cdd94112468c3c5fc Mon Sep 17 00:00:00 2001 From: Kaelyn Uhrain Date: Thu, 18 Aug 2011 18:19:12 +0000 Subject: [PATCH] Rework DiagnoseInvalidRedeclaration to add the ability to correct typos when diagnosing invalid function redeclarations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137966 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 5 ++ lib/Sema/SemaDecl.cpp | 92 ++++++++++++++++------ test/SemaCXX/function-redecl.cpp | 26 ++++++ 3 files changed, 100 insertions(+), 23 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 13f3dbc1d4..1c49a723d1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -610,6 +610,8 @@ def err_tagless_friend_type_template : Error< "friend type templates must use an elaborated type">; def err_no_matching_local_friend : Error< "no matching function found in local scope">; +def err_no_matching_local_friend_suggest : Error< + "no matching function %0 found in local scope; did you mean %2">; def err_partial_specialization_friend : Error< "partial specialization cannot be declared as a friend">; @@ -3038,6 +3040,9 @@ def err_member_def_undefined_record : Error< "out-of-line definition of %0 from class %1 without definition">; def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; +def err_member_def_does_not_match_suggest : Error< + "out-of-line definition of %0 does not match any declaration in %1; " + "did you mean %2">; def err_member_def_does_not_match_ret_type : Error< "out-of-line definition of %q0 differs from the declaration in the return type">; def err_nonstatic_member_out_of_line : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 67493c7716..898fca4203 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4204,28 +4204,79 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { return AddedAny; } -static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) { - LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(), +static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD, + bool isFriendDecl) { + DeclarationName Name = NewFD->getDeclName(); + DeclContext *DC = NewFD->getDeclContext(); + LookupResult Prev(S, Name, NewFD->getLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); llvm::SmallVector MismatchedParams; - S.LookupQualifiedName(Prev, NewFD->getDeclContext()); + llvm::SmallVector, 1> NearMatches; + TypoCorrection Correction; + unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend + : diag::err_member_def_does_not_match; + + NewFD->setInvalidDecl(); + S.LookupQualifiedName(Prev, DC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); - for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); - Func != FuncEnd; ++Func) { - FunctionDecl *FD = dyn_cast(*Func); - if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD, - MismatchedParams)) { - if (MismatchedParams.size() > 0) { - unsigned Idx = MismatchedParams.front(); - ParmVarDecl *FDParam = FD->getParamDecl(Idx); - S.Diag(FDParam->getTypeSpecStartLoc(), - diag::note_member_def_close_param_match) - << Idx+1 << FDParam->getType() << NewFD->getParamDecl(Idx)->getType(); - } else - S.Diag(FD->getLocation(), diag::note_member_def_close_match); + if (!Prev.empty()) { + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); + Func != FuncEnd; ++Func) { + FunctionDecl *FD = dyn_cast(*Func); + if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD, + MismatchedParams)) { + // Add 1 to the index so that 0 can mean the mismatch didn't + // involve a parameter + unsigned ParamNum = + MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1; + NearMatches.push_back(std::make_pair(FD, ParamNum)); + } + } + // If the qualified name lookup yielded nothing, try typo correction + } else if ((Correction = S.CorrectTypo(Prev.getLookupNameInfo(), + Prev.getLookupKind(), 0, 0, DC))) { + DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest + : diag::err_member_def_does_not_match_suggest; + for (TypoCorrection::decl_iterator CDecl = Correction.begin(), + CDeclEnd = Correction.end(); + CDecl != CDeclEnd; ++CDecl) { + FunctionDecl *FD = dyn_cast(*CDecl); + if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD, + MismatchedParams)) { + // Add 1 to the index so that 0 can mean the mismatch didn't + // involve a parameter + unsigned ParamNum = + MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1; + NearMatches.push_back(std::make_pair(FD, ParamNum)); + } } } + + if (Correction) + S.Diag(NewFD->getLocation(), DiagMsg) + << Name << DC << Correction.getQuoted(S.getLangOptions()) + << FixItHint::CreateReplacement( + NewFD->getLocation(), Correction.getAsString(S.getLangOptions())); + else + S.Diag(NewFD->getLocation(), DiagMsg) << Name << DC << NewFD->getLocation(); + + for (llvm::SmallVector, 1>::iterator + NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end(); + NearMatch != NearMatchEnd; ++NearMatch) { + FunctionDecl *FD = NearMatch->first; + + if (unsigned Idx = NearMatch->second) { + ParmVarDecl *FDParam = FD->getParamDecl(Idx-1); + S.Diag(FDParam->getTypeSpecStartLoc(), + diag::note_member_def_close_param_match) + << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType(); + } else if (Correction) { + S.Diag(FD->getLocation(), diag::note_previous_decl) + << Correction.getQuoted(S.getLangOptions()); + } else + S.Diag(FD->getLocation(), diag::note_member_def_close_match); + } } NamedDecl* @@ -4939,19 +4990,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Complain about this problem, and attempt to suggest close // matches (e.g., those that differ only in cv-qualifiers and // whether the parameter types are references). - Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) - << Name << DC << D.getCXXScopeSpec().getRange(); - NewFD->setInvalidDecl(); - DiagnoseInvalidRedeclaration(*this, NewFD); + DiagnoseInvalidRedeclaration(*this, NewFD, false); } // Unqualified local friend declarations are required to resolve // to something. } else if (isFriend && cast(CurContext)->isLocalClass()) { - Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend); - NewFD->setInvalidDecl(); - DiagnoseInvalidRedeclaration(*this, NewFD); + DiagnoseInvalidRedeclaration(*this, NewFD, true); } } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp index b15d866165..8c734945f2 100644 --- a/test/SemaCXX/function-redecl.cpp +++ b/test/SemaCXX/function-redecl.cpp @@ -24,3 +24,29 @@ namespace N { } } } + +class A { + void typocorrection(); // expected-note {{'typocorrection' declared here}} +}; + +void A::Notypocorrection() { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'A'; did you mean 'typocorrection'}} +} + + +namespace test0 { + void dummy() { + void Bar(); // expected-note {{'Bar' declared here}} + class A { + friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean 'Bar'}} + }; + } +} + + +class B { + void typocorrection(const int); // expected-note {{type of 1st parameter of member declaration does not match definition}} + void typocorrection(double); +}; + +void B::Notypocorrection(int) { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'B'; did you mean 'typocorrection'}} +} -- 2.40.0