]> granicus.if.org Git - clang/commitdiff
Forgot to add unittests/Sema/ before committing r188196 :(
authorKaelyn Uhrain <rikka@google.com>
Mon, 12 Aug 2013 19:57:06 +0000 (19:57 +0000)
committerKaelyn Uhrain <rikka@google.com>
Mon, 12 Aug 2013 19:57:06 +0000 (19:57 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188197 91177308-0d34-0410-b5e6-96231b3b80d8

unittests/Sema/CMakeLists.txt [new file with mode: 0644]
unittests/Sema/ExternalSemaSourceTest.cpp [new file with mode: 0644]
unittests/Sema/Makefile [new file with mode: 0644]

diff --git a/unittests/Sema/CMakeLists.txt b/unittests/Sema/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d491655
--- /dev/null
@@ -0,0 +1,7 @@
+add_clang_unittest(SemaTests
+  ExternalSemaSourceTest.cpp
+  )
+
+target_link_libraries(SemaTests
+  clangAST clangASTMatchers clangTooling
+  )
diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp
new file mode 100644 (file)
index 0000000..8aa626c
--- /dev/null
@@ -0,0 +1,214 @@
+//=== unittests/Sema/ExternalSemaSourceTest.cpp - ExternalSemaSource tests ===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/TypoCorrection.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace clang::tooling;
+
+namespace {
+
+// \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 {
+  DiagnosticConsumer *Chained;
+  std::string FromNS;
+  std::string ToNS;
+
+public:
+  NamespaceDiagnosticWatcher(StringRef From, StringRef To)
+      : Chained(NULL), FromNS(From), ToNS("'"), SeenCount(0) {
+    ToNS.append(To);
+    ToNS.append("'");
+  }
+
+  virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+                                const Diagnostic &Info) {
+    if (Chained)
+      Chained->HandleDiagnostic(DiagLevel, Info);
+    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)
+        ++SeenCount;
+    }
+  }
+
+  virtual void clear() {
+    DiagnosticConsumer::clear();
+    if (Chained)
+      Chained->clear();
+  }
+
+  virtual bool IncludeInDiagnosticCounts() const {
+    if (Chained)
+      return Chained->IncludeInDiagnosticCounts();
+    return false;
+  }
+
+  NamespaceDiagnosticWatcher *Chain(DiagnosticConsumer *ToChain) {
+    Chained = ToChain;
+    return this;
+  }
+
+  int SeenCount;
+};
+
+// \brief Always corrects a typo matching CorrectFrom with a new namespace
+// with the name CorrectTo.
+class NamespaceTypoProvider : public clang::ExternalSemaSource {
+  std::string CorrectFrom;
+  std::string CorrectTo;
+  Sema *CurrentSema;
+
+public:
+  NamespaceTypoProvider(StringRef From, StringRef To)
+      : CorrectFrom(From), CorrectTo(To), CurrentSema(NULL), CallCount(0) {}
+
+  virtual void InitializeSema(Sema &S) { CurrentSema = &S; }
+
+  virtual void ForgetSema() { CurrentSema = NULL; }
+
+  virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
+                                     int LookupKind, Scope *S, CXXScopeSpec *SS,
+                                     CorrectionCandidateCallback &CCC,
+                                     DeclContext *MemberContext,
+                                     bool EnteringContext,
+                                     const ObjCObjectPointerType *OPT) {
+    ++CallCount;
+    if (CurrentSema && Typo.getName().getAsString() == CorrectFrom) {
+      DeclContext *DestContext = NULL;
+      ASTContext &Context = CurrentSema->getASTContext();
+      if (SS != NULL)
+        DestContext = CurrentSema->computeDeclContext(*SS, EnteringContext);
+      if (DestContext == NULL)
+        DestContext = Context.getTranslationUnitDecl();
+      IdentifierInfo *ToIdent =
+          CurrentSema->getPreprocessor().getIdentifierInfo(CorrectTo);
+      NamespaceDecl *NewNamespace =
+          NamespaceDecl::Create(Context, DestContext, false, Typo.getBeginLoc(),
+                                Typo.getLoc(), ToIdent, NULL);
+      DestContext->addDecl(NewNamespace);
+      TypoCorrection Correction(ToIdent);
+      Correction.addCorrectionDecl(NewNamespace);
+      return Correction;
+    }
+    return TypoCorrection();
+  }
+
+  int CallCount;
+};
+
+// \brief Chains together a vector of NamespaceDiagnosticWatchers and
+// adds a vector of ExternalSemaSources to the CompilerInstance before
+// performing semantic analysis.
+class ExternalSemaSourceInstaller : public clang::ASTFrontendAction {
+  std::vector<NamespaceDiagnosticWatcher *> Watchers;
+  std::vector<clang::ExternalSemaSource *> Sources;
+  llvm::OwningPtr<DiagnosticConsumer> OwnedClient;
+
+protected:
+  virtual clang::ASTConsumer *
+  CreateASTConsumer(clang::CompilerInstance &Compiler,
+                    llvm::StringRef /* dummy */) {
+    return new clang::ASTConsumer();
+  }
+
+  virtual void ExecuteAction() {
+    CompilerInstance &CI = getCompilerInstance();
+    ASSERT_FALSE(CI.hasSema());
+    CI.createSema(getTranslationUnitKind(), NULL);
+    ASSERT_TRUE(CI.hasDiagnostics());
+    DiagnosticsEngine &Diagnostics = CI.getDiagnostics();
+    DiagnosticConsumer *Client = Diagnostics.getClient();
+    if (Diagnostics.ownsClient())
+      OwnedClient.reset(Diagnostics.takeClient());
+    for (size_t I = 0, E = Watchers.size(); I < E; ++I)
+      Client = Watchers[I]->Chain(Client);
+    Diagnostics.setClient(Client, false);
+    for (size_t I = 0, E = Sources.size(); I < E; ++I) {
+      Sources[I]->InitializeSema(CI.getSema());
+      CI.getSema().addExternalSource(Sources[I]);
+    }
+    ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
+             CI.getFrontendOpts().SkipFunctionBodies);
+  }
+
+public:
+  void PushSource(clang::ExternalSemaSource *Source) {
+    Sources.push_back(Source);
+  }
+
+  void PushWatcher(NamespaceDiagnosticWatcher *Watcher) {
+    Watchers.push_back(Watcher);
+  }
+};
+
+// Make sure that the NamespaceDiagnosticWatcher is not miscounting.
+TEST(ExternalSemaSource, SanityCheck) {
+  llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+      new ExternalSemaSourceInstaller);
+  NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
+  Installer->PushWatcher(&Watcher);
+  std::vector<std::string> Args(1, "-std=c++11");
+  ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+      Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+  ASSERT_EQ(0, Watcher.SeenCount);
+}
+
+// Check that when we add a NamespaceTypeProvider, we use that suggestion
+// instead of the usual suggestion we would use above.
+TEST(ExternalSemaSource, ExternalTypoCorrectionPrioritized) {
+  llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+      new ExternalSemaSourceInstaller);
+  NamespaceTypoProvider Provider("AAB", "BBB");
+  NamespaceDiagnosticWatcher Watcher("AAB", "BBB");
+  Installer->PushSource(&Provider);
+  Installer->PushWatcher(&Watcher);
+  std::vector<std::string> Args(1, "-std=c++11");
+  ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+      Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+  ASSERT_LE(0, Provider.CallCount);
+  ASSERT_EQ(1, Watcher.SeenCount);
+}
+
+// Check that we use the first successful TypoCorrection returned from an
+// ExternalSemaSource.
+TEST(ExternalSemaSource, ExternalTypoCorrectionOrdering) {
+  llvm::OwningPtr<ExternalSemaSourceInstaller> Installer(
+      new ExternalSemaSourceInstaller);
+  NamespaceTypoProvider First("XXX", "BBB");
+  NamespaceTypoProvider Second("AAB", "CCC");
+  NamespaceTypoProvider Third("AAB", "DDD");
+  NamespaceDiagnosticWatcher Watcher("AAB", "CCC");
+  Installer->PushSource(&First);
+  Installer->PushSource(&Second);
+  Installer->PushSource(&Third);
+  Installer->PushWatcher(&Watcher);
+  std::vector<std::string> Args(1, "-std=c++11");
+  ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs(
+      Installer.take(), "namespace AAA { } using namespace AAB;", Args));
+  ASSERT_LE(1, First.CallCount);
+  ASSERT_LE(1, Second.CallCount);
+  ASSERT_EQ(0, Third.CallCount);
+  ASSERT_EQ(1, Watcher.SeenCount);
+}
+
+} // anonymous namespace
diff --git a/unittests/Sema/Makefile b/unittests/Sema/Makefile
new file mode 100644 (file)
index 0000000..cd1d93d
--- /dev/null
@@ -0,0 +1,19 @@
+##===- unittests/Sema/Makefile -----------------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+TESTNAME = Sema
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
+USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+           clangRewriteCore.a clangRewriteFrontend.a \
+           clangParse.a clangSema.a clangAnalysis.a \
+           clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile