]> granicus.if.org Git - clang/commitdiff
Fix typo correction of one qualified name to another.
authorDavid Blaikie <dblaikie@gmail.com>
Fri, 12 Oct 2012 20:00:44 +0000 (20:00 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Fri, 12 Oct 2012 20:00:44 +0000 (20:00 +0000)
When suggesting "foo::bar" as a correction for "fob::bar" we mistakenly
replaced only "bar" with "foo::bar" producing "fob::foo::bar" which was broken.

This corrects that replacement in as many places as I could find & provides
test cases for all those cases I could find a test case for. There are a couple
that don't seem to be reachable (one looks entirely dead, the other just
doesn't seem to ever get called with a namespace to namespace change).

Review by Richard Smith ( http://llvm-reviews.chandlerc.com/D57 ).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165817 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/TypoCorrection.h
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprMember.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplate.cpp
test/FixIt/typo.cpp

index a8f6e1178b72e67d2613510e4ae366d337333a8f..2b4a9e62167bd7882a6e146d9c752853cec73de7 100644 (file)
@@ -170,6 +170,17 @@ public:
     return CorrectionDecls.size() > 1;
   }
 
+  void setCorrectionRange(CXXScopeSpec* SS,
+                          const DeclarationNameInfo &TypoName) {
+    CorrectionRange.setBegin(CorrectionNameSpec && SS ? SS->getBeginLoc()
+                                                      : TypoName.getLoc());
+    CorrectionRange.setEnd(TypoName.getLoc());
+  }
+
+  SourceRange getCorrectionRange() const {
+    return CorrectionRange;
+  }
+
   typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator;
   decl_iterator begin() {
     return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
@@ -193,6 +204,7 @@ private:
   unsigned CharDistance;
   unsigned QualifierDistance;
   unsigned CallbackDistance;
+  SourceRange CorrectionRange;
 };
 
 /// @brief Base class for callback objects used by Sema::CorrectTypo to check
index 0de9dd5f64c9b50bb511f2bd01891c7c9f52e7d8..15bfd1ce629482bd64b0dfb8b2fce791359a4586 100644 (file)
@@ -520,7 +520,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
       if (LookupCtx)
         Diag(Found.getNameLoc(), diag::err_no_member_suggest)
           << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
-          << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
+          << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                          CorrectedStr);
       else
         Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
           << Name << CorrectedQuotedStr
index aec5f01a91abd7b68785cd424bee2fa56d51a47e..ee246b81a6025bc3a4b9586fe6a9bd9615415e15 100644 (file)
@@ -435,7 +435,8 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
       else if (DeclContext *DC = computeDeclContext(*SS, false))
         Diag(IILoc, diag::err_unknown_nested_typename_suggest)
           << II << DC << CorrectedQuotedStr << SS->getRange()
-          << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+          << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                          CorrectedStr);
       else
         llvm_unreachable("could not have corrected a typo here");
 
@@ -684,11 +685,12 @@ Corrected:
           Diag(NameLoc, UnqualifiedDiag)
             << Name << CorrectedQuotedStr
             << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
-        else
+        else // FIXME: is this even reachable? Test it.
           Diag(NameLoc, QualifiedDiag)
             << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
             << SS.getRange()
-            << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
+            << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                            CorrectedStr);
 
         // Update the name, so that the caller has the new name.
         Name = Corrected.getCorrectionAsIdentifierInfo();
@@ -4894,6 +4896,10 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
   }
 
   if (Correction) {
+    // FIXME: use Correction.getCorrectionRange() instead of computing the range
+    // here. This requires passing in the CXXScopeSpec to CorrectTypo which in
+    // turn causes the correction to fully qualify the name. If we fix
+    // CorrectTypo to minimally qualify then this change should be good.
     SourceRange FixItLoc(NewFD->getLocation());
     CXXScopeSpec &SS = ExtraArgs.D.getCXXScopeSpec();
     if (Correction.getCorrectionSpecifier() && SS.isValid())
index 12452b2429b051fe7b52d78c7f5db9e54b50621a..8d891a37e73b587eae5855f4d6b96a2016c4261c 100644 (file)
@@ -5811,7 +5811,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
     if (DeclContext *DC = S.computeDeclContext(SS, false))
       S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
         << Ident << DC << CorrectedQuotedStr << SS.getRange()
-        << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+        << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                        CorrectedStr);
     else
       S.Diag(IdentLoc, diag::err_using_directive_suggest)
         << Ident << CorrectedQuotedStr
