r270039 - [Sema] Allow an external sema source to handle delayed typo corrections.

Benjamin Kramer via cfe-commits cfe-commits at lists.llvm.org
Thu May 19 03:52:27 PDT 2016


Author: d0k
Date: Thu May 19 05:46:10 2016
New Revision: 270039

URL: http://llvm.org/viewvc/llvm-project?rev=270039&view=rev
Log:
[Sema] Allow an external sema source to handle delayed typo corrections.

This probably isn't perfectly perfect but allows correcting function calls
again.

Modified:
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=270039&r1=270038&r2=270039&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu May 19 05:46:10 2016
@@ -4781,11 +4781,19 @@ TypoExpr *Sema::CorrectTypoDelayed(
     const ObjCObjectPointerType *OPT) {
   assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback");
 
-  TypoCorrection Empty;
   auto Consumer = makeTypoCorrectionConsumer(
       TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
       EnteringContext, OPT, Mode == CTK_ErrorRecovery);
 
+  // Give the external sema source a chance to correct the typo.
+  TypoCorrection ExternalTypo;
+  if (ExternalSource && Consumer) {
+    ExternalTypo = ExternalSource->CorrectTypo(
+        TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT);
+    if (ExternalTypo)
+      Consumer->addCorrection(ExternalTypo);
+  }
+
   if (!Consumer || Consumer->empty())
     return nullptr;
 
@@ -4793,7 +4801,7 @@ TypoExpr *Sema::CorrectTypoDelayed(
   // is not more that about a third of the length of the typo's identifier.
   unsigned ED = Consumer->getBestEditDistance(true);
   IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
-  if (ED > 0 && Typo->getName().size() / ED < 3)
+  if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3)
     return nullptr;
 
   ExprEvalContexts.back().NumTypos++;

Modified: cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp?rev=270039&r1=270038&r2=270039&view=diff
==============================================================================
--- cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp (original)
+++ cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp Thu May 19 05:46:10 2016
@@ -39,19 +39,18 @@ public:
   bool Result;
 };
 
-// \brief Counts the number of err_using_directive_member_suggest diagnostics
-// correcting from one namespace to another while still passing all diagnostics
-// along a chain of consumers.
-class NamespaceDiagnosticWatcher : public clang::DiagnosticConsumer {
+/// Counts the number of typo-correcting diagnostics correcting from one name to
+/// another while still passing all diagnostics along a chain of consumers.
+class DiagnosticWatcher : public clang::DiagnosticConsumer {
   DiagnosticConsumer *Chained;
-  std::string FromNS;
-  std::string ToNS;
+  std::string FromName;
+  std::string ToName;
 
 public:
-  NamespaceDiagnosticWatcher(StringRef From, StringRef To)
-      : Chained(nullptr), FromNS(From), ToNS("'"), SeenCount(0) {
-    ToNS.append(To);
-    ToNS.append("'");
+  DiagnosticWatcher(StringRef From, StringRef To)
+      : Chained(nullptr), FromName(From), ToName("'"), SeenCount(0) {
+    ToName.append(To);
+    ToName.append("'");
   }
 
   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
@@ -61,7 +60,12 @@ public:
     if (Info.getID() - 1 == diag::err_using_directive_member_suggest) {
       const IdentifierInfo *Ident = Info.getArgIdentifier(0);
       const std::string &CorrectedQuotedStr = Info.getArgStdStr(1);
-      if (Ident->getName() == FromNS && CorrectedQuotedStr == ToNS)
+      if (Ident->getName() == FromName && CorrectedQuotedStr == ToName)
+        ++SeenCount;
+    } else if (Info.getID() == diag::err_no_member_suggest) {
+      auto Ident = DeclarationName::getFromOpaqueInteger(Info.getRawArg(0));
+      const std::string &CorrectedQuotedStr = Info.getArgStdStr(3);
+      if (Ident.getAsString() == FromName && CorrectedQuotedStr == ToName)
         ++SeenCount;
     }
   }
@@ -78,7 +82,7 @@ public:
     return false;
   }
 
-  NamespaceDiagnosticWatcher *Chain(DiagnosticConsumer *ToChain) {
+  DiagnosticWatcher *Chain(DiagnosticConsumer *ToChain) {
     Chained = ToChain;
     return this;
   }
@@ -130,11 +134,53 @@ public:
   int CallCount;
 };
 
-// \brief Chains together a vector of NamespaceDiagnosticWatchers and
+class FunctionTypoProvider : public clang::ExternalSemaSource {
+  std::string CorrectFrom;
+  std::string CorrectTo;
+  Sema *CurrentSema;
+
+public:
+  FunctionTypoProvider(StringRef From, StringRef To)
+      : CorrectFrom(From), CorrectTo(To), CurrentSema(nullptr), CallCount(0) {}
+
+  void InitializeSema(Sema &S) override { CurrentSema = &S; }
+
+  void ForgetSema() override { CurrentSema = nullptr; }
+
+  TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, int LookupKind,
+                             Scope *S, CXXScopeSpec *SS,
+                             CorrectionCandidateCallback &CCC,
+                             DeclContext *MemberContext, bool EnteringContext,
+                             const ObjCObjectPointerType *OPT) override {
+    ++CallCount;
+    if (CurrentSema && Typo.getName().getAsString() == CorrectFrom) {
+      DeclContext *DestContext = nullptr;
+      ASTContext &Context = CurrentSema->getASTContext();
+      if (SS)
+        DestContext = CurrentSema->computeDeclContext(*SS, EnteringContext);
+      if (!DestContext)
+        DestContext = Context.getTranslationUnitDecl();
+      IdentifierInfo *ToIdent =
+          CurrentSema->getPreprocessor().getIdentifierInfo(CorrectTo);
+      auto *NewFunction = FunctionDecl::Create(
+          Context, DestContext, SourceLocation(), SourceLocation(), ToIdent,
+          Context.getFunctionType(Context.VoidTy, {}, {}), nullptr, SC_Static);
+      DestContext->addDecl(NewFunction);
+      TypoCorrection Correction(ToIdent);
+      Correction.addCorrectionDecl(NewFunction);
+      return Correction;
+    }
+    return TypoCorrection();
+  }
+
+  int CallCount;
+};
+
+// \brief Chains together a vector of DiagnosticWatchers and
 // adds a vector of ExternalSemaSources to the CompilerInstance before
 // performing semantic analysis.
 class ExternalSemaSourceInstaller : public clang::ASTFrontendAction {
-  std::vector<NamespaceDiagnosticWatcher *> Watchers;
+  std::vector<DiagnosticWatcher *> Watchers;
   std::vector<clang::ExternalSemaSource *> Sources;
   std::unique_ptr<DiagnosticConsumer> OwnedClient;
 
@@ -170,16 +216,14 @@ public:
     Sources.push_back(Source);
   }
 
