1. Make resource dir unique and global.
2. Use our custom CDB loader.
This commit is contained in:
@@ -5,45 +5,114 @@
|
||||
namespace clice {
|
||||
|
||||
void CommandManager::update(llvm::StringRef dir) {
|
||||
std::string error;
|
||||
auto CDB = clang::tooling::CompilationDatabase::loadFromDirectory(dir, error);
|
||||
if(!CDB) {
|
||||
log::fatal("Failed to load compilation database from {0}, because {1}", dir, error);
|
||||
llvm::SmallString<128> path;
|
||||
path::append(path, dir, "compile_commands.json");
|
||||
|
||||
auto buffer = llvm::MemoryBuffer::getFile(path);
|
||||
if(!buffer) {
|
||||
log::warn("Failed to read compile_commands.json from {}, because {}",
|
||||
dir,
|
||||
buffer.getError().message());
|
||||
return;
|
||||
}
|
||||
|
||||
CDBs.try_emplace(dir, std::move(CDB));
|
||||
log::info("Successfully loaded compilation database from {0}.", dir);
|
||||
}
|
||||
auto json = json::parse(buffer.get()->getBuffer());
|
||||
if(!json) {
|
||||
log::warn("Failed to parse json file at {}, because {}", path, json.takeError());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> CommandManager::lookup(llvm::StringRef file) {
|
||||
std::vector<std::string> result;
|
||||
for(const auto& [dir, CDB]: CDBs) {
|
||||
auto commands = CDB->getCompileCommands(file);
|
||||
if(commands.empty()) {
|
||||
if(!json->getAsArray()) {
|
||||
log::warn("Invalid JSON format at {}, Compilation Database requires Array, but get {}",
|
||||
path,
|
||||
refl::enum_name(json->kind()));
|
||||
return;
|
||||
}
|
||||
|
||||
auto& CDB = CDBs[dir];
|
||||
|
||||
/// Clear old commands.
|
||||
/// FIXME: it would be better to have cache in some way.
|
||||
CDB.clear();
|
||||
|
||||
for(auto& value: *json->getAsArray()) {
|
||||
auto element = value.getAsObject();
|
||||
if(!element) {
|
||||
log::warn("Invalid JSON format at {}, Compilation Database requires Object, but get {}",
|
||||
path,
|
||||
refl::enum_name(value.kind()));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& args = commands[0].CommandLine;
|
||||
for(auto iter = args.begin(); iter != args.end(); ++iter) {
|
||||
if(iter->starts_with("-o")) {
|
||||
iter++;
|
||||
continue;
|
||||
} else if(iter->starts_with("-c")) {
|
||||
continue;
|
||||
} else if(*iter == "--") {
|
||||
continue;
|
||||
/// Source file path.
|
||||
llvm::SmallString<128> path;
|
||||
|
||||
auto file = element->getString("file");
|
||||
if(!file) {
|
||||
log::warn("the element in {} does not have a file field",
|
||||
path,
|
||||
refl::enum_name(value.kind()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(path::is_relative(file.value())) {
|
||||
auto working = element->getString("directory");
|
||||
if(!working) {
|
||||
log::warn(
|
||||
"Invalid JSON format at {}, {} is relative path, but directory is not provided",
|
||||
path,
|
||||
file.value());
|
||||
}
|
||||
|
||||
result.push_back(std::move(*iter));
|
||||
path::append(path, working.value(), file.value());
|
||||
} else {
|
||||
path::append(path, file.value());
|
||||
}
|
||||
break;
|
||||
|
||||
/// Command to compile the source file.
|
||||
llvm::SmallString<1024> rawCommand;
|
||||
|
||||
if(auto command = element->getString("command")) {
|
||||
rawCommand = command.value();
|
||||
} else if(auto arguments = element->getArray("arguments")) {
|
||||
/// FIXME:
|
||||
std::terminate();
|
||||
} else {
|
||||
log::warn(
|
||||
"Invalid JSON format, the element in {} does not have a command or arguments field",
|
||||
path,
|
||||
refl::enum_name(value.kind()));
|
||||
continue;
|
||||
}
|
||||
|
||||
CDB[path].emplace_back(rawCommand.str());
|
||||
}
|
||||
|
||||
result.push_back("-resource-dir=");
|
||||
result.back() += config::frontend().resource_dictionary;
|
||||
log::info("Compilation Database at {} is up-to-date", dir);
|
||||
}
|
||||
|
||||
return result;
|
||||
llvm::StringRef CommandManager::lookupFirst(llvm::StringRef file) {
|
||||
for(auto& [dir, cdb]: CDBs) {
|
||||
auto iter = cdb.find(file);
|
||||
if(iter != cdb.end()) {
|
||||
return iter->second.front();
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
llvm::ArrayRef<std::string> CommandManager::lookup(llvm::StringRef file) {
|
||||
for(auto& [dir, cdb]: CDBs) {
|
||||
/// FIXME: currently we directly return the first match.
|
||||
/// it is better to provide a callback to handle all matches.
|
||||
auto iter = cdb.find(file);
|
||||
if(iter != cdb.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
|
||||
Reference in New Issue
Block a user