mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 02:56:06 +00:00

After implementation of "[Clang] Implement P2741R3 - user-generated static_assert messages" (47ccfd7a89e2a9a747a7114db18db1376324799c) the c indexer crashes when handling a `static_assert` w/o any message. This is caused by using `dyn_cast` to get the literal string, which isn't working on `nullptr`. Reviewed By: cor3ntin Differential Revision: https://reviews.llvm.org/D156053
121 lines
4.2 KiB
C++
121 lines
4.2 KiB
C++
//===- unittests/libclang/TestUtils.h -------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_TEST_TESTUTILS_H
|
|
#define LLVM_CLANG_TEST_TESTUTILS_H
|
|
|
|
#include "clang-c/Index.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
#include <fstream>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class LibclangParseTest : public ::testing::Test {
|
|
typedef std::unique_ptr<std::string> fixed_addr_string;
|
|
std::map<fixed_addr_string, fixed_addr_string> UnsavedFileContents;
|
|
public:
|
|
// std::greater<> to remove files before their parent dirs in TearDown().
|
|
std::set<std::string, std::greater<>> FilesAndDirsToRemove;
|
|
std::string TestDir;
|
|
bool RemoveTestDirRecursivelyDuringTeardown = false;
|
|
CXIndex Index;
|
|
CXTranslationUnit ClangTU;
|
|
unsigned TUFlags;
|
|
std::vector<CXUnsavedFile> UnsavedFiles;
|
|
|
|
void SetUp() override {
|
|
llvm::SmallString<256> Dir;
|
|
ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir));
|
|
TestDir = std::string(Dir.str());
|
|
TUFlags = CXTranslationUnit_DetailedPreprocessingRecord |
|
|
clang_defaultEditingTranslationUnitOptions();
|
|
CreateIndex();
|
|
ClangTU = nullptr;
|
|
}
|
|
void TearDown() override {
|
|
clang_disposeTranslationUnit(ClangTU);
|
|
clang_disposeIndex(Index);
|
|
|
|
namespace fs = llvm::sys::fs;
|
|
for (const std::string &Path : FilesAndDirsToRemove)
|
|
EXPECT_FALSE(fs::remove(Path, /*IgnoreNonExisting=*/false));
|
|
if (RemoveTestDirRecursivelyDuringTeardown)
|
|
EXPECT_FALSE(fs::remove_directories(TestDir, /*IgnoreErrors=*/false));
|
|
else
|
|
EXPECT_FALSE(fs::remove(TestDir, /*IgnoreNonExisting=*/false));
|
|
}
|
|
void WriteFile(std::string &Filename, const std::string &Contents) {
|
|
if (!llvm::sys::path::is_absolute(Filename)) {
|
|
llvm::SmallString<256> Path(TestDir);
|
|
namespace path = llvm::sys::path;
|
|
for (auto FileI = path::begin(Filename), FileEnd = path::end(Filename);
|
|
FileI != FileEnd; ++FileI) {
|
|
ASSERT_NE(*FileI, ".");
|
|
path::append(Path, *FileI);
|
|
FilesAndDirsToRemove.emplace(Path.str());
|
|
}
|
|
Filename = std::string(Path.str());
|
|
}
|
|
llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename));
|
|
std::ofstream OS(Filename);
|
|
OS << Contents;
|
|
assert(OS.good());
|
|
}
|
|
void MapUnsavedFile(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 = std::string(Path.str());
|
|
}
|
|
auto it = UnsavedFileContents.insert(std::make_pair(
|
|
fixed_addr_string(new std::string(Filename)),
|
|
fixed_addr_string(new std::string(Contents))));
|
|
UnsavedFiles.push_back({
|
|
it.first->first->c_str(), // filename
|
|
it.first->second->c_str(), // contents
|
|
it.first->second->size() // length
|
|
});
|
|
}
|
|
template <typename F>
|
|
void Traverse(const CXCursor &cursor, const F &TraversalFunctor) {
|
|
std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor);
|
|
clang_visitChildren(cursor,
|
|
&TraverseStateless<std::reference_wrapper<const F>>,
|
|
&FunctorRef);
|
|
}
|
|
|
|
template <typename F> void Traverse(const F &TraversalFunctor) {
|
|
Traverse(clang_getTranslationUnitCursor(ClangTU), TraversalFunctor);
|
|
}
|
|
|
|
static std::string fromCXString(CXString cx_string) {
|
|
std::string string{clang_getCString(cx_string)};
|
|
clang_disposeString(cx_string);
|
|
return string;
|
|
};
|
|
|
|
protected:
|
|
virtual void CreateIndex() { Index = clang_createIndex(0, 0); }
|
|
|
|
private:
|
|
template<typename TState>
|
|
static CXChildVisitResult TraverseStateless(CXCursor cx, CXCursor parent,
|
|
CXClientData data) {
|
|
TState *State = static_cast<TState*>(data);
|
|
return State->get()(cx, parent);
|
|
}
|
|
};
|
|
|
|
#endif // LLVM_CLANG_TEST_TESTUTILS_H
|