1 //===- unittests/libclang/TestUtils.h -------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CLANG_TEST_TESTUTILS_H 10 #define LLVM_CLANG_TEST_TESTUTILS_H 11 12 #include "clang-c/Index.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/Support/FileSystem.h" 15 #include "llvm/Support/Path.h" 16 17 #include "gtest/gtest.h" 18 #include <fstream> 19 #include <functional> 20 #include <memory> 21 #include <string> 22 #include <vector> 23 24 class LibclangParseTest : public ::testing::Test { 25 typedef std::unique_ptr<std::string> fixed_addr_string; 26 std::map<fixed_addr_string, fixed_addr_string> UnsavedFileContents; 27 public: 28 // std::greater<> to remove files before their parent dirs in TearDown(). 29 std::set<std::string, std::greater<>> FilesAndDirsToRemove; 30 std::string TestDir; 31 bool RemoveTestDirRecursivelyDuringTeardown = false; 32 CXIndex Index; 33 CXTranslationUnit ClangTU; 34 unsigned TUFlags; 35 std::vector<CXUnsavedFile> UnsavedFiles; 36 SetUp()37 void SetUp() override { 38 llvm::SmallString<256> Dir; 39 ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir)); 40 TestDir = std::string(Dir.str()); 41 TUFlags = CXTranslationUnit_DetailedPreprocessingRecord | 42 clang_defaultEditingTranslationUnitOptions(); 43 CreateIndex(); 44 ClangTU = nullptr; 45 } TearDown()46 void TearDown() override { 47 clang_disposeTranslationUnit(ClangTU); 48 clang_disposeIndex(Index); 49 50 namespace fs = llvm::sys::fs; 51 for (const std::string &Path : FilesAndDirsToRemove) 52 EXPECT_FALSE(fs::remove(Path, /*IgnoreNonExisting=*/false)); 53 if (RemoveTestDirRecursivelyDuringTeardown) 54 EXPECT_FALSE(fs::remove_directories(TestDir, /*IgnoreErrors=*/false)); 55 else 56 EXPECT_FALSE(fs::remove(TestDir, /*IgnoreNonExisting=*/false)); 57 } WriteFile(std::string & Filename,const std::string & Contents)58 void WriteFile(std::string &Filename, const std::string &Contents) { 59 if (!llvm::sys::path::is_absolute(Filename)) { 60 llvm::SmallString<256> Path(TestDir); 61 namespace path = llvm::sys::path; 62 for (auto FileI = path::begin(Filename), FileEnd = path::end(Filename); 63 FileI != FileEnd; ++FileI) { 64 ASSERT_NE(*FileI, "."); 65 path::append(Path, *FileI); 66 FilesAndDirsToRemove.emplace(Path.str()); 67 } 68 Filename = std::string(Path.str()); 69 } 70 llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename)); 71 std::ofstream OS(Filename); 72 OS << Contents; 73 assert(OS.good()); 74 } MapUnsavedFile(std::string Filename,const std::string & Contents)75 void MapUnsavedFile(std::string Filename, const std::string &Contents) { 76 if (!llvm::sys::path::is_absolute(Filename)) { 77 llvm::SmallString<256> Path(TestDir); 78 llvm::sys::path::append(Path, Filename); 79 Filename = std::string(Path.str()); 80 } 81 auto it = UnsavedFileContents.insert(std::make_pair( 82 fixed_addr_string(new std::string(Filename)), 83 fixed_addr_string(new std::string(Contents)))); 84 UnsavedFiles.push_back({ 85 it.first->first->c_str(), // filename 86 it.first->second->c_str(), // contents 87 it.first->second->size() // length 88 }); 89 } 90 template <typename F> Traverse(const CXCursor & cursor,const F & TraversalFunctor)91 void Traverse(const CXCursor &cursor, const F &TraversalFunctor) { 92 std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor); 93 clang_visitChildren(cursor, 94 &TraverseStateless<std::reference_wrapper<const F>>, 95 &FunctorRef); 96 } 97 Traverse(const F & TraversalFunctor)98 template <typename F> void Traverse(const F &TraversalFunctor) { 99 Traverse(clang_getTranslationUnitCursor(ClangTU), TraversalFunctor); 100 } 101 fromCXString(CXString cx_string)102 static std::string fromCXString(CXString cx_string) { 103 std::string string{clang_getCString(cx_string)}; 104 clang_disposeString(cx_string); 105 return string; 106 }; 107 108 protected: CreateIndex()109 virtual void CreateIndex() { Index = clang_createIndex(0, 0); } 110 111 private: 112 template<typename TState> TraverseStateless(CXCursor cx,CXCursor parent,CXClientData data)113 static CXChildVisitResult TraverseStateless(CXCursor cx, CXCursor parent, 114 CXClientData data) { 115 TState *State = static_cast<TState*>(data); 116 return State->get()(cx, parent); 117 } 118 }; 119 120 #endif // LLVM_CLANG_TEST_TESTUTILS_H 121