<div class="gmail_quote">On Thu, Aug 18, 2011 at 1:38 PM, Eli Friedman <span dir="ltr"><<a href="mailto:eli.friedman@gmail.com">eli.friedman@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="HOEnZb"><div></div><div class="h5">On Thu, Aug 18, 2011 at 11:19 AM, Kaelyn Uhrain <<a href="mailto:rikka@google.com">rikka@google.com</a>> wrote:<br>
> Author: rikka<br>
> Date: Thu Aug 18 13:19:12 2011<br>
> New Revision: 137966<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=137966&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=137966&view=rev</a><br>
> Log:<br>
> Rework DiagnoseInvalidRedeclaration to add the ability to correct typos when<br>
> diagnosing invalid function redeclarations.<br>
><br>
> Modified:<br>
>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
>    cfe/trunk/lib/Sema/SemaDecl.cpp<br>
>    cfe/trunk/test/SemaCXX/function-redecl.cpp<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=137966&r1=137965&r2=137966&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=137966&r1=137965&r2=137966&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug 18 13:19:12 2011<br>
> @@ -610,6 +610,8 @@<br>
>   "friend type templates must use an elaborated type">;<br>
>  def err_no_matching_local_friend : Error<<br>
>   "no matching function found in local scope">;<br>
> +def err_no_matching_local_friend_suggest : Error<<br>
> +  "no matching function %0 found in local scope; did you mean %2">;<br>
>  def err_partial_specialization_friend : Error<<br>
>   "partial specialization cannot be declared as a friend">;<br>
><br>
> @@ -3038,6 +3040,9 @@<br>
>   "out-of-line definition of %0 from class %1 without definition">;<br>
>  def err_member_def_does_not_match : Error<<br>
>   "out-of-line definition of %0 does not match any declaration in %1">;<br>
> +def err_member_def_does_not_match_suggest : Error<<br>
> +  "out-of-line definition of %0 does not match any declaration in %1; "<br>
> +  "did you mean %2">;<br>
>  def err_member_def_does_not_match_ret_type : Error<<br>
>   "out-of-line definition of %q0 differs from the declaration in the return type">;<br>
>  def err_nonstatic_member_out_of_line : Error<<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=137966&r1=137965&r2=137966&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=137966&r1=137965&r2=137966&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 18 13:19:12 2011<br>
> @@ -4204,28 +4204,79 @@<br>
>   return AddedAny;<br>
>  }<br>
><br>
> -static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {<br>
> -  LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(),<br>
> +static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD,<br>
> +                                         bool isFriendDecl) {<br>
> +  DeclarationName Name = NewFD->getDeclName();<br>
> +  DeclContext *DC = NewFD->getDeclContext();<br>
> +  LookupResult Prev(S, Name, NewFD->getLocation(),<br>
>                     Sema::LookupOrdinaryName, Sema::ForRedeclaration);<br>
>   llvm::SmallVector<unsigned, 1> MismatchedParams;<br>
> -  S.LookupQualifiedName(Prev, NewFD->getDeclContext());<br>
> +  llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches;<br>
> +  TypoCorrection Correction;<br>
> +  unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend<br>
> +                                  : diag::err_member_def_does_not_match;<br>
> +<br>
> +  NewFD->setInvalidDecl();<br>
> +  S.LookupQualifiedName(Prev, DC);<br>
>   assert(!Prev.isAmbiguous() &&<br>
>          "Cannot have an ambiguity in previous-declaration lookup");<br>
> -  for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();<br>
> -       Func != FuncEnd; ++Func) {<br>
> -    FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);<br>
> -    if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,<br>
> -                                       MismatchedParams)) {<br>
> -      if (MismatchedParams.size() > 0) {<br>
> -        unsigned Idx = MismatchedParams.front();<br>
> -        ParmVarDecl *FDParam = FD->getParamDecl(Idx);<br>
> -        S.Diag(FDParam->getTypeSpecStartLoc(),<br>
> -               diag::note_member_def_close_param_match)<br>
> -            << Idx+1 << FDParam->getType() << NewFD->getParamDecl(Idx)->getType();<br>
> -      } else<br>
> -        S.Diag(FD->getLocation(), diag::note_member_def_close_match);<br>
> +  if (!Prev.empty()) {<br>
> +    for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();<br>
> +         Func != FuncEnd; ++Func) {<br>
> +      FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);<br>
> +      if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,<br>
> +                                         MismatchedParams)) {<br>
> +        // Add 1 to the index so that 0 can mean the mismatch didn't<br>
> +        // involve a parameter<br>
> +        unsigned ParamNum =<br>
> +            MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1;<br>
> +        NearMatches.push_back(std::make_pair(FD, ParamNum));<br>
> +      }<br>
> +    }<br>
> +  // If the qualified name lookup yielded nothing, try typo correction<br>
> +  } else if ((Correction = S.CorrectTypo(Prev.getLookupNameInfo(),<br>
> +                                         Prev.getLookupKind(), 0, 0, DC))) {<br>
> +    DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest<br>
> +                           : diag::err_member_def_does_not_match_suggest;<br>
> +    for (TypoCorrection::decl_iterator CDecl = Correction.begin(),<br>
> +                                    CDeclEnd = Correction.end();<br>
> +         CDecl != CDeclEnd; ++CDecl) {<br>
> +      FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);<br>
> +      if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,<br>
> +                                         MismatchedParams)) {<br>
> +        // Add 1 to the index so that 0 can mean the mismatch didn't<br>
> +        // involve a parameter<br>
> +        unsigned ParamNum =<br>
> +            MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1;<br>
> +        NearMatches.push_back(std::make_pair(FD, ParamNum));<br>
> +      }<br>
>     }<br>
>   }<br>
> +<br>
> +  if (Correction)<br>
> +    S.Diag(NewFD->getLocation(), DiagMsg)<br>
> +        << Name << DC << Correction.getQuoted(S.getLangOptions())<br>
> +        << FixItHint::CreateReplacement(<br>
> +            NewFD->getLocation(), Correction.getAsString(S.getLangOptions()));<br>
> +  else<br>
> +    S.Diag(NewFD->getLocation(), DiagMsg) << Name << DC << NewFD->getLocation();<br>
> +<br>
> +  for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator<br>
> +       NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();<br>
> +       NearMatch != NearMatchEnd; ++NearMatch) {<br>
> +    FunctionDecl *FD = NearMatch->first;<br>
> +<br>
> +    if (unsigned Idx = NearMatch->second) {<br>
> +      ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);<br>
> +      S.Diag(FDParam->getTypeSpecStartLoc(),<br>
> +             diag::note_member_def_close_param_match)<br>
> +          << Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType();<br>
> +    } else if (Correction) {<br>
> +      S.Diag(FD->getLocation(), diag::note_previous_decl)<br>
> +        << Correction.getQuoted(S.getLangOptions());<br>
> +    } else<br>
> +      S.Diag(FD->getLocation(), diag::note_member_def_close_match);<br>
> +  }<br>
>  }<br>
><br>
>  NamedDecl*<br>
> @@ -4939,19 +4990,14 @@<br>
>               // Complain about this problem, and attempt to suggest close<br>
>               // matches (e.g., those that differ only in cv-qualifiers and<br>
>               // whether the parameter types are references).<br>
> -              Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)<br>
> -              << Name << DC << D.getCXXScopeSpec().getRange();<br>
> -              NewFD->setInvalidDecl();<br>
><br>
> -              DiagnoseInvalidRedeclaration(*this, NewFD);<br>
> +              DiagnoseInvalidRedeclaration(*this, NewFD, false);<br>
>             }<br>
><br>
>         // Unqualified local friend declarations are required to resolve<br>
>         // to something.<br>
>         } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {<br>
> -          Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend);<br>
> -          NewFD->setInvalidDecl();<br>
> -          DiagnoseInvalidRedeclaration(*this, NewFD);<br>
> +          DiagnoseInvalidRedeclaration(*this, NewFD, true);<br>
>         }<br>
><br>
>     } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&<br>
><br>
> Modified: cfe/trunk/test/SemaCXX/function-redecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=137966&r1=137965&r2=137966&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=137966&r1=137965&r2=137966&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/function-redecl.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/function-redecl.cpp Thu Aug 18 13:19:12 2011<br>
> @@ -24,3 +24,29 @@<br>
>     }<br>
>   }<br>
>  }<br>
> +<br>
> +class A {<br>
> + void typocorrection(); // expected-note {{'typocorrection' declared here}}<br>
> +};<br>
> +<br>
> +void A::Notypocorrection() { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'A'; did you mean 'typocorrection'}}<br>
> +}<br>
> +<br>
> +<br>
> +namespace test0 {<br>
> +  void dummy() {<br>
> +    void Bar(); // expected-note {{'Bar' declared here}}<br>
> +    class A {<br>
> +      friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean 'Bar'}}<br>
> +    };<br>
> +  }<br>
> +}<br>
> +<br>
> +<br>
> +class B {<br>
> + void typocorrection(const int); // expected-note {{type of 1st parameter of member declaration does not match definition}}<br>
> + void typocorrection(double);<br>
> +};<br>
> +<br>
> +void B::Notypocorrection(int) { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'B'; did you mean 'typocorrection'}}<br>
> +}<br>
<br>
</div></div>This is giving an extremely strange-looking error for the following:<br></blockquote><div><br></div><div>Looks like its doing really nice qualifier-based typo correction, but failing to mention those qualified names in the diagnostic, or suggest the fixit hint for the qualifier itself... This works for other contexts though so hopefully it doesn't require a huge change to fix.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
struct A { int f(); };<br>
struct B : public A {};<br>
int B::f() { return 3; }<br>
<br>
<stdin>:3:8: error: out-of-line definition of 'f' does not match any<br>
declaration in 'B'; did you mean 'f'<br>
int B::f() { return 3; }<br>
       ^<br>
       f<br>
<stdin>:1:16: note: 'f' declared here<br>
struct A { int f(); };<br>
               ^<br>
1 error generated.<br>
<span class="HOEnZb"><font color="#888888"><br>
-Eli<br>
</font></span><div class="HOEnZb"><div></div><div class="h5"><br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</div></div></blockquote></div><br>