r224375 - Add a new flag, -fspell-checking-limit=<number> to control how many times we'll do spell checking. Note that spell checking will change the produced AST, so we don't automatically change this value when someone sets -ferror-limit=. With this, merge test typo-correction-pt2.cpp into typo-correction.cpp.

Nick Lewycky nicholas at mxc.ca
Tue Dec 16 13:39:02 PST 2014


Author: nicholas
Date: Tue Dec 16 15:39:02 2014
New Revision: 224375

URL: http://llvm.org/viewvc/llvm-project?rev=224375&view=rev
Log:
Add a new flag, -fspell-checking-limit=<number> to control how many times we'll do spell checking. Note that spell checking will change the produced AST, so we don't automatically change this value when someone sets -ferror-limit=. With this, merge test typo-correction-pt2.cpp into typo-correction.cpp.

Remove Sema::UnqualifiedTyposCorrected, a cache of corrected typos. It would only cache typo corrections that didn't provide ValidateCandidate of which there were few left, and it had a bug when we had the same identifier spelled wrong twice. See the last two tests in typo-correction.cpp for cases this fires.

Removed:
    cfe/trunk/test/SemaCXX/typo-correction-pt2.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticOptions.def
    cfe/trunk/include/clang/Basic/DiagnosticOptions.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/test/CXX/class.access/class.friend/p11.cpp
    cfe/trunk/test/SemaCXX/typo-correction.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticOptions.def?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticOptions.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticOptions.def Tue Dec 16 15:39:02 2014
@@ -81,6 +81,8 @@ VALUE_DIAGOPT(MacroBacktraceLimit, 32, D
 VALUE_DIAGOPT(TemplateBacktraceLimit, 32, DefaultTemplateBacktraceLimit)
 /// Limit depth of constexpr backtrace.
 VALUE_DIAGOPT(ConstexprBacktraceLimit, 32, DefaultConstexprBacktraceLimit)
+/// Limit number of times to perform spell checking.
+VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit)
 
 VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops.
 /// Column limit for formatting message diagnostics, or 0 if unused.
@@ -92,4 +94,3 @@ VALUE_DIAGOPT(MessageLength, 32, 0)
 #undef SEMANTIC_DIAGOPT
 #undef SEMANTIC_ENUM_DIAGOPT
 #undef SEMANTIC_VALUE_DIAGOPT
-

Modified: cfe/trunk/include/clang/Basic/DiagnosticOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticOptions.h?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticOptions.h (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticOptions.h Tue Dec 16 15:39:02 2014
@@ -33,7 +33,8 @@ public:
   enum { DefaultTabStop = 8, MaxTabStop = 100,
     DefaultMacroBacktraceLimit = 6,
     DefaultTemplateBacktraceLimit = 10,
-    DefaultConstexprBacktraceLimit = 10 };
+    DefaultConstexprBacktraceLimit = 10,
+    DefaultSpellCheckingLimit = 50 };
 
   // Define simple diagnostic options (with no accessors).
 #define DIAGOPT(Name, Bits, Default) unsigned Name : Bits;

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Tue Dec 16 15:39:02 2014
@@ -279,6 +279,8 @@ def ftemplate_backtrace_limit : Separate
   HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
 def fconstexpr_backtrace_limit : Separate<["-"], "fconstexpr-backtrace-limit">, MetaVarName<"<N>">,
   HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">;
+def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarName<"<N>">,
+  HelpText<"Set the maximum number of times to perform spell checking on unrecognized identifiers (0 = no limit).">;
 def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
   HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
 def verify : Flag<["-"], "verify">,

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Tue Dec 16 15:39:02 2014
@@ -862,6 +862,7 @@ def fshow_overloads_EQ : Joined<["-"], "
 def fshow_column : Flag<["-"], "fshow-column">, Group<f_Group>, Flags<[CC1Option]>;
 def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>;
 def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
+def fspell_checking_limit_EQ : Joined<["-"], "fspell-checking-limit=">, Group<f_Group>;
 def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>;
 def fsigned_char : Flag<["-"], "fsigned-char">, Group<f_Group>;
 def fno_signed_char : Flag<["-"], "fno-signed-char">, Flags<[CC1Option]>,

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Dec 16 15:39:02 2014
@@ -2630,7 +2630,7 @@ private:
                              std::unique_ptr<CorrectionCandidateCallback> CCC,
                              DeclContext *MemberContext, bool EnteringContext,
                              const ObjCObjectPointerType *OPT,
-                             bool ErrorRecovery, bool &IsUnqualifiedLookup);
+                             bool ErrorRecovery);
 
 public:
   const TypoExprState &getTypoExprState(TypoExpr *TE) const;
@@ -2985,10 +2985,7 @@ private:
 
   /// \brief Record the typo correction failure and return an empty correction.
   TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc,
