]> granicus.if.org Git - clang/commitdiff
Allow CorrectTypo to add/modify nested name qualifiers to typos that
authorKaelyn Uhrain <rikka@google.com>
Wed, 6 Jun 2012 20:54:51 +0000 (20:54 +0000)
committerKaelyn Uhrain <rikka@google.com>
Wed, 6 Jun 2012 20:54:51 +0000 (20:54 +0000)
are otherwise too short to try to correct.

The TODOs added to two of the tests are for existing deficiencies in the
typo correction code that could be exposed by using longer identifiers.

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

lib/Sema/SemaLookup.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p3.cpp
test/Parser/cxx-using-directive.cpp
test/SemaCXX/elaborated-type-specifier.cpp
test/SemaCXX/nested-name-spec.cpp
test/SemaCXX/qualified-id-lookup.cpp

index 1ee594c2a316ca4b413c018d44650bc6e2bc7e31..91d76de17292325483da11b7a06ed470ad3f318b 100644 (file)
@@ -3795,6 +3795,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
   bool SearchNamespaces
     = getLangOpts().CPlusPlus &&
       (IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace()));
+  // In a few cases we *only* want to search for corrections bases on just
+  // adding or changing the nested name specifier.
+  bool AllowOnlyNNSChanges = Typo->getName().size() < 3;
   
   if (IsUnqualifiedLookup || SearchNamespaces) {
     // For unqualified lookup, look through all of the names that we have
@@ -3831,8 +3834,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
     return TypoCorrection();
   }
 
