]> granicus.if.org Git - clang/commitdiff
Allow typo correction to try removing nested name specifiers.
authorKaelyn Uhrain <rikka@google.com>
Tue, 2 Jul 2013 23:47:44 +0000 (23:47 +0000)
committerKaelyn Uhrain <rikka@google.com>
Tue, 2 Jul 2013 23:47:44 +0000 (23:47 +0000)
The removal is tried by retrying the failed lookup of a correction
candidate with either the MemberContext or SS (CXXScopeSpecifier) or
both set to NULL if they weren't already. If the candidate identifier
is then looked up successfully, make a note in the candidate that the
SourceRange should include any existing nested name specifier even if
the candidate isn't adding a different one (i.e. the candidate has a
NULL NestedNameSpecifier).

Also tweak the diagnostic messages to differentiate between a suggestion
that just replaces the identifer but leaves the existing nested name
specifier intact and one that replaces the entire qualified identifier,
in cases where the suggested replacement is unqualified.

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

13 files changed:
include/clang/Basic/DiagnosticSemaKinds.td
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/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
test/FixIt/typo.cpp
test/Parser/cxx-using-directive.cpp
test/SemaCXX/pr13394-crash-on-invalid.cpp

index 77fe76efd16d251f609204462d6e11d941576292..6b8ac2aee1e62b183493dd03f7cfa1bf19797709 100644 (file)
@@ -6349,15 +6349,15 @@ def err_unknown_type_or_class_name_suggest : Error<
 def err_unknown_typename_suggest : Error<
   "unknown type name %0; did you mean %1?">;
 def err_unknown_nested_typename_suggest : Error<
-  "no type named %0 in %1; did you mean %2?">;
-def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %2?">;
+  "no type named %0 in %1; did you mean %select{|simply }2%3?">;
+def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %select{|simply }2%3?">;
 def err_undeclared_use_suggest : Error<
   "use of undeclared %0; did you mean %1?">;
 def err_undeclared_var_use_suggest : Error<
   "use of undeclared identifier %0; did you mean %1?">;
 def err_no_template_suggest : Error<"no template named %0; did you mean %1?">;
 def err_no_member_template_suggest : Error<
-  "no template named %0 in %1; did you mean %2?">;
+  "no template named %0 in %1; did you mean %select{|simply }2%3?">;
 def err_mem_init_not_member_or_class_suggest : Error<
   "initializer %0 does not name a non-static data member or base "
   "class; did you mean the %select{base class|member}1 %2?">;
@@ -6387,7 +6387,7 @@ def note_base_class_specified_here : Note<
 def err_using_directive_suggest : Error<
   "no namespace named %0; did you mean %1?">;
 def err_using_directive_member_suggest : Error<
-  "no namespace named %0 in %1; did you mean %2?">;
+  "no namespace named %0 in %1; did you mean %select{|simply }2%3?">;
 def note_namespace_defined_here : Note<"namespace %0 defined here">;
 def err_sizeof_pack_no_pack_name_suggest : Error<
   "%0 does not refer to the name of a parameter pack; did you mean %1?">;
index 59f34176056ac8ca12de6226371649e92fdced89..6d21b44494d41c0d8f4786773a86e36c4b276b42 100644 (file)
@@ -39,31 +39,33 @@ public:
   static const unsigned CallbackDistanceWeight = 150U;
 
   TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
-                 NestedNameSpecifier *NNS=0, unsigned CharDistance=0,
-                 unsigned QualifierDistance=0)
+                 NestedNameSpecifier *NNS = 0, unsigned CharDistance = 0,
+                 unsigned QualifierDistance = 0)
       : CorrectionName(Name), CorrectionNameSpec(NNS),
-      CharDistance(CharDistance), QualifierDistance(QualifierDistance),
-      CallbackDistance(0) {
+        CharDistance(CharDistance), QualifierDistance(QualifierDistance),
+        CallbackDistance(0), ForceSpecifierReplacement(false) {
     if (NameDecl)
       CorrectionDecls.push_back(NameDecl);
   }
 
-  TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0,
-                 unsigned CharDistance=0)
+  TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = 0,
+                 unsigned CharDistance = 0)
       : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