-                                  bool RecordFailure = true,
-                                  bool IsUnqualifiedLookup = false) {
-    if (IsUnqualifiedLookup)
-      (void)UnqualifiedTyposCorrected[Typo];
+                                  bool RecordFailure = true) {
     if (RecordFailure)
       TypoCorrectionFailures[Typo].insert(TypoLoc);
     return TypoCorrection();
@@ -6688,17 +6685,6 @@ public:
   /// \brief The number of typos corrected by CorrectTypo.
   unsigned TyposCorrected;
 
-  typedef llvm::DenseMap<IdentifierInfo *, TypoCorrection>
-    UnqualifiedTyposCorrectedMap;
-
-  /// \brief A cache containing the results of typo correction for unqualified
-  /// name lookup.
-  ///
-  /// The string is the string that we corrected to (which may be empty, if
-  /// there was no correction), while the boolean will be true when the
-  /// string represents a keyword.
-  UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected;
-
   typedef llvm::SmallSet<SourceLocation, 2> SrcLocSet;
   typedef llvm::DenseMap<IdentifierInfo *, SrcLocSet> IdentifierSourceLocations;
 

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Tue Dec 16 15:39:02 2014
@@ -3546,6 +3546,11 @@ void Clang::ConstructJob(Compilation &C,
     CmdArgs.push_back(A->getValue());
   }
 
+  if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) {
+    CmdArgs.push_back("-fspell-checking-limit");
+    CmdArgs.push_back(A->getValue());
+  }
+
   // Pass -fmessage-length=.
   CmdArgs.push_back("-fmessage-length");
   if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
@@ -8306,4 +8311,3 @@ void CrossWindows::Link::ConstructJob(Co
 
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs));
 }
-

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Dec 16 15:39:02 2014
@@ -707,6 +707,9 @@ bool clang::ParseDiagnosticArgs(Diagnost
   Opts.ConstexprBacktraceLimit = getLastArgIntValue(
       Args, OPT_fconstexpr_backtrace_limit,
       DiagnosticOptions::DefaultConstexprBacktraceLimit, Diags);
+  Opts.SpellCheckingLimit = getLastArgIntValue(
+      Args, OPT_fspell_checking_limit,
+      DiagnosticOptions::DefaultSpellCheckingLimit, Diags);
   Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
                                     DiagnosticOptions::DefaultTabStop, Diags);
   if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Dec 16 15:39:02 2014
@@ -4023,8 +4023,7 @@ std::unique_ptr<TypoCorrectionConsumer>
     Scope *S, CXXScopeSpec *SS,
     std::unique_ptr<CorrectionCandidateCallback> CCC,
     DeclContext *MemberContext, bool EnteringContext,
-    const ObjCObjectPointerType *OPT, bool ErrorRecovery,
-    bool &IsUnqualifiedLookup) {
+    const ObjCObjectPointerType *OPT, bool ErrorRecovery) {
 
   if (Diags.hasFatalErrorOccurred() || !getLangOpts().SpellChecking ||
       DisableTypoCorrection)
@@ -4068,6 +4067,14 @@ std::unique_ptr<TypoCorrectionConsumer>
   if (getLangOpts().AltiVec && Typo->isStr("vector"))
     return nullptr;
 
+  // Provide a stop gap for files that are just seriously broken.  Trying
+  // to correct all typos can turn into a HUGE performance penalty, causing
+  // some files to take minutes to get rejected by the parser.
+  unsigned Limit = getDiagnostics().getDiagnosticOptions().SpellCheckingLimit;
+  if (Limit && TyposCorrected >= Limit)
+    return nullptr;
+  ++TyposCorrected;
+
   // If we're handling a missing symbol error, using modules, and the
   // special search all modules option is used, look for a missing import.
   if (ErrorRecovery && getLangOpts().Modules &&
@@ -4082,13 +4089,8 @@ std::unique_ptr<TypoCorrectionConsumer>
       *this, TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
       EnteringContext);
 
-  // If a callback object considers an empty typo correction candidate to be
-  // viable, assume it does not do any actual validation of the candidates.
-  TypoCorrection EmptyCorrection;
-  bool ValidatingCallback = !isCandidateViable(CCCRef, EmptyCorrection);
-
   // Perform name lookup to find visible, similarly-named entities.
-  IsUnqualifiedLookup = false;
+  bool IsUnqualifiedLookup = false;
   DeclContext *QualifiedDC = MemberContext;
   if (MemberContext) {
     LookupVisibleDecls(MemberContext, LookupKind, *Consumer);
@@ -4103,46 +4105,9 @@ std::unique_ptr<TypoCorrectionConsumer>
     if (!QualifiedDC)
       return nullptr;
 
-    // Provide a stop gap for files that are just seriously broken.  Trying
-    // to correct all typos can turn into a HUGE performance penalty, causing
-    // some files to take minutes to get rejected by the parser.
-    if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
-      return nullptr;
-    ++TyposCorrected;
-
     LookupVisibleDecls(QualifiedDC, LookupKind, *Consumer);
   } else {
     IsUnqualifiedLookup = true;
-    UnqualifiedTyposCorrectedMap::iterator Cached
-      = UnqualifiedTyposCorrected.find(Typo);
-    if (Cached != UnqualifiedTyposCorrected.end()) {
-      // Add the cached value, unless it's a keyword or fails validation. In the
-      // keyword case, we'll end up adding the keyword below.
-      if (Cached->second) {
-        if (!Cached->second.isKeyword() &&
-            isCandidateViable(CCCRef, Cached->second)) {
-          // Do not use correction that is unaccessible in the given scope.
-          NamedDecl *CorrectionDecl = Cached->second.getCorrectionDecl();
-          DeclarationNameInfo NameInfo(CorrectionDecl->getDeclName(),
-                                       CorrectionDecl->getLocation());
-          LookupResult R(*this, NameInfo, LookupOrdinaryName);
-          if (LookupName(R, S))
-            Consumer->addCorrection(Cached->second);
-        }
-      } else {
-        // Only honor no-correction cache hits when a callback that will validate
-        // correction candidates is not being used.
-        if (!ValidatingCallback)
-          return nullptr;
-      }
-    }
-    if (Cached == UnqualifiedTyposCorrected.end()) {
-      // Provide a stop gap for files that are just seriously broken.  Trying
-      // to correct all typos can turn into a HUGE performance penalty, causing
-      // some files to take minutes to get rejected by the parser.
-      if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
-        return nullptr;
-    }
   }
 
   // Determine whether we are going to search in the various namespaces for
@@ -4249,30 +4214,24 @@ TypoCorrection Sema::CorrectTypo(const D
   // for CTC_Unknown but not for CTC_ObjCMessageReceiver.
   bool ObjCMessageReceiver = CCC->WantObjCSuper && !CCC->WantRemainingKeywords;
 
-  TypoCorrection EmptyCorrection;
-  bool ValidatingCallback = !isCandidateViable(*CCC, EmptyCorrection);
-
   IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
-  bool IsUnqualifiedLookup = false;
   auto Consumer = makeTypoCorrectionConsumer(
       TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
-      EnteringContext, OPT, Mode == CTK_ErrorRecovery, IsUnqualifiedLookup);
+      EnteringContext, OPT, Mode == CTK_ErrorRecovery);
 
   if (!Consumer)
     return TypoCorrection();
 
   // If we haven't found anything, we're done.
   if (Consumer->empty())
-    return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
-                            IsUnqualifiedLookup);
+    return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
 
   // 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);
   unsigned TypoLen = Typo->getName().size();
   if (ED > 0 && TypoLen / ED < 3)
