[cfe-commits] r141609 - in /cfe/trunk: lib/Sema/SemaDecl.cpp test/SemaCXX/function-redecl.cpp

Kaelyn Uhrain rikka at google.com
Mon Oct 10 17:28:39 PDT 2011


Author: rikka
Date: Mon Oct 10 19:28:39 2011
New Revision: 141609

URL: http://llvm.org/viewvc/llvm-project?rev=141609&view=rev
Log:
Only accept a typo correction if it doesn't trigger additional errors

Modified:
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/SemaCXX/function-redecl.cpp

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=141609&r1=141608&r2=141609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Oct 10 19:28:39 2011
@@ -2958,13 +2958,14 @@
   } while (true);
 }
 
-/// isNearlyMatchingFunction - Determine whether the C++ functions
-/// Declaration and Definition are "nearly" matching. This heuristic
-/// is used to improve diagnostics in the case where an out-of-line
-/// function definition doesn't match any declaration within the class
-/// or namespace. Also sets Params to the list of indices to the
-/// parameters that differ between the declaration and the definition.
-static bool isNearlyMatchingFunction(ASTContext &Context,
+/// hasSimilarParameters - Determine whether the C++ functions Declaration
+/// and Definition have "nearly" matching parameters. This heuristic is
+/// used to improve diagnostics in the case where an out-of-line function
+/// definition doesn't match any declaration within the class or namespace.
+/// Also sets Params to the list of indices to the parameters that differ
+/// between the declaration and the definition. If hasSimilarParameters
+/// returns true and Params is empty, then all of the parameters match.
+static bool hasSimilarParameters(ASTContext &Context,
                                      FunctionDecl *Declaration,
                                      FunctionDecl *Definition,
                                      llvm::SmallVectorImpl<unsigned> &Params) {
@@ -4302,10 +4303,38 @@
   return AddedAny;
 }
 
-static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD,
-                                         bool isFriendDecl) {
+namespace {
+  // Struct for holding all of the extra arguments needed by
+  // DiagnoseInvalidRedeclaration to call Sema::ActOnFunctionDeclarator.
+  struct ActOnFDArgs {
+    Scope *S;
+    Declarator &D;
+    DeclContext *DC;
+    QualType R;
+    TypeSourceInfo *TInfo;
+    MultiTemplateParamsArg TemplateParamLists;
+    bool IsFunctionDefinition;
+    bool Redeclaration;
+    bool AddToScope;
+  };
+}
+
+/// \brief Generate diagnostics for an invalid function redeclaration.
+///
+/// This routine handles generating the diagnostic messages for an invalid
+/// function redeclaration, including finding possible similar declarations
+/// or performing typo correction if there are no previous declarations with
+/// the same name.
+///
+/// Returns a NamedDecl iff typo correction was performed and substituting in
+/// the new declaration name does not cause new errors.
+static NamedDecl* DiagnoseInvalidRedeclaration(
+    Sema &S, LookupResult &Previous, FunctionDecl *NewFD, bool isFriendDecl,
+    ActOnFDArgs &ExtraArgs) {
+  assert(NewFD->getDeclContext() == ExtraArgs.DC && "NewFD has different DeclContext!");
+  NamedDecl *Result = NULL;
   DeclarationName Name = NewFD->getDeclName();
-  DeclContext *DC = NewFD->getDeclContext();
+  DeclContext *NewDC = NewFD->getDeclContext();
   LookupResult Prev(S, Name, NewFD->getLocation(),
                     Sema::LookupOrdinaryName, Sema::ForRedeclaration);
   llvm::SmallVector<unsigned, 1> MismatchedParams;
@@ -4315,15 +4344,14 @@
                                   : diag::err_member_def_does_not_match;
 
   NewFD->setInvalidDecl();
-  S.LookupQualifiedName(Prev, DC);
+  S.LookupQualifiedName(Prev, NewDC);
   assert(!Prev.isAmbiguous() &&
          "Cannot have an ambiguity in previous-declaration lookup");
   if (!Prev.empty()) {
     for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
          Func != FuncEnd; ++Func) {
       FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);
-      if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,
-                                         MismatchedParams)) {
+      if (FD && hasSimilarParameters(S.Context, FD, NewFD, MismatchedParams)) {
         // Add 1 to the index so that 0 can mean the mismatch didn't
         // involve a parameter
         unsigned ParamNum =
@@ -4333,37 +4361,64 @@
     }
   // If the qualified name lookup yielded nothing, try typo correction
   } else if ((Correction = S.CorrectTypo(Prev.getLookupNameInfo(),
-                                         Prev.getLookupKind(), 0, 0, DC)) &&
+                                         Prev.getLookupKind(), 0, 0, NewDC)) &&
              Correction.getCorrection() != Name) {
+    // Trap errors.
+    Sema::SFINAETrap Trap(S);
+
+    // Set up everything for the call to ActOnFunctionDeclarator
+    ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
+                              ExtraArgs.D.getIdentifierLoc());
+    Previous.clear();
+    Previous.setLookupName(Correction.getCorrection());
     for (TypoCorrection::decl_iterator CDecl = Correction.begin(),
                                     CDeclEnd = Correction.end();
          CDecl != CDeclEnd; ++CDecl) {
       FunctionDecl *FD = dyn_cast<FunctionDecl>(*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 (FD && hasSimilarParameters(S.Context, FD, NewFD, MismatchedParams)) {
+        Previous.addDecl(FD);
+      }
+    }
+    // TODO: Refactor ActOnFunctionDeclarator so that we can call only the
+    // pieces need to verify the typo-corrected C++ declaraction and hopefully
+    // eliminate the need for the parameter pack ExtraArgs.
+    Result = S.ActOnFunctionDeclarator(ExtraArgs.S, ExtraArgs.D, ExtraArgs.DC,
+                                       ExtraArgs.R, ExtraArgs.TInfo, Previous,
+                                       ExtraArgs.TemplateParamLists,
+                                       ExtraArgs.IsFunctionDefinition,
+                                       ExtraArgs.Redeclaration,
+                                       ExtraArgs.AddToScope);
+    if (Trap.hasErrorOccurred()) {
+      // Pretend the typo correction never occurred
+      ExtraArgs.D.SetIdentifier(Name.getAsIdentifierInfo(),
+                                ExtraArgs.D.getIdentifierLoc());
+      Previous.clear();
+      Previous.setLookupName(Name);
+      Result = NULL;
+    } else {
+      for (LookupResult::iterator Func = Previous.begin(),
+                               FuncEnd = Previous.end();
+           Func != FuncEnd; ++Func) {
+        if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func))
+          NearMatches.push_back(std::make_pair(FD, 0));
       }
     }
