From 7f4d902dcf1f52e88f2810d4d33521f553fa010f Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Mon, 17 Apr 2017 00:06:01 -0700 Subject: [PATCH] Add alternative compile_commands.json loader using rapidjson. It may be faster than clang. I haven't tested it yet. --- src/cache.cc | 13 +--- src/project.cc | 193 ++++++++++++++++++++++++++++++------------------- src/utils.cc | 11 +++ src/utils.h | 6 ++ 4 files changed, 140 insertions(+), 83 deletions(-) diff --git a/src/cache.cc b/src/cache.cc index 9e711f3c..a31c37d8 100644 --- a/src/cache.cc +++ b/src/cache.cc @@ -17,18 +17,11 @@ std::string GetCachedFileName(std::string source_file) { std::unique_ptr LoadCachedFile(std::string filename) { return nullptr; - std::string cache_file = GetCachedFileName(filename); - - std::ifstream cache; - cache.open(GetCachedFileName(filename)); - if (!cache.good()) + optional file_content = ReadContent(GetCachedFileName(filename)); + if (!file_content) return nullptr; - std::string file_content = std::string( - std::istreambuf_iterator(cache), - std::istreambuf_iterator()); - - optional indexed = Deserialize(filename, file_content); + optional indexed = Deserialize(filename, *file_content); if (indexed) return MakeUnique(indexed.value()); diff --git a/src/project.cc b/src/project.cc index 50122677..99877cc9 100644 --- a/src/project.cc +++ b/src/project.cc @@ -2,41 +2,24 @@ #include "libclangmm/Utility.h" #include "platform.h" +#include "serializer.h" #include "utils.h" #include #include +#include + + +struct CompileCommandsEntry { + std::string directory; + std::string filename; + std::vector args; +}; +MAKE_REFLECT_STRUCT(CompileCommandsEntry, directory, filename, args); namespace { -std::vector LoadFromDirectoryListing(const std::string& project_directory) { - std::vector result; - std::vector 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 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,7 +97,110 @@ static const char *kBlacklist[] = { "..", }; +CompilationEntry GetCompilationEntryFromCompileCommandEntry(const CompileCommandsEntry& entry) { + CompilationEntry result; + result.filename = NormalizePath(entry.filename); + + unsigned int num_args = entry.args.size(); + result.args.reserve(num_args); + for (unsigned int j = 0; j < num_args; ++j) { + std::string arg = entry.args[j]; + + + bool bad = false; + for (auto& entry : kValueArgs) { + if (StartsWith(arg, entry)) { + bad = true; + continue; + } + } + if (bad) { + ++j; + continue; + } + + + for (auto& entry : kBlacklist) { + if (StartsWith(arg, entry)) { + bad = true; + continue; + } + } + if (bad) { + continue; + } + + + if (StartsWith(arg, "-I")) { + std::string path = entry.directory + "/" + arg.substr(2); + path = NormalizePath(path); + arg = "-I" + path; + } + + result.args.push_back(arg); + //if (StartsWith(arg, "-I") || StartsWith(arg, "-D") || StartsWith(arg, "-std")) + } + + // TODO/fixme + result.args.push_back("-xc++"); + result.args.push_back("-std=c++11"); + + return result; +} + +std::vector LoadFromCompileCommandsJson(const std::string& project_directory) { + optional 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 entries; + Reflect(reader, entries); + + std::vector result; + result.reserve(entries.size()); + for (const auto& entry : entries) + result.push_back(GetCompilationEntryFromCompileCommandEntry(entry)); + return result; +} + +std::vector LoadFromDirectoryListing(const std::string& project_directory) { + std::vector result; + + std::vector 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 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 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) { @@ -128,60 +214,21 @@ std::vector LoadCompilationEntriesFromDirectory(const std::str std::vector 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; + + 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 (unsigned int j = 0; j < num_args; ++j) { - std::string arg = clang::ToString(clang_CompileCommand_getArg(cx_command, j)); - - - bool bad = false; - for (auto& entry : kValueArgs) { - if (StartsWith(arg, entry)) { - bad = true; - continue; - } - } - if (bad) { - ++j; - continue; - } - - - for (auto& entry : kBlacklist) { - if (StartsWith(arg, entry)) { - bad = true; - continue; - } - } - if (bad) { - continue; - } - - - if (StartsWith(arg, "-I")) { - std::string path = directory + "/" + arg.substr(2); - path = NormalizePath(path); - arg = "-I" + path; - } - - entry.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.push_back(entry); + 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); diff --git a/src/utils.cc b/src/utils.cc index e617d2c1..eae689d0 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -149,6 +149,17 @@ std::istream& SafeGetline(std::istream& is, std::string& t) { } } +optional ReadContent(const std::string& filename) { + std::ifstream cache; + cache.open(filename); + if (!cache.good()) + return nullopt; + + return std::string( + std::istreambuf_iterator(cache), + std::istreambuf_iterator()); +} + std::vector ReadLines(std::string filename) { std::vector result; diff --git a/src/utils.h b/src/utils.h index 1bc597b7..185c608c 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -8,6 +10,9 @@ #include #include +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 GetFilesInFolder(std::string folder, bool recursive, bool add_folder_to_path); +optional ReadContent(const std::string& filename); std::vector ReadLines(std::string filename); std::vector ToLines(const std::string& content, bool trim_whitespace);