-      CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {
+        CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
+        ForceSpecifierReplacement(false) {
     if (Name)
       CorrectionDecls.push_back(Name);
   }
 
-  TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0,
-                 unsigned CharDistance=0)
+  TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = 0,
+                 unsigned CharDistance = 0)
       : CorrectionName(Name), CorrectionNameSpec(NNS),
-      CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {}
+        CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
+        ForceSpecifierReplacement(false) {}
 
   TypoCorrection()
       : CorrectionNameSpec(0), CharDistance(0), QualifierDistance(0),
-      CallbackDistance(0) {}
+        CallbackDistance(0), ForceSpecifierReplacement(false) {}
 
   /// \brief Gets the DeclarationName of the typo correction
   DeclarationName getCorrection() const { return CorrectionName; }
@@ -77,6 +79,15 @@ public:
   }
   void setCorrectionSpecifier(NestedNameSpecifier* NNS) {
     CorrectionNameSpec = NNS;
+    ForceSpecifierReplacement = (NNS != 0);
+  }
+
+  void WillReplaceSpecifier(bool ForceReplacement) {
+    ForceSpecifierReplacement = ForceReplacement;
+  }
+
+  bool WillReplaceSpecifier() const {
+    return ForceSpecifierReplacement;
   }
 
   void setQualifierDistance(unsigned ED) {
@@ -149,6 +160,7 @@ public:
   void makeKeyword() {
     CorrectionDecls.clear();
     CorrectionDecls.push_back(0);
+    ForceSpecifierReplacement = true;
   }
 
   // Check if this TypoCorrection is a keyword by checking if the first
@@ -173,8 +185,9 @@ public:
 
   void setCorrectionRange(CXXScopeSpec* SS,
                           const DeclarationNameInfo &TypoName) {
-    CorrectionRange.setBegin(CorrectionNameSpec && SS ? SS->getBeginLoc()
-                                                      : TypoName.getLoc());
+    CorrectionRange.setBegin(ForceSpecifierReplacement && SS
+                                 ? SS->getBeginLoc()
+                                 : TypoName.getLoc());
     CorrectionRange.setEnd(TypoName.getLoc());
   }
 
@@ -206,6 +219,7 @@ private:
   unsigned QualifierDistance;
   unsigned CallbackDistance;
   SourceRange CorrectionRange;
+  bool ForceSpecifierReplacement;
 };
 
 /// @brief Base class for callback objects used by Sema::CorrectTypo to check
index de68e2e1e46ec413d4f9ec3b49bde2c002781121..9701f7d751958b9bfdb96c1e60e13b062d18984d 100644 (file)
@@ -496,16 +496,20 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
                                  LookupCtx, EnteringContext))) {
       std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
       std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
+      bool droppedSpecifier = Corrected.WillReplaceSpecifier() &&
+                              Name.getAsString() == CorrectedStr;
       if (LookupCtx)
         Diag(Found.getNameLoc(), diag::err_no_member_suggest)
-          << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+          << Name << LookupCtx << droppedSpecifier << CorrectedQuotedStr
+          << SS.getRange()
           << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
                                           CorrectedStr);
       else
         Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
           << Name << CorrectedQuotedStr
-          << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
-      
+          << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                          CorrectedStr);
+
       if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
         Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr;
         Found.addDecl(ND);
index 8e863896521b7d2b07730c64fc7843fedf6de645..162b5b8c091fc71b46d098e025ce9e06aff9fb0d 100644 (file)
@@ -422,22 +422,29 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
         CorrectedQuotedStr = "the keyword " + CorrectedQuotedStr;
       Diag(IILoc, diag::err_unknown_typename_suggest)
         << II << CorrectedQuotedStr