-  // Make sure that the user typed at least 3 characters for each correction
-  // made. Otherwise, we don't even both looking at the results.
+  // Make sure the best edit distance (prior to adding any namespace qualifiers)
+  // is not more that about a third of the length of the typo's identifier.
   unsigned ED = Consumer.getBestEditDistance(true);
   if (ED > 0 && Typo->getName().size() / ED < 3) {
     // If this was an unqualified lookup, note that no correction was found.
@@ -3872,6 +3875,16 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
     for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(),
                                               IEnd = DI->second.end();
          I != IEnd; /* Increment in loop. */) {
+      // If we only want nested name specifier corrections, ignore potential
+      // corrections that have a different base identifier from the typo.
+      if (AllowOnlyNNSChanges &&
+          I->second.front().getCorrectionAsIdentifierInfo() != Typo) {
+        TypoCorrectionConsumer::result_iterator Prev = I;
+        ++I;
+        DI->second.erase(Prev);
+        continue;
+      }
+
       // If the item already has been looked up or is a keyword, keep it.
       // If a validator callback object was given, drop the correction
       // unless it passes validation.
@@ -4013,7 +4026,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
   TypoResultsMap &BestResults = Consumer.getBestResults();
   ED = Consumer.getBestEditDistance(true);
 
-  if (ED > 0 && Typo->getName().size() / ED < 3) {
+  if (!AllowOnlyNNSChanges && ED > 0 && Typo->getName().size() / ED < 3) {
     // If this was an unqualified lookup and we believe the callback
     // object wouldn't have filtered out possible corrections, note
     // that no correction was found.
index 84841cb60f4d9a74e62a32dadb16f18742ce07c0..c8b7def5a4485a973abbbd7c9df09e1a35c84ad3 100644 (file)
@@ -1,10 +1,14 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
 namespace N {
-  template<class T> class X;
+  template<class T> class X; // expected-note {{'N::X' declared here}} \
+                             // expected-note {{explicitly specialized declaration is here}}
 }
 
-template<> class X<int> { /* ... */ }; // expected-error {{non-template class 'X'}}
+// TODO: Don't add a namespace qualifier to the template if it would trigger
+// the warning about the specialization being outside of the namespace.
+template<> class X<int> { /* ... */ }; // expected-error {{no template named 'X'; did you mean 'N::X'?}} \
+                                        // expected-warning {{first declaration of class template specialization of 'X' outside namespace 'N' is a C++11 extension}}
 
 namespace N {
   
index 1d781fbdcf6449342f98a00c815d250eb1dafec3..9a1a6de892677961bae7fefecfa432457a25c102 100644 (file)
@@ -3,7 +3,8 @@
 class A {};
 
 namespace B {
-  namespace A {} // expected-note{{namespace '::B::A' defined here}}
+  namespace A {} // expected-note{{namespace '::B::A' defined here}} \
+                 // expected-note{{namespace 'B::A' defined here}}
   using namespace A ;
 }
 
@@ -25,7 +26,7 @@ namespace D {
 }
 
 using namespace ! ; // expected-error{{expected namespace name}}
-using namespace A ; // expected-error{{expected namespace name}}
+using namespace A ; // expected-error{{no namespace named 'A'; did you mean 'B::A'?}}
 using namespace ::A // expected-error{{expected namespace name}} \
                     // expected-error{{expected ';' after namespace name}}
                     B ; 
index 760079f3b0bcd7bd527789c05604867a0e6e18ff..1b1770a89f8506971486b2e2bcc140bc39f8a1b3 100644 (file)
@@ -19,7 +19,7 @@ bool test_elab(S1 *s1, struct S2 *s2, struct S3 *s3) {
 namespace NS {
   class X {
   public:
-    void test_elab2(struct S4 *s4);
+    void test_elab2(struct S4 *s4); // expected-note{{'NS::S4' declared here}}
   };
 
   void X::test_elab2(S4 *s4) { } // expected-note{{passing argument to parameter 's4' here}}
@@ -35,8 +35,7 @@ namespace NS {
 }
 
 void test_S5_scope() {
-  S4 *s4; // expected-error{{use of undeclared identifier 'S4'}} \
-  // expected-error{{use of undeclared identifier 's4'}}
+  S4 *s4; // expected-error{{unknown type name 'S4'; did you mean 'NS::S4'?}}
 }
 
 int test_funcparam_scope(struct S5 * s5) {
@@ -44,5 +43,3 @@ int test_funcparam_scope(struct S5 * s5) {
   if (s5 == s5_2) return 1; // expected-error {{comparison of distinct pointer types ('struct S5 *' and 'struct S5 *')}}
   return 0;
 }
-
-
index b31763484489db3701fcf9e2b05c23dd085b4dc5..d57a8523bbbc13c0879bd700e21ca06883df236d 100644 (file)
@@ -113,7 +113,8 @@ namespace E {
       X = 0
     };
 
-    void f() {
+    void f() { // expected-note{{'E::Nested::f' declared here}} \
+               // expected-note{{previous definition is here}}
       return E::X; // expected-error{{expected a class or namespace}}
     }
   }
@@ -143,7 +144,10 @@ namespace A {
   void g(int&); // expected-note{{type of 1st parameter of member declaration does not match definition ('int &' vs 'const int &')}}
 } 
 
-void A::f() {} // expected-error{{out-of-line definition of 'f' does not match any declaration in namespace 'A'}}
+// TODO: Suppress the typo correction for an invalid redeclaration if the chosen
+// correction is a function that already has a body.
+void A::f() {} // expected-error{{out-of-line definition of 'f' does not match any declaration in namespace 'A'; did you mean 'E::Nested::f'?}} \
+               // expected-error{{redefinition of 'f'}}
 
 void A::g(const int&) { } // expected-error{{out-of-line definition of 'g' does not match any declaration in namespace 'A'}}
 
@@ -286,3 +290,15 @@ protected:
 template <typename T>
 struct A2<T>::B::C; // expected-error {{no struct named 'C'}}
 }
+
+namespace PR13033 {
+namespace NS {
+ int a; // expected-note {{'NS::a' declared here}}
+ int longer_b; //expected-note {{'NS::longer_b' declared here}}
+}
+
+// Suggest adding a namespace qualifier to both variable names even though one
+// is only a single character long.
+int foobar = a + longer_b; // expected-error {{use of undeclared identifier 'a'; did you mean 'NS::a'?}} \
+                           // expected-error {{use of undeclared identifier 'longer_b'; did you mean 'NS::longer_b'?}}
+}
index d65a4684e629a66b19d7e609163e36ecae5574eb..a14193cc7ac88b1b5d20946418bcf93db28da48c 100644 (file)
@@ -86,14 +86,15 @@ namespace a {
 namespace a {  
   namespace a {   // A1
     namespace a { // A2
-      int i;
+      int i; // expected-note{{'::a::a::a::i' declared here}}
     }
   }
 }
 
 void test_a() {
-  a::a::i = 3; // expected-error{{no member named 'i'}}
+  a::a::i = 3; // expected-error{{no member named 'i' in namespace 'a::a'; did you mean '::a::a::a::i'?}}
   a::a::a::i = 4;
+  a::a::j = 3; // expected-error-re{{no member named 'j' in namespace 'a::a'$}}
 }
   
 struct Undef { // expected-note{{definition of 'Undef' is not complete until the closing '}'}}