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