-        << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
+        << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                        CorrectedStr);
       II = NewII;
     } else {
       NamedDecl *Result = Corrected.getCorrectionDecl();
       // We found a similarly-named type or interface; suggest that.
-      if (!SS || !SS->isSet())
+      if (!SS || !SS->isSet()) {
         Diag(IILoc, diag::err_unknown_typename_suggest)
           << II << CorrectedQuotedStr
-          << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
-      else if (DeclContext *DC = computeDeclContext(*SS, false))
-        Diag(IILoc, diag::err_unknown_nested_typename_suggest)
-          << II << DC << CorrectedQuotedStr << SS->getRange()
           << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
                                           CorrectedStr);
-      else
+      } else if (DeclContext *DC = computeDeclContext(*SS, false)) {
+        bool droppedSpecifier = Corrected.WillReplaceSpecifier() &&
+                                II->getName().equals(CorrectedStr);
+        Diag(IILoc, diag::err_unknown_nested_typename_suggest)
+            << II << DC << droppedSpecifier << CorrectedQuotedStr
+            << SS->getRange()
+            << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                            CorrectedStr);
+      }
+      else {
         llvm_unreachable("could not have corrected a typo here");
+      }
 
       Diag(Result->getLocation(), diag::note_previous_decl)
         << CorrectedQuotedStr;
@@ -680,16 +687,19 @@ Corrected:
           QualifiedDiag = diag::err_unknown_nested_typename_suggest;
         }
 
-        if (SS.isEmpty())
+        if (SS.isEmpty()) {
           Diag(NameLoc, UnqualifiedDiag)
             << Name << CorrectedQuotedStr
             << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
-        else // FIXME: is this even reachable? Test it.
+        } else {// FIXME: is this even reachable? Test it.
+          bool droppedSpecifier = Corrected.WillReplaceSpecifier() &&
+                                  Name->getName().equals(CorrectedStr);
           Diag(NameLoc, QualifiedDiag)
-            << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
-            << SS.getRange()
+            << Name << computeDeclContext(SS, false) << droppedSpecifier
+            << CorrectedQuotedStr << SS.getRange()
             << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
                                             CorrectedStr);
+        }
 
         // Update the name, so that the caller has the new name.
         Name = Corrected.getCorrectionAsIdentifierInfo();
index 77c3339507c32abf5cf50559a2479c212cfdcbf6..e42d249542bcb13bcb3a7c861de71e0011abbadd 100644 (file)
@@ -6603,15 +6603,18 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
                                                Validator)) {
     std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
     std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOpts()));
-    if (DeclContext *DC = S.computeDeclContext(SS, false))
+    if (DeclContext *DC = S.computeDeclContext(SS, false)) {
+      bool droppedSpecifier = Corrected.WillReplaceSpecifier() &&
+                              Ident->getName().equals(CorrectedStr);
       S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
-        << Ident << DC << CorrectedQuotedStr << SS.getRange()
-        << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
-                                        CorrectedStr);
-    else
+          << Ident << DC << droppedSpecifier << CorrectedQuotedStr
+          << SS.getRange() << FixItHint::CreateReplacement(
+                                  Corrected.getCorrectionRange(), CorrectedStr);
+    } else {
       S.Diag(IdentLoc, diag::err_using_directive_suggest)
         << Ident << CorrectedQuotedStr
         << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+    }
 
     S.Diag(Corrected.getCorrectionDecl()->getLocation(),
          diag::note_namespace_defined_here) << CorrectedQuotedStr;
index 2f5961d47925d1aa153d7110ab7cdbd51475afd7..c885e3f927303533ea698d0d1ef4de1c2e1e1853 100644 (file)
@@ -1720,6 +1720,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
                                     S, &SS, CCC))) {
     std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
     std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
+    bool droppedSpecifier =
+        Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
     R.setLookupName(Corrected.getCorrection());
 
     if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
@@ -1754,8 +1756,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
             << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
         else
           Diag(R.getNameLoc(), diag::err_no_member_suggest)
-            << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
-            << SS.getRange()
+            << Name << computeDeclContext(SS, false) << droppedSpecifier
+            << CorrectedQuotedStr << SS.getRange()
             << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
                                             CorrectedStr);
 