-  void PushWatcher(NamespaceDiagnosticWatcher *Watcher) {
-    Watchers.push_back(Watcher);
-  }
+  void PushWatcher(DiagnosticWatcher *Watcher) { Watchers.push_back(Watcher); }
 };
 
-// Make sure that the NamespaceDiagnosticWatcher is not miscounting.
+// Make sure that the DiagnosticWatcher is not miscounting.
 TEST(ExternalSemaSource, SanityCheck) {
   std::unique_ptr<ExternalSemaSourceInstaller> Installer(
       new ExternalSemaSourceInstaller);
-  NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
+  DiagnosticWatcher Watcher("AAB", "BBB");
   Installer->PushWatcher(&Watcher);
   std::vector<std::string> Args(1, "-std=c++11");
   ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
@@ -193,7 +237,7 @@ TEST(ExternalSemaSource, ExternalTypoCor
   std::unique_ptr<ExternalSemaSourceInstaller> Installer(
       new ExternalSemaSourceInstaller);
   NamespaceTypoProvider Provider("AAB", "BBB");
-  NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
+  DiagnosticWatcher Watcher("AAB", "BBB");
   Installer->PushSource(&Provider);
   Installer->PushWatcher(&Watcher);
   std::vector<std::string> Args(1, "-std=c++11");
@@ -211,7 +255,7 @@ TEST(ExternalSemaSource, ExternalTypoCor
   NamespaceTypoProvider First("XXX", "BBB");
   NamespaceTypoProvider Second("AAB", "CCC");
   NamespaceTypoProvider Third("AAB", "DDD");
-  NamespaceDiagnosticWatcher Watcher("AAB", "CCC");
+  DiagnosticWatcher Watcher("AAB", "CCC");
   Installer->PushSource(&First);
   Installer->PushSource(&Second);
   Installer->PushSource(&Third);
@@ -225,6 +269,21 @@ TEST(ExternalSemaSource, ExternalTypoCor
   ASSERT_EQ(1, Watcher.SeenCount);
 }
 
+TEST(ExternalSemaSource, ExternalDelayedTypoCorrection) {
+  std::unique_ptr<ExternalSemaSourceInstaller> Installer(
+      new ExternalSemaSourceInstaller);
+  FunctionTypoProvider Provider("aaa", "bbb");
+  DiagnosticWatcher Watcher("aaa", "bbb");
+  Installer->PushSource(&Provider);
+  Installer->PushWatcher(&Watcher);
+  std::vector<std::string> Args(1, "-std=c++11");
+  ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+      Installer.release(), "namespace AAA { } void foo() { AAA::aaa(); }",
+      Args));
+  ASSERT_LE(0, Provider.CallCount);
+  ASSERT_EQ(1, Watcher.SeenCount);
+}
+
 // We should only try MaybeDiagnoseMissingCompleteType if we can't otherwise
 // solve the problem.
 TEST(ExternalSemaSource, TryOtherTacticsBeforeDiagnosing) {




More information about the cfe-commits mailing list