Add alternative compile_commands.json loader using rapidjson.

It may be faster than clang. I haven't tested it yet.
This commit is contained in:
Jacob Dufault 2017-04-17 00:06:01 -07:00
parent 5e8e13380d
commit 7f4d902dcf
4 changed files with 140 additions and 83 deletions

View File

@ -17,18 +17,11 @@ std::string GetCachedFileName(std::string source_file) {
std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename) {
return nullptr;
std::string cache_file = GetCachedFileName(filename);
std::ifstream cache;
cache.open(GetCachedFileName(filename));
if (!cache.good())
optional<std::string> file_content = ReadContent(GetCachedFileName(filename));
if (!file_content)
return nullptr;
std::string file_content = std::string(
std::istreambuf_iterator<char>(cache),
std::istreambuf_iterator<char>());
optional<IndexedFile> indexed = Deserialize(filename, file_content);
optional<IndexedFile> indexed = Deserialize(filename, *file_content);
if (indexed)
return MakeUnique<IndexedFile>(indexed.value());

View File

@ -2,41 +2,24 @@
#include "libclangmm/Utility.h"
#include "platform.h"
#include "serializer.h"
#include "utils.h"
#include <clang-c/CXCompilationDatabase.h>
#include <iostream>
#include <vector>
struct CompileCommandsEntry {
std::string directory;
std::string filename;
std::vector<std::string> args;
};
MAKE_REFLECT_STRUCT(CompileCommandsEntry, directory, filename, args);
namespace {
std::vector<CompilationEntry> LoadFromDirectoryListing(const std::string& project_directory) {
std::vector<CompilationEntry> result;
std::vector<std::string> args;
std::cerr << "Using arguments: ";
for (const std::string& line : ReadLines(project_directory + "/clang_args")) {
if (line.empty() || StartsWith(line, "#"))
continue;
if (!args.empty())
std::cerr << ", ";
std::cerr << line;
args.push_back(line);
}
std::cerr << std::endl;
std::vector<std::string> files = GetFilesInFolder(project_directory, true /*recursive*/, true /*add_folder_to_path*/);
for (const std::string& file : files) {
if (EndsWith(file, ".cc") || EndsWith(file, ".cpp") || EndsWith(file, ".c")) {
CompilationEntry entry;
entry.filename = NormalizePath(file);
entry.args = args;
result.push_back(entry);
}
}
return result;
}
// https://github.com/Andersbakken/rtags/blob/6b16b81ea93aeff4a58930b44b2a0a207b456192/src/Source.cpp
@ -114,31 +97,14 @@ static const char *kBlacklist[] = {
"..",
};
std::vector<CompilationEntry> LoadCompilationEntriesFromDirectory(const std::string& project_directory) {
CXCompilationDatabase_Error cx_db_load_error;
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(project_directory.c_str(), &cx_db_load_error);
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
std::cerr << "Unable to load compile_commands.json located at \"" << project_directory << "\"; using directory listing instead." << std::endl;
return LoadFromDirectoryListing(project_directory);
}
CompilationEntry GetCompilationEntryFromCompileCommandEntry(const CompileCommandsEntry& entry) {
CompilationEntry result;
result.filename = NormalizePath(entry.filename);
CXCompileCommands cx_commands = clang_CompilationDatabase_getAllCompileCommands(cx_db);
unsigned int num_commands = clang_CompileCommands_getSize(cx_commands);
std::vector<CompilationEntry> result;
for (unsigned int i = 0; i < num_commands; i++) {
CXCompileCommand cx_command = clang_CompileCommands_getCommand(cx_commands, i);
CompilationEntry entry;
std::string directory = clang::ToString(clang_CompileCommand_getDirectory(cx_command));
std::string relative_filename = clang::ToString(clang_CompileCommand_getFilename(cx_command));
std::string absolute_filename = directory + "/" + relative_filename;
entry.filename = NormalizePath(absolute_filename);
unsigned int num_args = clang_CompileCommand_getNumArgs(cx_command);
entry.args.reserve(num_args);
unsigned int num_args = entry.args.size();
result.args.reserve(num_args);
for (unsigned int j = 0; j < num_args; ++j) {
std::string arg = clang::ToString(clang_CompileCommand_getArg(cx_command, j));
std::string arg = entry.args[j];
bool bad = false;
@ -166,23 +132,104 @@ std::vector<CompilationEntry> LoadCompilationEntriesFromDirectory(const std::str
if (StartsWith(arg, "-I")) {
std::string path = directory + "/" + arg.substr(2);
std::string path = entry.directory + "/" + arg.substr(2);
path = NormalizePath(path);
arg = "-I" + path;
}
entry.args.push_back(arg);
result.args.push_back(arg);
//if (StartsWith(arg, "-I") || StartsWith(arg, "-D") || StartsWith(arg, "-std"))
}
// TODO/fixme
entry.args.push_back("-xc++");
entry.args.push_back("-std=c++11");
result.args.push_back("-xc++");
result.args.push_back("-std=c++11");
return result;
}
std::vector<CompilationEntry> LoadFromCompileCommandsJson(const std::string& project_directory) {
optional<std::string> compile_commands_content = ReadContent(project_directory + "/compile_commands.json");
if (!compile_commands_content)
return {};
rapidjson::Document reader;
reader.Parse(compile_commands_content->c_str());
if (reader.HasParseError())
return {};
std::vector<CompileCommandsEntry> entries;
Reflect(reader, entries);
std::vector<CompilationEntry> result;
result.reserve(entries.size());
for (const auto& entry : entries)
result.push_back(GetCompilationEntryFromCompileCommandEntry(entry));
return result;
}
std::vector<CompilationEntry> LoadFromDirectoryListing(const std::string& project_directory) {
std::vector<CompilationEntry> result;
std::vector<std::string> args;
std::cerr << "Using arguments: ";
for (const std::string& line : ReadLines(project_directory + "/clang_args")) {
if (line.empty() || StartsWith(line, "#"))
continue;
if (!args.empty())
std::cerr << ", ";
std::cerr << line;
args.push_back(line);
}
std::cerr << std::endl;
std::vector<std::string> files = GetFilesInFolder(project_directory, true /*recursive*/, true /*add_folder_to_path*/);
for (const std::string& file : files) {
if (EndsWith(file, ".cc") || EndsWith(file, ".cpp") || EndsWith(file, ".c")) {
CompilationEntry entry;
entry.filename = NormalizePath(file);
entry.args = args;
result.push_back(entry);
}
}
return result;
}
std::vector<CompilationEntry> LoadCompilationEntriesFromDirectory(const std::string& project_directory) {
// TODO: Figure out if this function or the clang one is faster.
return LoadFromCompileCommandsJson(project_directory);
CXCompilationDatabase_Error cx_db_load_error;
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(project_directory.c_str(), &cx_db_load_error);
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
std::cerr << "Unable to load compile_commands.json located at \"" << project_directory << "\"; using directory listing instead." << std::endl;
return LoadFromDirectoryListing(project_directory);
}
CXCompileCommands cx_commands = clang_CompilationDatabase_getAllCompileCommands(cx_db);
unsigned int num_commands = clang_CompileCommands_getSize(cx_commands);
std::vector<CompilationEntry> result;
for (unsigned int i = 0; i < num_commands; i++) {
CXCompileCommand cx_command = clang_CompileCommands_getCommand(cx_commands, i);
std::string directory = clang::ToString(clang_CompileCommand_getDirectory(cx_command));
std::string relative_filename = clang::ToString(clang_CompileCommand_getFilename(cx_command));
std::string absolute_filename = directory + "/" + relative_filename;
CompileCommandsEntry entry;
entry.filename = NormalizePath(absolute_filename);
entry.directory = directory;
unsigned int num_args = clang_CompileCommand_getNumArgs(cx_command);
entry.args.reserve(num_args);
for (int i = 0; i < num_args; ++i)
entry.args.push_back(clang::ToString(clang_CompileCommand_getArg(cx_command, i)));
result.push_back(GetCompilationEntryFromCompileCommandEntry(entry));
}
clang_CompileCommands_dispose(cx_commands);
clang_CompilationDatabase_dispose(cx_db);

View File

@ -149,6 +149,17 @@ std::istream& SafeGetline(std::istream& is, std::string& t) {
}
}
optional<std::string> ReadContent(const std::string& filename) {
std::ifstream cache;
cache.open(filename);
if (!cache.good())
return nullopt;
return std::string(
std::istreambuf_iterator<char>(cache),
std::istreambuf_iterator<char>());
}
std::vector<std::string> ReadLines(std::string filename) {
std::vector<std::string> result;

View File

@ -1,5 +1,7 @@
#pragma once
#include <optional.h>
#include <algorithm>
#include <functional>
#include <memory>
@ -8,6 +10,9 @@
#include <unordered_map>
#include <vector>
using std::experimental::optional;
using std::experimental::nullopt;
// Returns true if |value| starts/ends with |start| or |ending|.
bool StartsWith(const std::string& value, const std::string& start);
bool EndsWith(const std::string& value, const std::string& ending);
@ -15,6 +20,7 @@ std::string ReplaceAll(const std::string& source, const std::string& from, const
// Finds all files in the given folder. This is recursive.
std::vector<std::string> GetFilesInFolder(std::string folder, bool recursive, bool add_folder_to_path);
optional<std::string> ReadContent(const std::string& filename);
std::vector<std::string> ReadLines(std::string filename);
std::vector<std::string> ToLines(const std::string& content, bool trim_whitespace);