@@ -1781,8 +1783,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
             << Name << CorrectedQuotedStr;
         else
           Diag(R.getNameLoc(), diag::err_no_member_suggest)
-            << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
-            << SS.getRange();
+            << Name << computeDeclContext(SS, false) << droppedSpecifier
+            << CorrectedQuotedStr << SS.getRange();
 
         // Don't try to recover; it won't work.
         return true;
@@ -1794,8 +1796,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
         Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
       else
         Diag(R.getNameLoc(), diag::err_no_member_suggest)
-        << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
-        << SS.getRange();
+          << Name << computeDeclContext(SS, false) << droppedSpecifier
+          << CorrectedQuotedStr << SS.getRange();
       return true;
     }
   }
index 73ca265fb2dd038a4a3bd2acef6caa182ae00a84..7151fc55041464d1ef42e9e9b1e4620ff33f3748 100644 (file)
@@ -610,6 +610,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
         Corrected.getAsString(SemaRef.getLangOpts()));
     std::string CorrectedQuotedStr(
         Corrected.getQuoted(SemaRef.getLangOpts()));
+    bool droppedSpecifier =
+        Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
 
     R.setLookupName(Corrected.getCorrection());
     for (TypoCorrection::decl_iterator DI = Corrected.begin(),
@@ -620,7 +622,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
     R.resolveKind();
 
     SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
-      << Name << DC << CorrectedQuotedStr << SS.getRange()
+      << Name << DC << droppedSpecifier << CorrectedQuotedStr << SS.getRange()
       << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
                                       CorrectedStr);
 
index d12d1a39a32cef9070b4f76c292b5c7fece533d4..d3fd69982fb1c2bdd6fa65ece0b517780d96f254 100644 (file)
@@ -3992,13 +3992,29 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
       // Perform name lookup on this name.
       TypoCorrection &Candidate = I->second.front();
       IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo();