-    if (!NearMatches.empty())
+    if (NearMatches.empty()) {
+      // Ignore the correction if it didn't yield any close FunctionDecl matches
+      Correction = TypoCorrection();
+    } else {
       DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest
                              : diag::err_member_def_does_not_match_suggest;
+    }
   }
 
-  // Ignore the correction if it didn't yield any close FunctionDecl matches
-  if (Correction && NearMatches.empty())
-    Correction = TypoCorrection();
-
   if (Correction)
     S.Diag(NewFD->getLocation(), DiagMsg)
-        << Name << DC << Correction.getQuoted(S.getLangOptions())
+        << Name << NewDC << Correction.getQuoted(S.getLangOptions())
         << FixItHint::CreateReplacement(
             NewFD->getLocation(), Correction.getAsString(S.getLangOptions()));
   else
-    S.Diag(NewFD->getLocation(), DiagMsg) << Name << DC << NewFD->getLocation();
+    S.Diag(NewFD->getLocation(), DiagMsg) << Name << NewDC << NewFD->getLocation();
 
   bool NewFDisConst = false;
   if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
@@ -4391,6 +4446,7 @@
     } else
       S.Diag(FD->getLocation(), diag::note_member_def_close_match);
   }
+  return Result;
 }
 
 NamedDecl*
@@ -5108,6 +5164,9 @@
     if (NewFD->isInvalidDecl()) {
       // Ignore all the rest of this.
     } else if (!Redeclaration) {
+      struct ActOnFDArgs ExtraArgs = { S, D, DC, R, TInfo, TemplateParamLists,
+                                       IsFunctionDefinition, Redeclaration,
+                                       AddToScope };
       // Fake up an access specifier if it's supposed to be a class member.
       if (isa<CXXRecordDecl>(NewFD->getDeclContext()))
         NewFD->setAccess(AS_public);
@@ -5144,13 +5203,25 @@
           // matches (e.g., those that differ only in cv-qualifiers and
           // whether the parameter types are references).
 
-          DiagnoseInvalidRedeclaration(*this, NewFD, false);
+          if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
+                                                               NewFD, false,
+                                                               ExtraArgs)) {
+            Redeclaration = ExtraArgs.Redeclaration;
+            AddToScope = ExtraArgs.AddToScope;
+            return Result;
+          }
         }
 
         // Unqualified local friend declarations are required to resolve
         // to something.
       } else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {
-        DiagnoseInvalidRedeclaration(*this, NewFD, true);
+        if (NamedDecl *Result = DiagnoseInvalidRedeclaration(*this, Previous,
+                                                             NewFD, true,
+                                                             ExtraArgs)) {
+          Redeclaration = ExtraArgs.Redeclaration;
+          AddToScope = ExtraArgs.AddToScope;
+          return Result;
+        }
       }
 
     } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&

Modified: cfe/trunk/test/SemaCXX/function-redecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=141609&r1=141608&r2=141609&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/function-redecl.cpp (original)
+++ cfe/trunk/test/SemaCXX/function-redecl.cpp Mon Oct 10 19:28:39 2011
@@ -44,7 +44,7 @@
 
 
 class B {
- void typocorrection(const int); // expected-note {{type of 1st parameter of member declaration does not match definition}}
+ void typocorrection(const int); // expected-note {{'typocorrection' declared here}}
  void typocorrection(double);
 };
 
@@ -92,3 +92,6 @@
 
 void TestConst::setit(int) const { // expected-error {{out-of-line definition of 'setit' does not match any declaration in 'TestConst'}}
 }
+
+struct J { int typo() const; };
+int J::typo_() { return 3; } // expected-error {{out-of-line definition of 'typo_' does not match any declaration in 'J'}}





More information about the cfe-commits mailing list