Convert SemaExprMember.cpp to pass a callback object to CorrectTypo,
improving the typo correction results in certain situations.

This is also the first typo correction callback conversion to affect
an existing unit test. :)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148140 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 478b2dd..0080156 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -509,6 +509,20 @@
   return true;
 }
 
+namespace {
+
+// Callback to only accept typo corrections that are either a ValueDecl or a
+// FunctionTemplateDecl.
+class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
+ public:
+  virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+    NamedDecl *ND = candidate.getCorrectionDecl();
+    return ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND));
+  }
+};
+
+}
+
 static bool
 LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
                          SourceRange BaseRange, const RecordType *RTy,
@@ -559,13 +573,12 @@
   // We didn't find anything with the given name, so try to correct
   // for typos.
   DeclarationName Name = R.getLookupName();
+  RecordMemberExprValidatorCCC Validator;
   TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
                                                  R.getLookupKind(), NULL,
-                                                 &SS, DC, false,
-                                                 Sema::CTC_MemberLookup);
-  NamedDecl *ND = Corrected.getCorrectionDecl();
+                                                 &SS, &Validator, DC);
   R.clear();
-  if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) {
+  if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
     std::string CorrectedStr(
         Corrected.getAsString(SemaRef.getLangOptions()));
     std::string CorrectedQuotedStr(
@@ -1094,12 +1107,12 @@
 
     if (!IV) {
       // Attempt to correct for typos in ivar names.
-      LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
-                       LookupMemberName);
-      TypoCorrection Corrected = CorrectTypo(
-          R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false,
-          IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup);
-      if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) {
+      DeclFilterCCC<ObjCIvarDecl> Validator;
+      Validator.IsObjCIvarLookup = IsArrow;
+      if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+                                                 LookupMemberName, NULL, NULL,
+                                                 &Validator, IDecl)) {
+        IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
         Diag(R.getNameLoc(),
              diag::err_typecheck_member_reference_ivar_suggest)
           << IDecl->getDeclName() << MemberName << IV->getDeclName()
@@ -1115,8 +1128,6 @@
           << FixItHint::CreateReplacement(OpLoc, ".");
           return ExprError();
         }
-        Res.clear();
-        Res.setLookupName(Member);
 
         Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
           << IDecl->getDeclName() << MemberName
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index db5a051..dbddd1c 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -94,11 +94,11 @@
 namespace PR7508 {
   struct A {
     struct CleanupScope {};
-    void PopCleanupBlock();
+    void PopCleanupBlock(); // expected-note{{'PopCleanupBlock' declared here}}
   };
 
   void foo(A &a) {
-    a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'}}
+    a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'; did you mean 'PopCleanupBlock'?}}
   }
 }
 
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index a4cbbb8..bc3433b 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -37,10 +37,14 @@
 // refer to a base class or non-static data member.
 struct BaseType { };
 struct Derived : public BaseType { // expected-note {{base class 'BaseType' specified here}}
-  static int base_type;
+  static int base_type; // expected-note {{'base_type' declared here}}
   Derived() : basetype() {} // expected-error{{initializer 'basetype' does not name a non-static data member or base class; did you mean the base class 'BaseType'?}}
 };
 
+int get_type(struct Derived *st) {
+  return st->Base_Type; // expected-error{{no member named 'Base_Type' in 'Derived'; did you mean 'base_type'?}}
+}
+
 // In this example, somename should not be corrected to the cached correction
 // "some_name" since "some_name" is a class and a namespace name is needed.
 class some_name {}; // expected-note {{'some_name' declared here}}