]> granicus.if.org Git - clang/commitdiff
Look for corrections in enclosing namespaces that require a global NestedNameSpecifier.
authorKaelyn Uhrain <rikka@google.com>
Tue, 2 Jul 2013 23:47:35 +0000 (23:47 +0000)
committerKaelyn Uhrain <rikka@google.com>
Tue, 2 Jul 2013 23:47:35 +0000 (23:47 +0000)
CorrectTypo will now see and consider those corrections that are effectively
shadowed by other declarations in a closer context when resolved via an
unqualified lookup. This involves adding any parent namespaces to the set of
namespaces as fully-qualified name specifiers, and also adding potential
corrections that passed name lookup but were rejected by the given
CorrectionCandidateCallback into the set of failed corrections that should be
tried with the set of namespace specifiers.

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

lib/Sema/SemaLookup.cpp
test/FixIt/typo-crash.cpp
test/SemaCXX/pr13394-crash-on-invalid.cpp
test/SemaCXX/typo-correction.cpp

index dbf66711af5103a56193bfcd0e60a6151656fe17..d12d1a39a32cef9070b4f76c292b5c7fece533d4 100644 (file)
@@ -3496,9 +3496,11 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
   }
 
   // Add an explicit leading '::' specifier if needed.
-  if (NamespaceDecl *ND =
-        NamespaceDeclChain.empty() ? NULL :
-          dyn_cast_or_null<NamespaceDecl>(NamespaceDeclChain.back())) {
+  if (NamespaceDeclChain.empty()) {
+    NamespaceDeclChain = FullNamespaceDeclChain;
+    NNS = NestedNameSpecifier::GlobalSpecifier(Context);
+  } else if (NamespaceDecl *ND =
+                 dyn_cast_or_null<NamespaceDecl>(NamespaceDeclChain.back())) {
     IdentifierInfo *Name = ND->getIdentifier();
     if (std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(),
                   Name) != CurContextIdentifiers.end() ||
@@ -4020,8 +4022,10 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
              TRD != TRDEnd; ++TRD)
           Candidate.addCorrectionDecl(*TRD);
         ++I;
-        if (!isCandidateViable(CCC, Candidate))
+        if (!isCandidateViable(CCC, Candidate)) {
+          QualifiedResults.push_back(Candidate);
           DI->second.erase(Prev);
+        }
         break;
       }
 
@@ -4029,8 +4033,10 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
         TypoCorrectionConsumer::result_iterator Prev = I;
         Candidate.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
         ++I;
-        if (!isCandidateViable(CCC, Candidate))
+        if (!isCandidateViable(CCC, Candidate)) {
+          QualifiedResults.push_back(Candidate);
           DI->second.erase(Prev);
+        }
         break;
       }
 
@@ -4066,18 +4072,12 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
           // Any corrections added below will be validated in subsequent
           // iterations of the main while() loop over the Consumer's contents.
           switch (TmpRes.getResultKind()) {
-          case LookupResult::Found: {
-            TypoCorrection TC(*QRI);
-            TC.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
-            TC.setCorrectionSpecifier(NI->NameSpecifier);
-            TC.setQualifierDistance(NI->EditDistance);
-            Consumer.addCorrection(TC);
-            break;
-          }
+          case LookupResult::Found:
           case LookupResult::FoundOverloaded: {
             TypoCorrection TC(*QRI);
             TC.setCorrectionSpecifier(NI->NameSpecifier);
             TC.setQualifierDistance(NI->EditDistance);
+            TC.setCallbackDistance(0); // Reset the callback distance
             for (LookupResult::iterator TRD = TmpRes.begin(),
                                      TRDEnd = TmpRes.end();
                  TRD != TRDEnd; ++TRD)
index c154e3baba4f820a5c0376ec74812ed3a3f7808f..0ff160e448211d916ca72a666888dcbd8f1febe1 100644 (file)
@@ -19,11 +19,12 @@ namespace PR12297 {
     namespace B {
       typedef short   T;
         
-      T global(); // expected-note {{'A::B::global' declared here}}
+      T global(); // expected-note {{'::PR12297::global' declared here}}
     }
   }
 
   using namespace A::B;
 
-  T A::global(); // expected-error {{out-of-line definition of 'global' does not match any declaration in namespace 'PR12297::A'; did you mean 'A::B::global'?}}
+  // FIXME: Adding '::PR12297::' is not needed as removing 'A::' is sufficient
+  T A::global(); // expected-error {{out-of-line definition of 'global' does not match any declaration in namespace 'PR12297::A'; did you mean '::PR12297::global'?}}
 }
index 413c52af858c14883636387e035cf6b8e5e7a241..a198340d6fba656f65028e8a66521de30bf01e19 100644 (file)
@@ -8,8 +8,10 @@ namespace stretch_v1 {
 }
 namespace gatekeeper_v1 {
   namespace gatekeeper_factory_v1 {
-    struct closure_t { // expected-note {{'closure_t' declared here}}
-      gatekeeper_v1::closure_t* create(); // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean 'closure_t'?}}
+    struct closure_t { // expected-note {{'::gatekeeper_v1::gatekeeper_factory_v1::closure_t' declared here}}
+      // FIXME: Just remove the original 'gatekeeper_v1::' name specifier
+      // instead of adding a fully-qualified name specifier to 'closure_t'
+      gatekeeper_v1::closure_t* create(); // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1'; did you mean '::gatekeeper_v1::gatekeeper_factory_v1::closure_t'?}}
     };
   }
   gatekeeper_v1::closure_t *x; // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1}}
index 3d40d842f0e9ad9579c372f6bbd15a2896263c97..62d870c826efd7b3105e7e693e37479910773484 100644 (file)
@@ -230,6 +230,18 @@ class foo { }; // expected-note{{'foo' declared here}}
 class bar : boo { }; // expected-error{{unknown class name 'boo'; did you mean 'foo'?}}
 }
 
+namespace outer {
+  void somefunc();  // expected-note{{'::outer::somefunc' declared here}}
+  void somefunc(int, int);  // expected-note{{'::outer::somefunc' declared here}}
+
+  namespace inner {
+    void somefunc(int) {
+      someFunc();  // expected-error{{use of undeclared identifier 'someFunc'; did you mean '::outer::somefunc'?}}
+      someFunc(1, 2);  // expected-error{{use of undeclared identifier 'someFunc'; did you mean '::outer::somefunc'?}}
+    }
+  }
+}
+
 namespace bogus_keyword_suggestion {
 void test() {
    status = "OK"; // expected-error-re{{use of undeclared identifier 'status'$}}