-    return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
-                            IsUnqualifiedLookup);
+    return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
 
   TypoCorrection BestTC = Consumer->getNextCorrection();
   TypoCorrection SecondBestTC = Consumer->getNextCorrection();
@@ -4285,8 +4244,7 @@ TypoCorrection Sema::CorrectTypo(const D
     // 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.
-    return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
-                            IsUnqualifiedLookup && !ValidatingCallback);
+    return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
   }
 
   // If only a single name remains, return that result.
@@ -4299,10 +4257,6 @@ TypoCorrection Sema::CorrectTypo(const D
     if (ED == 0 && Result.isKeyword())
       return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
 
-    // Record the correction for unqualified lookup.
-    if (IsUnqualifiedLookup)
-      UnqualifiedTyposCorrected[Typo] = Result;
-
     TypoCorrection TC = Result;
     TC.setCorrectionRange(SS, TypoName);
     checkCorrectionVisibility(*this, TC);
@@ -4323,10 +4277,6 @@ TypoCorrection Sema::CorrectTypo(const D
         BestTC.getCorrection().getAsString() != "super")
       return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
 
-    // Record the correction for unqualified lookup.
-    if (IsUnqualifiedLookup)
-      UnqualifiedTyposCorrected[Typo] = BestTC;
-
     BestTC.setCorrectionRange(SS, TypoName);
     return BestTC;
   }
@@ -4334,8 +4284,7 @@ TypoCorrection Sema::CorrectTypo(const D
   // Record the failure's location if needed and return an empty correction. If
   // this was an unqualified lookup and we believe the callback object did not
   // filter out possible corrections, also cache the failure for the typo.
-  return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure,
-                          IsUnqualifiedLookup && !ValidatingCallback);
+  return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure);
 }
 
 /// \brief Try to "correct" a typo in the source code by finding
@@ -4386,13 +4335,11 @@ TypoExpr *Sema::CorrectTypoDelayed(
   assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback");
 
   TypoCorrection Empty;
-  bool IsUnqualifiedLookup = false;
   auto Consumer = makeTypoCorrectionConsumer(
       TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
       EnteringContext, OPT,
       /*SearchModules=*/(Mode == CTK_ErrorRecovery) && getLangOpts().Modules &&
-          getLangOpts().ModulesSearchAll,
-      IsUnqualifiedLookup);
+          getLangOpts().ModulesSearchAll);
 
   if (!Consumer || Consumer->empty())
     return nullptr;

