From 54d7831c3b8f99ed297abd939f1cd6a884c03a99 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Fri, 27 Jun 2014 17:04:26 +0000 Subject: [PATCH] Add reparse test for libclang 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 | 89 +++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp index b69b2ac11f..20f742ef4c 100644 --- a/unittests/libclang/LibclangTest.cpp +++ b/unittests/libclang/LibclangTest.cpp @@ -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 +#include +#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 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)); +} -- 2.40.0