Offer typo suggestions for 'using' declarations.

Patch courtesy of Luke Zarko <zarko@google.com>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186019 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e42d249..1c21b2c 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -7024,6 +7024,35 @@
   // be possible for this to happen, because...?
 }
 
+class UsingValidatorCCC : public CorrectionCandidateCallback {
+public:
+  UsingValidatorCCC(bool IsTypeName, bool IsInstantiation)
+      : IsTypeName(IsTypeName), IsInstantiation(IsInstantiation) {}
+  
+  virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
+    if (NamedDecl *ND = Candidate.getCorrectionDecl()) {
+      if (isa<NamespaceDecl>(ND))
+        return false;
+      // Completely unqualified names are invalid for a 'using' declaration.
+      bool droppedSpecifier = Candidate.WillReplaceSpecifier() &&
+                              !Candidate.getCorrectionSpecifier();
+      if (droppedSpecifier)
+        return false;
+      else if (isa<TypeDecl>(ND))
+        return IsTypeName || !IsInstantiation;
+      else
+        return !IsTypeName;
+    } else {
+      // Keywords are not valid here.
+      return false;
+    }
+  }
+
+private:
+  bool IsTypeName;
+  bool IsInstantiation;
+};
+
 /// Builds a using declaration.
 ///
 /// \param IsInstantiation - Whether this call arises from an
@@ -7133,11 +7162,32 @@
 
   LookupQualifiedName(R, LookupContext);
 
+  // Try to correct typos if possible.
   if (R.empty()) {
-    Diag(IdentLoc, diag::err_no_member) 
-      << NameInfo.getName() << LookupContext << SS.getRange();
-    UD->setInvalidDecl();
-    return UD;
+    UsingValidatorCCC CCC(IsTypeName, IsInstantiation);
+    if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+                                               R.getLookupKind(), S, &SS, CCC)){
+      // We reject any correction for which ND would be NULL.
+      NamedDecl *ND = Corrected.getCorrectionDecl();
+      std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+      std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
+      R.setLookupName(Corrected.getCorrection());
+      R.addDecl(ND);
+      // We reject candidates where droppedSpecifier == true, hence the
+      // literal '0' below.
+      Diag(R.getNameLoc(), diag::err_no_member_suggest)
+        << NameInfo.getName() << LookupContext << 0
+        << CorrectedQuotedStr << SS.getRange()
+        << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+                                        CorrectedStr);
+      Diag(ND->getLocation(), diag::note_previous_decl)
+        << CorrectedQuotedStr;
+    } else {
+      Diag(IdentLoc, diag::err_no_member) 
+        << NameInfo.getName() << LookupContext << SS.getRange();
+      UD->setInvalidDecl();
+      return UD;
+    }
   }
 
   if (R.isAmbiguous()) {