]> granicus.if.org Git - clang/commitdiff
Add reparse test for libclang
authorBen Langmuir <blangmuir@apple.com>
Fri, 27 Jun 2014 17:04:26 +0000 (17:04 +0000)
committerBen Langmuir <blangmuir@apple.com>
Fri, 27 Jun 2014 17:04:26 +0000 (17:04 +0000)
Adapted from a reproducer by Dan Schmidt, thanks!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211910 91177308-0d34-0410-b5e6-96231b3b80d8

unittests/libclang/LibclangTest.cpp

index b69b2ac11ff7b830b70712427429c5f8a97864d0..20f742ef4cf7d9d559b427817f4bec558e0d92cc 100644 (file)
@@ -9,6 +9,13 @@
 
 #include "clang-c/Index.h"
 #include "gtest/gtest.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+#include <set>
+#define DEBUG_TYPE "libclang-test"
 
 TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) {
   EXPECT_EQ(CXError_InvalidArguments,
@@ -331,3 +338,85 @@ TEST(libclang, ModuleMapDescriptor) {
   free(BufPtr);
   clang_ModuleMapDescriptor_dispose(MMD);
 }
+
+class LibclangReparseTest : public ::testing::Test {
+  std::string TestDir;
+  std::set<std::string> Files;
+public:
+  CXIndex Index;
+  CXTranslationUnit ClangTU;
+  unsigned TUFlags;
+
+  void SetUp() {
+    llvm::SmallString<256> Dir;
+    ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir));
+    TestDir = Dir.str();
+    TUFlags = CXTranslationUnit_DetailedPreprocessingRecord |
+              clang_defaultEditingTranslationUnitOptions();
+    Index = clang_createIndex(0, 0);
+  }
+  void TearDown() {
+    clang_disposeTranslationUnit(ClangTU);
+    clang_disposeIndex(Index);
+    for (const std::string &Path : Files)
+      llvm::sys::fs::remove(Path);
+    llvm::sys::fs::remove(TestDir);
+  }
+  void WriteFile(std::string &Filename, const std::string &Contents) {
+    if (!llvm::sys::path::is_absolute(Filename)) {
+      llvm::SmallString<256> Path(TestDir);
+      llvm::sys::path::append(Path, Filename);
+      Filename = Path.str();
+      Files.insert(Filename);
+    }
+    std::ofstream OS(Filename);
+    OS << Contents;
+  }
+  void DisplayDiagnostics() {
+    uint NumDiagnostics = clang_getNumDiagnostics(ClangTU);
+    for (uint i = 0; i < NumDiagnostics; ++i) {
+      auto Diag = clang_getDiagnostic(ClangTU, i);
+      DEBUG(llvm::dbgs() << clang_getCString(clang_formatDiagnostic(
+          Diag, clang_defaultDiagnosticDisplayOptions())) << "\n");
+      clang_disposeDiagnostic(Diag);
+    }
+  }
+  bool ReparseTU(uint num_unsaved_files, CXUnsavedFile* unsaved_files) {
+    if (clang_reparseTranslationUnit(ClangTU, num_unsaved_files, unsaved_files,
+                                     clang_defaultReparseOptions(ClangTU))) {
+      DEBUG(llvm::dbgs() << "Reparse failed\n");
+      return false;
+    }
+    DisplayDiagnostics();
+    return true;
+  }
+};
+
+
+TEST_F(LibclangReparseTest, Reparse) {
+  const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";
+  const char *HeaderBottom = "\n};\n#endif\n";
+  const char *CppFile = "#include \"HeaderFile.h\"\nint main() {"
+                         " Foo foo; foo.bar = 7; foo.baz = 8; }\n";
+  std::string HeaderName = "HeaderFile.h";
+  std::string CppName = "CppFile.cpp";
+  WriteFile(CppName, CppFile);
+  WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom);
+
+  ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0,
+                                       nullptr, 0, TUFlags);
+  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
+  DisplayDiagnostics();
+
+  // Immedaitely reparse.
+  ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
+  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
+
+  std::string NewHeaderContents =
+      std::string(HeaderTop) + "int baz;" + HeaderBottom;
+  WriteFile(HeaderName, NewHeaderContents);
+
+  // Reparse after fix.
+  ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
+  EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
+}