Modified: cfe/trunk/test/CXX/class.access/class.friend/p11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.friend/p11.cpp?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p11.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p11.cpp Tue Dec 16 15:39:02 2014
@@ -24,6 +24,8 @@ namespace test2 {
   void foo() { // expected-note {{'::test2::foo' declared here}}
     struct S1 {
       friend void foo(); // expected-error {{no matching function 'foo' found in local scope; did you mean '::test2::foo'?}}
+      // expected-note at -1{{'::test2::foo' declared here}}
+      // TODO: the above note should go on line 24
     };
 
     void foo(); // expected-note {{local declaration nearly matches}}
@@ -40,17 +42,19 @@ namespace test2 {
     {
       int foo;
       struct S3 {
-        friend void foo(); // expected-error {{no matching function found in local scope}}
+        friend void foo(); // expected-error {{no matching function 'foo' found in local scope; did you mean '::test2::foo'?}}
       };
     }
 
     struct S4 {
       friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean '::test2::bar'?}}
+      // expected-note at -1 2 {{'::test2::bar' declared here}}
+      // TODO: the above two notes should go on line 22
     };
 
     { void bar(); }
     struct S5 {
-      friend void bar(); // expected-error {{no matching function found in local scope}}
+      friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean '::test2::bar'?}}
     };
 
     {
@@ -85,7 +89,7 @@ namespace test2 {
       void quux() {}
       void foo() {
         struct Inner1 {
-          friend void bar(); // expected-error {{no matching function found in local scope}}
+          friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean '::test2::bar'?}}
           friend void quux(); // expected-error {{no matching function found in local scope}}
         };
 

Removed: cfe/trunk/test/SemaCXX/typo-correction-pt2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typo-correction-pt2.cpp?rev=224374&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/typo-correction-pt2.cpp (original)
+++ cfe/trunk/test/SemaCXX/typo-correction-pt2.cpp (removed)
@@ -1,358 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
-//
-// FIXME: This file is overflow from test/SemaCXX/typo-correction.cpp due to a
-// hard-coded limit of 20 different typo corrections Sema::CorrectTypo will
-// attempt within a single file (which is to avoid having very broken files take
-// minutes to finally be rejected by the parser).
-
-namespace PR12951 {
-// If there are two corrections that have the same identifier and edit distance
-// and only differ by their namespaces, don't suggest either as a correction
-// since both are equally likely corrections.
-namespace foobar { struct Thing {}; }
-namespace bazquux { struct Thing {}; }
-void f() { Thing t; } // expected-error{{unknown type name 'Thing'}}
-}
-
-namespace bogus_keyword_suggestion {
-void test() {
-   status = "OK";  // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
-   return status;  // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
- }
-}
-
-namespace PR13387 {
-struct A {
-  void CreateFoo(float, float);
-  void CreateBar(float, float);
-};
-struct B : A {
-  using A::CreateFoo;
-  void CreateFoo(int, int);  // expected-note {{'CreateFoo' declared here}}
-};
-void f(B &x) {
-  x.Createfoo(0,0);  // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
-}
-}
-
-struct DataStruct {void foo();};
-struct T {
- DataStruct data_struct;
- void f();
-};
-// should be void T::f();
-void f() {
- data_struct->foo();  // expected-error-re{{use of undeclared identifier 'data_struct'{{$}}}}
-}
-
-namespace PR12287 {
-class zif {
-  void nab(int);
-};
-void nab();  // expected-note{{'::PR12287::nab' declared here}}
-void zif::nab(int) {
-  nab();  // expected-error{{too few arguments to function call, expected 1, have 0; did you mean '::PR12287::nab'?}}
-}
-}
-
-namespace TemplateFunction {
-template <class T>
-void A(T) { }  // expected-note {{'::TemplateFunction::A' declared here}}
-
-template <class T>
-void B(T) { }  // expected-note {{'::TemplateFunction::B' declared here}}
-
-class Foo {
- public:
-  void A(int, int) {}
-  void B() {}
-};
-
-void test(Foo F, int num) {
-  F.A(num);  // expected-error {{too few arguments to function call, expected 2, have 1; did you mean '::TemplateFunction::A'?}}
-  F.B(num);  // expected-error {{too many arguments to function call, expected 0, have 1; did you mean '::TemplateFunction::B'?}}
-}
-}
-namespace using_suggestion_val_dropped_specifier {
-void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}}
-namespace N { }
-using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}}
-}
-
-namespace class_member_typo_corrections {
-class Outer {
-public:
-  class Inner {};  // expected-note {{'Outer::Inner' declared here}}
-  Inner MyMethod(Inner arg);
-};
-
-Inner Outer::MyMethod(Inner arg) {  // expected-error {{unknown type name 'Inner'; did you mean 'Outer::Inner'?}}
-  return Inner();
-}
-
-class Result {
-public:
-  enum ResultType {
-    ENTITY,  // expected-note {{'Result::ENTITY' declared here}}
-    PREDICATE,  // expected-note {{'Result::PREDICATE' declared here}}
-    LITERAL  // expected-note {{'Result::LITERAL' declared here}}
-  };
-
-  ResultType type();
-};
-
-void test() {
-  Result result_cell;
-  switch (result_cell.type()) {
-  case ENTITY:  // expected-error {{use of undeclared identifier 'ENTITY'; did you mean 'Result::ENTITY'?}}
-  case LITERAL:  // expected-error {{use of undeclared identifier 'LITERAL'; did you mean 'Result::LITERAL'?}}
-  case PREDICAT:  // expected-error {{use of undeclared identifier 'PREDICAT'; did you mean 'Result::PREDICATE'?}}
-    break;
-  }
-}
-
-class Figure {
-  enum ResultType {
-    SQUARE,
-    TRIANGLE,
-    CIRCLE
-  };
-
-public:
-  ResultType type();
-};
-
-void testAccess() {
-  Figure obj;
-  switch (obj.type()) {  // expected-warning {{enumeration values 'SQUARE', 'TRIANGLE', and 'CIRCLE' not handled in switch}}
-  case SQUARE:  // expected-error-re {{use of undeclared identifier 'SQUARE'{{$}}}}
-  case TRIANGLE:  // expected-error-re {{use of undeclared identifier 'TRIANGLE'{{$}}}}
-  case CIRCE:  // expected-error-re {{use of undeclared identifier 'CIRCE'{{$}}}}
-    break;
-  }
-}
-}
-
-long readline(const char *, char *, unsigned long);
-void assign_to_unknown_var() {
-    deadline_ = 1;  // expected-error-re {{use of undeclared identifier 'deadline_'{{$}}}}
-}
-
-namespace no_ns_before_dot {
-namespace re2 {}
-void test() {
-    req.set_check(false);  // expected-error-re {{use of undeclared identifier 'req'{{$}}}}
-}
-}
-
-namespace PR17394 {
-  class A {
-  protected:
-    long zzzzzzzzzz;
-  };
-  class B : private A {};
-  B zzzzzzzzzy<>; // expected-error {{expected ';' after top level declarator}}{}
-}
-
-namespace correct_fields_in_member_funcs {
-struct S {
-  int my_member;  // expected-note {{'my_member' declared here}}
-  void f() { my_menber = 1; }  // expected-error {{use of undeclared identifier 'my_menber'; did you mean 'my_member'?}}
-};
-}
-
-namespace PR17019 {
-  template<class F>
-  struct evil {
-    evil(F de) {  // expected-note {{'de' declared here}}
-      de_;  // expected-error {{use of undeclared identifier 'de_'; did you mean 'de'?}} \
-            // expected-warning {{expression result unused}}
-    }
-    ~evil() {
-      de_->bar()  // expected-error {{use of undeclared identifier 'de_'}}
-    }
-  };
-
-  void meow() {
-    evil<int> Q(0); // expected-note {{in instantiation of member function}}
-  }
-}
-
-namespace fix_class_name_qualifier {
-class MessageHeaders {};
-class MessageUtils {
- public:
-  static void ParseMessageHeaders(int, int); // expected-note {{'MessageUtils::ParseMessageHeaders' declared here}}
-};
-
-void test() {
-  // No, we didn't mean to call MessageHeaders::MessageHeaders.
-  MessageHeaders::ParseMessageHeaders(5, 4); // expected-error {{no member named 'ParseMessageHeaders' in 'fix_class_name_qualifier::MessageHeaders'; did you mean 'MessageUtils::ParseMessageHeaders'?}}
-}
-}
-
-namespace PR18213 {  // expected-note {{'PR18213' declared here}}
-struct WrapperInfo {
-  int i;
-};
-
-template <typename T> struct Wrappable {
-  static WrapperInfo kWrapperInfo;
-};
-
-// Note the space before "::PR18213" is intended and needed, as it highlights
-// the actual typo, which is the leading "::".
-// TODO: Suggest removing the "::" from "::PR18213" (the right correction)
-// instead of incorrectly suggesting dropping "PR18213::WrapperInfo::".
-template <>
-PR18213::WrapperInfo ::PR18213::Wrappable<int>::kWrapperInfo = { 0 };  // expected-error {{no member named 'PR18213' in 'PR18213::WrapperInfo'; did you mean simply 'PR18213'?}} \
-                                                                       // expected-error {{C++ requires a type specifier for all declarations}}
-}
-
-namespace PR18651 {
-struct {
-  int x;
-} a, b;
-
-int y = x;  // expected-error-re {{use of undeclared identifier 'x'{{$}}}}
-}
-
-namespace PR18685 {
-template <class C, int I, int J>
-class SetVector {
- public:
-  SetVector() {}
-};
-
-template <class C, int I>
-class SmallSetVector : public SetVector<C, I, 8> {};
-
-class foo {};
-SmallSetVector<foo*, 2> fooSet;
-}
-
-PR18685::BitVector Map;  // expected-error-re {{no type named 'BitVector' in namespace 'PR18685'{{$}}}}
-
-namespace shadowed_template {
-template <typename T> class Fizbin {};  // expected-note {{'::shadowed_template::Fizbin' declared here}}
-class Baz {
-   int Fizbin();
-   // TODO: Teach the parser to recover from the typo correction instead of
-   // continuing to treat the template name as an implicit-int declaration.
-   Fizbin<int> qux;  // expected-error {{unknown type name 'Fizbin'; did you mean '::shadowed_template::Fizbin'?}} \
-                     // expected-error {{expected member name or ';' after declaration specifiers}}
-};
-}
-
-namespace PR18852 {
-void func() {
-  struct foo {
-    void bar() {}
-  };
-  bar();  // expected-error-re {{use of undeclared identifier 'bar'{{$}}}}
-}
-
-class Thread {
- public:
-  void Start();
-  static void Stop();  // expected-note {{'Thread::Stop' declared here}}
-};
-
-class Manager {
- public:
-  void Start(int);  // expected-note {{'Start' declared here}}
-  void Stop(int);  // expected-note {{'Stop' declared here}}
-};
-
-void test(Manager *m) {
-  // Don't suggest Thread::Start as a correction just because it has the same
-  // (unqualified) name and accepts the right number of args; this is a method
-  // call on an object in an unrelated class.
-  m->Start();  // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
-  m->Stop();  // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
-  Stop();  // expected-error {{use of undeclared identifier 'Stop'; did you mean 'Thread::Stop'?}}
-}
-
-}
-
-namespace std {
-class bernoulli_distribution {
- public:
-  double p() const;
-};
-}
-void test() {
-  // Make sure that typo correction doesn't suggest changing 'p' to
-  // 'std::bernoulli_distribution::p' as that is most likely wrong.
-  if (p)  // expected-error-re {{use of undeclared identifier 'p'{{$}}}}
-    return;
-}
-
-namespace PR19681 {
-  struct TypoA {};
-  struct TypoB {
-    void test();
-  private:
-    template<typename T> void private_memfn(T);  // expected-note{{declared here}}
-  };
-  void TypoB::test() {
-    // FIXME: should suggest 'PR19681::TypoB::private_memfn' instead of '::PR19681::TypoB::private_memfn'
-    (void)static_cast<void(TypoB::*)(int)>(&TypoA::private_memfn);  // expected-error{{no member named 'private_memfn' in 'PR19681::TypoA'; did you mean '::PR19681::TypoB::private_memfn'?}}
-  }
-}
-
-namespace testWantFunctionLikeCasts {
-  long test(bool a) {
-    if (a)
-      return struc(5.7);  // expected-error-re {{use of undeclared identifier 'struc'{{$}}}}
-    else
-      return lon(8.0);  // expected-error {{use of undeclared identifier 'lon'; did you mean 'long'?}}
-  }
-}
-
-namespace testCXXDeclarationSpecifierParsing {
-namespace test {
-  struct SomeSettings {};  // expected-note {{'test::SomeSettings' declared here}}
-}
-class Test {};
-int bar() {
-  Test::SomeSettings some_settings; // expected-error {{no type named 'SomeSettings' in 'testCXXDeclarationSpecifierParsing::Test'; did you mean 'test::SomeSettings'?}}
-}
-}
-
-namespace testNonStaticMemberHandling {
-struct Foo {
-  bool usesMetadata;  // expected-note {{'usesMetadata' declared here}}
-};
-int test(Foo f) {
-  if (UsesMetadata)  // expected-error-re {{use of undeclared identifier 'UsesMetadata'{{$}}}}
-    return 5;
-  if (f.UsesMetadata)  // expected-error {{no member named 'UsesMetadata' in 'testNonStaticMemberHandling::Foo'; did you mean 'usesMetadata'?}}
-    return 11;
-  return 0;
-}
-};
-
-namespace testMemberExprDeclarationNameInfo {
-  // The AST should only have the corrected name with no mention of 'data_'.
-  // FIXME: the second typo is being printed out with the location of the first
-  // because the TypoCorrection objects contain the SourceRange but the
-  // UnqualifiedTyposCorrected cache is keyed on IdentifierInfo.
-  void f(int);
-  struct S {
-    int data;  // expected-note 2{{'data' declared here}}
-    void m_fn1() {
-      data_[] =  // expected-error 2{{use of undeclared identifier 'data_'}}  expected-error {{expected expression}}
-          f(data_);
-    }
-  };
-}
-
-namespace testArraySubscriptIndex {
-  struct S {
-    int foodata;  // expected-note {{'foodata' declared here}}
-    void m_fn1() {
-      (+)[foodata_];  // expected-error{{expected expression}} expected-error {{use of undeclared identifier 'foodata_'; did you mean 'foodata'}}
-    }
-  };
-}

