Basic support C++20 named module. (#12)

This commit is contained in:
ykiko
2024-12-14 13:40:13 +08:00
committed by GitHub
parent 7d42b4e1ec
commit 5326480cd6
30 changed files with 1082 additions and 593 deletions

118
src/Server/Synchronizer.cpp Normal file
View File

@@ -0,0 +1,118 @@
#include "Compiler/Compiler.h"
#include "Server/Logger.h"
#include "Server/Synchronizer.h"
namespace clice {
void Synchronizer::sync(llvm::StringRef filename) {
/// Read the compile commands from the file.
json::Value json = nullptr;
if(auto buffer = llvm::MemoryBuffer::getFile(filename)) {
if(auto result = json::parse(buffer->get()->getBuffer())) {
/// llvm::json::Value will hold on string buffer.
/// Do not worry about the lifetime of the buffer.
/// Release buffer to save memory.
json = std::move(result.get());
} else {
log::warn("Failed to parse json file at {0}, because {1}",
filename,
result.takeError());
return;
}
} else {
log::warn("Failed to read file {0}", filename);
return;
}
assert(json.kind() != json::Value::Null && "json is nullptr");
if(json.kind() != json::Value::Array) {
log::warn("Compilation Database requires a array of object, but get {0}, input file: {1}",
refl::enum_name(json.kind()),
filename);
return;
}
auto elements = json.getAsArray();
assert(elements && "json is not an array");
for(auto& element: *elements) {
auto object = element.getAsObject();
if(!object) {
log::warn(
"Compilation Database requires an array of object, but get a array of {0}, input file: {1}",
refl::enum_name(element.kind()),
filename);
continue;
}
/// FIXME: currently we assume all path here is absolute.
/// Add `directory` field in the future.
llvm::SmallString<128> path;
if(auto file = object->getString("file")) {
if(auto error = fs::real_path(*file, path)) {
log::warn("Failed to get real path of {0}, because {1}", *file, error.message());
continue;
}
} else {
log::warn("The element does not have a file field, input file: {0}", filename);
continue;
}
auto command = object->getString("command");
if(!command) {
log::warn("The key:{0} does not have a command field, input file: {1}", path, filename);
continue;
}
commands[path] = *command;
}
log::info("Successfully loaded compile commands from {0}, total {1} commands",
filename,
commands.size());
/// Scan all files to build module map.
CompilationParams params;
for(auto& [path, command]: commands) {
params.srcPath = path;
params.command = command;
auto info = scanModule(params);
if(!info) {
log::warn("Failed to scan module from {0}, because {1}", path, info.takeError());
continue;
}
if(info->isInterfaceUnit) {
assert(!info->name.empty() && "module name is empty");
moduleMap[info->name] = path;
}
}
log::info("Successfully built module map, total {0} modules", moduleMap.size());
}
void Synchronizer::sync(llvm::StringRef name, llvm::StringRef path) {
moduleMap[name] = path;
}
llvm::StringRef Synchronizer::lookup(llvm::StringRef file) const {
auto iter = commands.find(file);
if(iter == commands.end()) {
return "";
}
return iter->second;
}
llvm::StringRef Synchronizer::map(llvm::StringRef name) const {
auto iter = moduleMap.find(name);
if(iter == moduleMap.end()) {
return "";
}
return iter->second;
}
} // namespace clice