-      LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
-                                EnteringContext, CCC.IsObjCIvarLookup);
+      DeclContext *TempMemberContext = MemberContext;
+      CXXScopeSpec *TempSS = SS;
+retry_lookup:
+      LookupPotentialTypoResult(*this, TmpRes, Name, S, TempSS,
+                                TempMemberContext, EnteringContext,
+                                CCC.IsObjCIvarLookup);
 
       switch (TmpRes.getResultKind()) {
       case LookupResult::NotFound:
       case LookupResult::NotFoundInCurrentInstantiation:
       case LookupResult::FoundUnresolvedValue:
+        if (TempSS) {
+          // Immediately retry the lookup without the given CXXScopeSpec
+          TempSS = NULL;
+          Candidate.WillReplaceSpecifier(true);
+          goto retry_lookup;
+        }
+        if (TempMemberContext) {
+          if (SS && !TempSS)
+            TempSS = SS;
+          TempMemberContext = NULL;
+          goto retry_lookup;
+        }
         QualifiedResults.push_back(Candidate);
         // We didn't find this name in our scope, or didn't like what we found;
         // ignore it.
index e21acb1b10bb17c3de580871f0a6c95c9281be61..2502db829b969746dce01dd1a3f8fb0b5a356e5f 100644 (file)
@@ -331,15 +331,19 @@ void Sema::LookupTemplateName(LookupResult &Found,
       if (!Found.empty()) {
         std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
         std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
-        if (LookupCtx)
+        if (LookupCtx) {
+          bool droppedSpecifier = Corrected.WillReplaceSpecifier() &&
+                                  Name.getAsString() == CorrectedStr;
           Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
-            << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+            << Name << LookupCtx << droppedSpecifier << CorrectedQuotedStr
+            << SS.getRange()
             << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
                                             CorrectedStr);
-        else
+        } else {
           Diag(Found.getNameLoc(), diag::err_no_template_suggest)
             << Name << CorrectedQuotedStr
             << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
+        }
         if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
           Diag(Template->getLocation(), diag::note_previous_decl)
             << CorrectedQuotedStr;
index 816cdb08a90cb663a1cd64778462cef5ddba464a..96a0df4a03f0ae0443c5bda0d270165fac5f9eba 100644 (file)
@@ -3,7 +3,7 @@
 // Fun things you can do with inline namespaces:
 
 inline namespace X {
-  void f1(); // expected-note {{'::f1' declared here}}
+  void f1(); // expected-note {{'f1' declared here}}
 
   inline namespace Y {
     void f2();
@@ -21,7 +21,7 @@ void foo1() {
   f1();
   ::f1();
   X::f1();
-  Y::f1(); // expected-error {{no member named 'f1' in namespace 'X::Y'; did you mean '::f1'?}}
+  Y::f1(); // expected-error {{no member named 'f1' in namespace 'X::Y'; did you mean simply 'f1'?}}
 
   f2();
   ::f2();
index ea4a97133c232b6a78cd291f7a407a5b4957ba5e..87df1c07f3469413f8c267515a96ffe47fd7f2b8 100644 (file)
@@ -5,8 +5,7 @@
 // RUN: grep test_string %t
 
 namespace std {
-  template<typename T> class basic_string { // expected-note 2{{'basic_string' declared here}} \
-                                            // expected-note {{'::basic_string' declared here}}
+  template<typename T> class basic_string { // expected-note 3{{'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}}
@@ -88,7 +87,7 @@ namespace another {
   template<typename T> class wide_string {}; // expected-note {{'another::wide_string' declared here}}
 }
 int poit() {
-  nonstd::basic_string<char> str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean '::basic_string'?}}
+  nonstd::basic_string<char> str; // expected-error{{no template named 'basic_string' in namespace 'nonstd'; did you mean simply 'basic_string'?}}
   nonstd::wide_string<char> str2; // expected-error{{no template named 'wide_string' in namespace 'nonstd'; did you mean 'another::wide_string'?}}
   return wibble::narf; // expected-error{{no member named 'narf' in namespace 'otherstd'; did you mean 'nonstd::narf'?}}
 }
index 1b8f495b70e7aa2a9fab2c0aca23720b88294f3a..76dc22f15301a6ed4e2e505fc1a65e0f3d4008a1 100644 (file)
@@ -8,7 +8,7 @@ namespace B {
   using namespace A ;
 }
 
-namespace C {} // expected-note{{namespace '::C' defined here}}
+namespace C {} // expected-note{{namespace 'C' defined here}}
 
 namespace D {
   
@@ -23,7 +23,7 @@ namespace D {
   using namespace B::A ; // expected-error{{no namespace named 'A' in namespace 'D::B'; did you mean '::B::A'?}}
   using namespace ::B::A ;
   using namespace ::D::F ; // expected-error{{expected namespace name}}
-  using namespace ::D::C ; // expected-error{{no namespace named 'C' in namespace 'D'; did you mean '::C'?}}
+  using namespace ::D::C ; // expected-error{{no namespace named 'C' in namespace 'D'; did you mean simply 'C'?}}
 }
 
 using namespace ! ; // expected-error{{expected namespace name}}
index a198340d6fba656f65028e8a66521de30bf01e19..160051c157e6915810e4576b197b922e7dbd18d6 100644 (file)
@@ -8,11 +8,10 @@ namespace stretch_v1 {
 }
 namespace gatekeeper_v1 {
   namespace gatekeeper_factory_v1 {
-    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'?}}
+    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 simply 'closure_t'?}}
     };
   }
-  gatekeeper_v1::closure_t *x; // expected-error {{no type named 'closure_t' in namespace 'gatekeeper_v1}}
+  // FIXME: Typo correction should remove the 'gatekeeper_v1::' name specifier
+  gatekeeper_v1::closure_t *x; // expected-error-re {{no type named 'closure_t' in namespace 'gatekeeper_v1'$}}
 }