xref: /llvm-project/clang/unittests/libclang/TestUtils.h (revision 86da763ab6ed19c58349d3f6f62d4bb52becab2c)
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