Modified: cfe/trunk/test/SemaCXX/typo-correction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typo-correction.cpp?rev=224375&r1=224374&r2=224375&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/typo-correction.cpp (original)
+++ cfe/trunk/test/SemaCXX/typo-correction.cpp Tue Dec 16 15:39:02 2014
@@ -1,8 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions %s
-//
-// WARNING: Do not add more typo correction test cases to this file lest you run
-// afoul the hard-coded limit (escape hatch) of 20 different typos whose
-// correction was attempted by Sema::CorrectTypo
+// RUN: %clang_cc1 -fspell-checking-limit 0 -verify -Wno-c++11-extensions %s
 
 namespace PR21817{
 int a(-rsing[2]); // expected-error {{undeclared identifier 'rsing'; did you mean 'using'?}}
@@ -102,7 +98,7 @@ unknown_type_test::stream_out out; // ex
 // Demonstrate a case where using only the cached value returns the wrong thing
 // when the cached value was the result of a previous callback object that only
 // accepts a subset of the current callback object.
-namespace {
+namespace cache_invalidation_test {
 using namespace unknown_type_test;
 void bar(long i);
 void before_caching_classname() {
@@ -289,13 +285,352 @@ namespace b6956809_test2 {
   }
 }
 
-// This test should have one correction, followed by an error without a
-// suggestion due to exceeding the maximum number of typos for which correction
-// is attempted.
-namespace CorrectTypo_has_reached_its_limit {
-int flibberdy();  // expected-note{{'flibberdy' declared here}}
-int no_correction() {
-  return hibberdy() +  // expected-error{{use of undeclared identifier 'hibberdy'; did you mean 'flibberdy'?}}
-         gibberdy();  // expected-error-re{{use of undeclared identifier 'gibberdy'{{$}}}}
+namespace PR12951 {
+// If there are two corrections that have the same identifier and edit distance
+// and only differ by their namespaces, don't suggest either as a correction
+// since both are equally likely corrections.
+namespace foobar { struct Thing {}; }
+namespace bazquux { struct Thing {}; }
+void f() { Thing t; } // expected-error{{unknown type name 'Thing'}}
+}
+
+namespace bogus_keyword_suggestion {
+void test() {
+   status = "OK";  // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
+   return status;  // expected-error-re {{use of undeclared identifier 'status'{{$}}}}
+ }
+}
+
+namespace PR13387 {
+struct A {
+  void CreateFoo(float, float);
+  void CreateBar(float, float);
+};
+struct B : A {
+  using A::CreateFoo;
+  void CreateFoo(int, int);  // expected-note {{'CreateFoo' declared here}}
+};
+void f(B &x) {
+  x.Createfoo(0,0);  // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
+}
+}
+
+struct DataStruct {void foo();};
+struct T {
+ DataStruct data_struct;
+ void f();
+};
+// should be void T::f();
+void f() {
+ data_struct->foo();  // expected-error-re{{use of undeclared identifier 'data_struct'{{$}}}}
+}
+
+namespace PR12287 {
+class zif {
+  void nab(int);
+};
+void nab();  // expected-note{{'::PR12287::nab' declared here}}
+void zif::nab(int) {
+  nab();  // expected-error{{too few arguments to function call, expected 1, have 0; did you mean '::PR12287::nab'?}}
+}
+}
+
+namespace TemplateFunction {
+template <class T>
+void A(T) { }  // expected-note {{'::TemplateFunction::A' declared here}}
+
+template <class T>
+void B(T) { }  // expected-note {{'::TemplateFunction::B' declared here}}
+
+class Foo {
+ public:
+  void A(int, int) {}
+  void B() {}
+};
+
+void test(Foo F, int num) {
+  F.A(num);  // expected-error {{too few arguments to function call, expected 2, have 1; did you mean '::TemplateFunction::A'?}}
+  F.B(num);  // expected-error {{too many arguments to function call, expected 0, have 1; did you mean '::TemplateFunction::B'?}}
+}
+}
+namespace using_suggestion_val_dropped_specifier {
+void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}}
+namespace N { }
+using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}}
+}
+
+namespace class_member_typo_corrections {
+class Outer {
+public:
+  class Inner {};  // expected-note {{'Outer::Inner' declared here}}
+  Inner MyMethod(Inner arg);
+};
+
+Inner Outer::MyMethod(Inner arg) {  // expected-error {{unknown type name 'Inner'; did you mean 'Outer::Inner'?}}
+  return Inner();
+}
+
+class Result {
+public:
+  enum ResultType {
+    ENTITY,  // expected-note {{'Result::ENTITY' declared here}}
+    PREDICATE,  // expected-note {{'Result::PREDICATE' declared here}}
+    LITERAL  // expected-note {{'Result::LITERAL' declared here}}
+  };
+
+  ResultType type();
+};
+
+void test() {
+  Result result_cell;
+  switch (result_cell.type()) {
+  case ENTITY:  // expected-error {{use of undeclared identifier 'ENTITY'; did you mean 'Result::ENTITY'?}}
+  case LITERAL:  // expected-error {{use of undeclared identifier 'LITERAL'; did you mean 'Result::LITERAL'?}}
+  case PREDICAT:  // expected-error {{use of undeclared identifier 'PREDICAT'; did you mean 'Result::PREDICATE'?}}
+    break;
+  }
+}
+
+class Figure {
+  enum ResultType {
+    SQUARE,
+    TRIANGLE,
+    CIRCLE
+  };
+
+public:
+  ResultType type();
+};
+
+void testAccess() {
+  Figure obj;
+  switch (obj.type()) {  // expected-warning {{enumeration values 'SQUARE', 'TRIANGLE', and 'CIRCLE' not handled in switch}}
+  case SQUARE:  // expected-error-re {{use of undeclared identifier 'SQUARE'{{$}}}}
+  case TRIANGLE:  // expected-error-re {{use of undeclared identifier 'TRIANGLE'{{$}}}}
+  case CIRCE:  // expected-error-re {{use of undeclared identifier 'CIRCE'{{$}}}}
+    break;
+  }
+}
+}
+
+long readline(const char *, char *, unsigned long);
+void assign_to_unknown_var() {
+    deadline_ = 1;  // expected-error-re {{use of undeclared identifier 'deadline_'{{$}}}}
+}
+
+namespace no_ns_before_dot {
+namespace re2 {}
+void test() {
+    req.set_check(false);  // expected-error-re {{use of undeclared identifier 'req'{{$}}}}
+}
+}
+
+namespace PR17394 {
+  class A {
+  protected:
+    long zzzzzzzzzz;
+  };
+  class B : private A {};
+  B zzzzzzzzzy<>; // expected-error {{expected ';' after top level declarator}}{}
+}
+
+namespace correct_fields_in_member_funcs {
+struct S {
+  int my_member;  // expected-note {{'my_member' declared here}}
+  void f() { my_menber = 1; }  // expected-error {{use of undeclared identifier 'my_menber'; did you mean 'my_member'?}}
+};
+}
+
+namespace PR17019 {
+  template<class F>
+  struct evil {
+    evil(F de) {  // expected-note {{'de' declared here}}
+      de_;  // expected-error {{use of undeclared identifier 'de_'; did you mean 'de'?}} \
+            // expected-warning {{expression result unused}}
+    }
+    ~evil() {
+      de_->bar()  // expected-error {{use of undeclared identifier 'de_'}}
+    }
+  };
+
+  void meow() {
+    evil<int> Q(0); // expected-note {{in instantiation of member function}}
+  }
+}
+
+namespace fix_class_name_qualifier {
+class MessageHeaders {};
+class MessageUtils {
+ public:
+  static void ParseMessageHeaders(int, int); // expected-note {{'MessageUtils::ParseMessageHeaders' declared here}}
+};
+
+void test() {
+  // No, we didn't mean to call MessageHeaders::MessageHeaders.
+  MessageHeaders::ParseMessageHeaders(5, 4); // expected-error {{no member named 'ParseMessageHeaders' in 'fix_class_name_qualifier::MessageHeaders'; did you mean 'MessageUtils::ParseMessageHeaders'?}}
+}
+}
+
+namespace PR18213 {  // expected-note {{'PR18213' declared here}}
+struct WrapperInfo {
+  int i;
+};
+
+template <typename T> struct Wrappable {
+  static WrapperInfo kWrapperInfo;
+};
+
+// Note the space before "::PR18213" is intended and needed, as it highlights
+// the actual typo, which is the leading "::".
+// TODO: Suggest removing the "::" from "::PR18213" (the right correction)
+// instead of incorrectly suggesting dropping "PR18213::WrapperInfo::".
+template <>
+PR18213::WrapperInfo ::PR18213::Wrappable<int>::kWrapperInfo = { 0 };  // expected-error {{no member named 'PR18213' in 'PR18213::WrapperInfo'; did you mean simply 'PR18213'?}} \
+                                                                       // expected-error {{C++ requires a type specifier for all declarations}}
+}
+
+namespace PR18651 {
+struct {
+  int x;
+} a, b;
+
+int y = x;  // expected-error-re {{use of undeclared identifier 'x'{{$}}}}
+}
+
+namespace PR18685 {
+template <class C, int I, int J>
+class SetVector {
+ public:
+  SetVector() {}
+};
+
+template <class C, int I>
+class SmallSetVector : public SetVector<C, I, 8> {};
+
+class foo {};
+SmallSetVector<foo*, 2> fooSet;
+}
+
+PR18685::BitVector Map;  // expected-error-re {{no type named 'BitVector' in namespace 'PR18685'{{$}}}}
+
+namespace shadowed_template {
+template <typename T> class Fizbin {};  // expected-note {{'::shadowed_template::Fizbin' declared here}}
+class Baz {
+   int Fizbin();
+   // TODO: Teach the parser to recover from the typo correction instead of
+   // continuing to treat the template name as an implicit-int declaration.
+   Fizbin<int> qux;  // expected-error {{unknown type name 'Fizbin'; did you mean '::shadowed_template::Fizbin'?}} \
+                     // expected-error {{expected member name or ';' after declaration specifiers}}
+};
+}
+
+namespace PR18852 {
+void func() {
+  struct foo {
+    void bar() {}
+  };
+  bar();  // expected-error-re {{use of undeclared identifier 'bar'{{$}}}}
+}
+
+class Thread {
+ public:
+  void Start();
+  static void Stop();  // expected-note {{'Thread::Stop' declared here}}
+};
+
+class Manager {
+ public:
+  void Start(int);  // expected-note {{'Start' declared here}}
+  void Stop(int);  // expected-note {{'Stop' declared here}}
+};
+
+void test(Manager *m) {
+  // Don't suggest Thread::Start as a correction just because it has the same
+  // (unqualified) name and accepts the right number of args; this is a method
+  // call on an object in an unrelated class.
+  m->Start();  // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
+  m->Stop();  // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
+  Stop();  // expected-error {{use of undeclared identifier 'Stop'; did you mean 'Thread::Stop'?}}
+}
+
+}
+
+namespace std {
+class bernoulli_distribution {
+ public:
+  double p() const;
 };
 }
+void test() {
+  // Make sure that typo correction doesn't suggest changing 'p' to
+  // 'std::bernoulli_distribution::p' as that is most likely wrong.
+  if (p)  // expected-error-re {{use of undeclared identifier 'p'{{$}}}}
+    return;
+}
+
+namespace PR19681 {
+  struct TypoA {};
+  struct TypoB {
+    void test();
+  private:
+    template<typename T> void private_memfn(T);  // expected-note{{declared here}}
+  };
+  void TypoB::test() {
+    // FIXME: should suggest 'PR19681::TypoB::private_memfn' instead of '::PR19681::TypoB::private_memfn'
+    (void)static_cast<void(TypoB::*)(int)>(&TypoA::private_memfn);  // expected-error{{no member named 'private_memfn' in 'PR19681::TypoA'; did you mean '::PR19681::TypoB::private_memfn'?}}
+  }
+}
+
+namespace testWantFunctionLikeCasts {
+  long test(bool a) {
+    if (a)
+      return struc(5.7);  // expected-error-re {{use of undeclared identifier 'struc'{{$}}}}
+    else
+      return lon(8.0);  // expected-error {{use of undeclared identifier 'lon'; did you mean 'long'?}}
+  }
+}
+
+namespace testCXXDeclarationSpecifierParsing {
+namespace test {
+  struct SomeSettings {};  // expected-note {{'test::SomeSettings' declared here}}
+}
+class Test {};
+int bar() {
+  Test::SomeSettings some_settings; // expected-error {{no type named 'SomeSettings' in 'testCXXDeclarationSpecifierParsing::Test'; did you mean 'test::SomeSettings'?}}
+}
+}
+
+namespace testNonStaticMemberHandling {
+struct Foo {
+  bool usesMetadata;  // expected-note {{'usesMetadata' declared here}}
+};
+int test(Foo f) {
+  if (UsesMetadata)  // expected-error-re {{use of undeclared identifier 'UsesMetadata'{{$}}}}
+    return 5;
+  if (f.UsesMetadata)  // expected-error {{no member named 'UsesMetadata' in 'testNonStaticMemberHandling::Foo'; did you mean 'usesMetadata'?}}
+    return 11;
+  return 0;
+}
+};
+
+namespace testMemberExprDeclarationNameInfo {
+  // The AST should only have the corrected name with no mention of 'data_'.
+  void f(int);
+  struct S {
+    int data;  // expected-note 2{{'data' declared here}}
+    void m_fn1() {
+      data_  // expected-error {{use of undeclared identifier 'data_'}}
+          [] =  // expected-error {{expected expression}}
+          f(data_);  // expected-error {{use of undeclared identifier 'data_'}}
+    }
+  };
+}
+
+namespace testArraySubscriptIndex {
+  struct S {
+    int data;  // expected-note {{'data' declared here}}
+    void m_fn1() {
+      (+)[data_];  // expected-error{{expected expression}} expected-error {{use of undeclared identifier 'data_'; did you mean 'data'}}
+    }
+  };
+}





More information about the cfe-commits mailing list