index 74ee87001247672ce2a2e39fa3024ac33eb68f50..3d66baa925907d02f6fe95d374bafcd977309483 100644 (file)
@@ -1640,7 +1640,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
           Diag(R.getNameLoc(), diag::err_no_member_suggest)
             << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
             << SS.getRange()
-            << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+            << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                            CorrectedStr);
         if (ND)
           Diag(ND->getLocation(), diag::note_previous_decl)
             << CorrectedQuotedStr;
index a44fbf2424e221969922aea27f6b1bd2198fae09..2b202ed9a1a72efff948a314bd0c8ef97536dfe4 100644 (file)
@@ -606,7 +606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
     R.addDecl(ND);
     SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
       << Name << DC << CorrectedQuotedStr << SS.getRange()
-      << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+      << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                      CorrectedStr);
     SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
       << ND->getDeclName();
   }
index d5efd757c8c05ff31982d71749d78cba0685741a..e4dab053e2b8824d5aeaf7dbb5b06d4130680971 100644 (file)
@@ -4056,7 +4056,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
     if (IsUnqualifiedLookup)
       UnqualifiedTyposCorrected[Typo] = Result;
 
-    return Result;
+    TypoCorrection TC = Result;
+    TC.setCorrectionRange(SS, TypoName);
+    return TC;
   }
   else if (BestResults.size() > 1
            // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver;
@@ -4076,7 +4078,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
     if (IsUnqualifiedLookup)
       UnqualifiedTyposCorrected[Typo] = BestResults["super"].front();
 
-    return BestResults["super"].front();
+    TypoCorrection TC = BestResults["super"].front();
+    TC.setCorrectionRange(SS, TypoName);
+    return TC;
   }
 
   // If this was an unqualified lookup and we believe the callback object did
index 0efe710acc1b9c50d021cf1cfcb0c98fdb9258d6..f56b05406d075a93c98f6df966ff1597a68459f0 100644 (file)
@@ -333,7 +333,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
         if (LookupCtx)
           Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
             << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
-            << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
+            << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                            CorrectedStr);
         else
           Diag(Found.getNameLoc(), diag::err_no_template_suggest)
             << Name << CorrectedQuotedStr
index 3d40da8d256a17abbf5550adac3db3643e1de05a..b3568a5bbf7329f26b3dc39884a679b9d0f76747 100644 (file)
@@ -5,7 +5,8 @@
 // RUN: grep test_string %t
 
 namespace std {
-  template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}}
+  template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}} \
+                                            // expected-note {{'otherstd::basic_string' declared here}}
   public:
     int find(const char *substr); // expected-note{{'find' declared here}}
     static const int npos = -1; // expected-note{{'npos' declared here}}
@@ -76,13 +77,50 @@ int foo() {
 }
 
 namespace nonstd {
-  typedef std::basic_string<char> yarn; // expected-note{{'nonstd::yarn' declared here}}
+  typedef std::basic_string<char> yarn; // expected-note 2 {{'nonstd::yarn' declared here}}
+  int narf; // expected-note{{'nonstd::narf' declared here}}
 }
 
 yarn str4; // expected-error{{unknown type name 'yarn'; did you mean 'nonstd::yarn'?}}
+wibble::yarn str5; // expected-error{{no type named 'yarn' in namespace 'otherstd'; did you mean 'nonstd::yarn'?}}
+
+int poit() {
+  nonstd::basic_string<char> str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean 'otherstd::basic_string'?}}
+  return wibble::narf; // expected-error{{no member named 'narf' in namespace 'otherstd'; did you mean 'nonstd::narf'?}}
+}
 
 namespace check_bool {
   void f() {
     Bool b; // expected-error{{use of undeclared identifier 'Bool'; did you mean 'bool'?}}
   }
 }
+
+namespace outr {
+}
+namespace outer {
+  namespace inner { // expected-note{{'outer::inner' declared here}} \
+                    // expected-note{{namespace 'outer::inner' defined here}} \
+                    // expected-note{{'inner' declared here}}
+    int i;
+  }
+}
+
+using namespace outr::inner; // expected-error{{no namespace named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}}
+
+void func() {
+  outr::inner::i = 3; // expected-error{{no member named 'inner' in namespace 'outr'; did you mean 'outer::inner'?}}
+  outer::innr::i = 4; // expected-error{{no member named 'innr' in namespace 'outer'; did you mean 'inner'?}}
+}
+
+struct base {
+};
+struct derived : base {
+  int i;
+};
+
+void func2() {
+  derived d;
+  // FIXME: we should offer a fix here. We do if the 'i' is misspelled, but we don't do name qualification changes
+  //        to replace base::i with derived::i as we would for other qualified name misspellings.
+  // d.base::i = 3;
+}