184 lines
5.5 KiB
C++
184 lines
5.5 KiB
C++
#pragma once
|
|
|
|
#include "Support/Enum.h"
|
|
#include "Support/Format.h"
|
|
#include <expected>
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/Support/Allocator.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
namespace clice {
|
|
|
|
struct CommandOptions {
|
|
/// Attach resource directory to the command.
|
|
bool resource_dir = false;
|
|
|
|
/// Query the compiler driver for additional information, such as system includes and target.
|
|
bool query_driver = false;
|
|
|
|
/// Suppress the warning log if failed to query driver info.
|
|
/// Set true in unittests to avoid cluttering test output.
|
|
bool suppress_log = false;
|
|
};
|
|
|
|
class CompilationDatabase {
|
|
public:
|
|
using Self = CompilationDatabase;
|
|
|
|
enum class UpdateKind : std::uint8_t {
|
|
Unchange,
|
|
Create,
|
|
Update,
|
|
Delete,
|
|
};
|
|
|
|
struct CommandInfo {
|
|
/// TODO: add sysroot or no stdinc command info.
|
|
llvm::StringRef directory;
|
|
|
|
/// The canonical command list.
|
|
llvm::ArrayRef<const char*> arguments;
|
|
};
|
|
|
|
struct DriverInfo {
|
|
/// The target of this driver.
|
|
llvm::StringRef target;
|
|
|
|
/// The default system includes of this driver.
|
|
llvm::ArrayRef<const char*> system_includes;
|
|
};
|
|
|
|
struct UpdateInfo {
|
|
/// The kind of update.
|
|
UpdateKind kind;
|
|
|
|
llvm::StringRef file;
|
|
};
|
|
|
|
struct LookupInfo {
|
|
llvm::StringRef directory;
|
|
|
|
std::vector<const char*> arguments;
|
|
};
|
|
|
|
struct QueryDriverError {
|
|
struct ErrorKind : refl::Enum<ErrorKind> {
|
|
enum Kind : std::uint8_t {
|
|
NotFoundInPATH,
|
|
FailToCreateTempFile,
|
|
InvokeDriverFail,
|
|
OutputFileNotReadable,
|
|
InvalidOutputFormat,
|
|
};
|
|
|
|
using Enum::Enum;
|
|
};
|
|
|
|
ErrorKind kind;
|
|
std::string detail;
|
|
};
|
|
|
|
CompilationDatabase();
|
|
|
|
auto save_string(this Self& self, llvm::StringRef string) -> llvm::StringRef;
|
|
|
|
auto save_cstring_list(this Self& self, llvm::ArrayRef<const char*> arguments)
|
|
-> llvm::ArrayRef<const char*>;
|
|
|
|
/// Get an the option for specific argument.
|
|
static std::optional<std::uint32_t> get_option_id(llvm::StringRef argument);
|
|
|
|
/// Query the compiler driver and return its driver info.
|
|
auto query_driver(this Self& self, llvm::StringRef driver)
|
|
-> std::expected<DriverInfo, QueryDriverError>;
|
|
|
|
/// Update with arguments.
|
|
auto update_command(this Self& self,
|
|
llvm::StringRef dictionary,
|
|
llvm::StringRef file,
|
|
llvm::ArrayRef<const char*> arguments) -> UpdateInfo;
|
|
|
|
/// Update with full command.
|
|
auto update_command(this Self& self,
|
|
llvm::StringRef dictionary,
|
|
llvm::StringRef file,
|
|
llvm::StringRef command) -> UpdateInfo;
|
|
|
|
/// Update commands from json file and return all updated file.
|
|
auto load_commands(this Self& self, llvm::StringRef json_content, llvm::StringRef workspace)
|
|
-> std::expected<std::vector<UpdateInfo>, std::string>;
|
|
|
|
/// Get compile command from database. `file` should has relative path of workspace.
|
|
auto get_command(this Self& self, llvm::StringRef file, CommandOptions options = {})
|
|
-> LookupInfo;
|
|
|
|
/// Load compile commands from given directories. If no valid commands are found,
|
|
/// search recursively from the workspace directory.
|
|
auto load_compile_database(this Self& self,
|
|
llvm::ArrayRef<std::string> compile_commands_dirs,
|
|
llvm::StringRef workspace) -> void;
|
|
|
|
private:
|
|
/// If file not found in CDB file, try to guess commands or use the default case.
|
|
auto guess_or_fallback(this Self& self, llvm::StringRef file) -> LookupInfo;
|
|
|
|
private:
|
|
/// The memory pool to hold all cstring and command list.
|
|
llvm::BumpPtrAllocator allocator;
|
|
|
|
/// A cache between input string and its cache cstring
|
|
/// in the allocator, make sure end with `\0`.
|
|
llvm::DenseSet<llvm::StringRef> string_cache;
|
|
|
|
/// A cache between input command and its cache array
|
|
/// in the allocator.
|
|
llvm::DenseSet<llvm::ArrayRef<const char*>> arguments_cache;
|
|
|
|
/// The clang options we want to filter in all cases, like -c and -o.
|
|
llvm::DenseSet<std::uint32_t> filtered_options;
|
|
|
|
/// A map between file path and its canonical command list.
|
|
llvm::DenseMap<const char*, CommandInfo> command_infos;
|
|
|
|
/// A map between driver path and its query driver info.
|
|
llvm::DenseMap<const char*, DriverInfo> driver_infos;
|
|
};
|
|
|
|
} // namespace clice
|
|
|
|
namespace llvm {
|
|
|
|
template <>
|
|
struct DenseMapInfo<llvm::ArrayRef<const char*>> {
|
|
using T = llvm::ArrayRef<const char*>;
|
|
|
|
inline static T getEmptyKey() {
|
|
return T(reinterpret_cast<T::const_pointer>(~0), T::size_type(0));
|
|
}
|
|
|
|
inline static T getTombstoneKey() {
|
|
return T(reinterpret_cast<T::const_pointer>(~1), T::size_type(0));
|
|
}
|
|
|
|
static unsigned getHashValue(const T& value) {
|
|
return llvm::hash_combine_range(value.begin(), value.end());
|
|
}
|
|
|
|
static bool isEqual(const T& lhs, const T& rhs) {
|
|
return lhs == rhs;
|
|
}
|
|
};
|
|
|
|
} // namespace llvm
|
|
|
|
template <>
|
|
struct std::formatter<clice::CompilationDatabase::QueryDriverError> :
|
|
std::formatter<llvm::StringRef> {
|
|
|
|
template <typename FormatContext>
|
|
auto format(clice::CompilationDatabase::QueryDriverError& e, FormatContext& ctx) const {
|
|
return std::format_to(ctx.out(), "{} {}", e.kind.name(), e.detail);
|
|
}
|
|
};
|