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
24class LibclangParseTest : public ::testing::Test {
25 typedef std::unique_ptr<std::string> fixed_addr_string;
26 std::map<fixed_addr_string, fixed_addr_string> UnsavedFileContents;
27public:
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
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 }
46 void TearDown() override {
47 clang_disposeTranslationUnit(ClangTU);
48 clang_disposeIndex(index: 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 }
58 void WriteFile(std::string &Filename, const std::string &Contents) {
59 if (!llvm::sys::path::is_absolute(path: Filename)) {
60 llvm::SmallString<256> Path(TestDir);
61 namespace path = llvm::sys::path;
62 for (auto FileI = path::begin(path: Filename), FileEnd = path::end(path: Filename);
63 FileI != FileEnd; ++FileI) {
64 ASSERT_NE(*FileI, ".");
65 path::append(path&: Path, a: *FileI);
66 FilesAndDirsToRemove.emplace(args: Path.str());
67 }
68 Filename = std::string(Path.str());
69 }
70 llvm::sys::fs::create_directories(path: llvm::sys::path::parent_path(path: Filename));
71 std::ofstream OS(Filename);
72 OS << Contents;
73 assert(OS.good());
74 }
75 void MapUnsavedFile(std::string Filename, const std::string &Contents) {
76 if (!llvm::sys::path::is_absolute(path: Filename)) {
77 llvm::SmallString<256> Path(TestDir);
78 llvm::sys::path::append(path&: Path, a: Filename);
79 Filename = std::string(Path.str());
80 }
81 auto it = UnsavedFileContents.insert(x: std::make_pair(
82 x: fixed_addr_string(new std::string(Filename)),
83 y: fixed_addr_string(new std::string(Contents))));
84 UnsavedFiles.push_back(x: {
85 .Filename: it.first->first->c_str(), // filename
86 .Contents: it.first->second->c_str(), // contents
87 .Length: it.first->second->size() // length
88 });
89 }
90 template <typename F>
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
98 template <typename F> void Traverse(const F &TraversalFunctor) {
99 Traverse(clang_getTranslationUnitCursor(ClangTU), TraversalFunctor);
100 }
101
102 static std::string fromCXString(CXString cx_string) {
103 std::string string{clang_getCString(string: cx_string)};
104 clang_disposeString(string: cx_string);
105 return string;
106 };
107
108protected:
109 virtual void CreateIndex() { Index = clang_createIndex(excludeDeclarationsFromPCH: 0, displayDiagnostics: 0); }
110
111private:
112 template<typename TState>
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

source code of clang/unittests/libclang/TestUtils.h