Browse Source

Cleanup of CompileCommands class

merge-requests/413/head
eidheim 3 years ago
parent
commit
082cee92ca
  1. 2
      src/cmake.cpp
  2. 142
      src/compile_commands.cpp
  3. 4
      src/compile_commands.hpp
  4. 2
      src/meson.cpp
  5. 16
      tests/compile_commands_test.cpp
  6. 5
      tests/meson_old_test_files/build/compile_commands.json

2
src/cmake.cpp

@ -160,7 +160,7 @@ boost::filesystem::path CMake::get_executable(const boost::filesystem::path &bui
std::vector<std::pair<boost::filesystem::path, boost::filesystem::path>> source_files_and_maybe_executables;
for(auto &command : compile_commands.commands) {
auto source_file = filesystem::get_normal_path(command.file);
auto values = command.parameter_values("-o");
auto values = command.get_argument_values("-o");
if(!values.empty()) {
size_t pos;
if((pos = values[0].find("CMakeFiles/")) != std::string::npos)

142
src/compile_commands.cpp

@ -8,78 +8,30 @@
#include <algorithm>
#include <regex>
std::vector<std::string> CompileCommands::Command::parameter_values(const std::string &parameter_name) const {
std::vector<std::string> parameter_values;
std::vector<std::string> CompileCommands::Command::get_argument_values(const std::string &argument_name) const {
std::vector<std::string> argument_values;
bool found_argument = false;
for(auto &parameter : parameters) {
for(auto &argument : arguments) {
if(found_argument) {
parameter_values.emplace_back(parameter);
argument_values.emplace_back(argument);
found_argument = false;
}
else if(parameter == parameter_name)
else if(argument == argument_name)
found_argument = true;
}
return parameter_values;
return argument_values;
}
CompileCommands::CompileCommands(const boost::filesystem::path &build_path) {
try {
JSON compile_commands(build_path / "compile_commands.json");
for(auto &command : compile_commands.array()) {
boost::filesystem::path directory = command.string("directory");
auto parameters_str = command.string("command");
boost::filesystem::path file = command.string("file");
std::vector<std::string> parameters;
bool backslash = false;
bool single_quote = false;
bool double_quote = false;
size_t parameter_start_pos = std::string::npos;
size_t parameter_size = 0;
auto add_parameter = [&parameters, &parameters_str, &parameter_start_pos, &parameter_size] {
auto parameter = parameters_str.substr(parameter_start_pos, parameter_size);
// Remove escaping
for(size_t c = 0; c < parameter.size() - 1; ++c) {
if(parameter[c] == '\\')
parameter.replace(c, 2, std::string() + parameter[c + 1]);
}
parameters.emplace_back(std::move(parameter));
};
for(size_t c = 0; c < parameters_str.size(); ++c) {
if(backslash)
backslash = false;
else if(parameters_str[c] == '\\')
backslash = true;
else if((parameters_str[c] == ' ' || parameters_str[c] == '\t') && !backslash && !single_quote && !double_quote) {
if(parameter_start_pos != std::string::npos) {
add_parameter();
parameter_start_pos = std::string::npos;
parameter_size = 0;
}
continue;
}
else if(parameters_str[c] == '\'' && !backslash && !double_quote) {
single_quote = !single_quote;
continue;
}
else if(parameters_str[c] == '\"' && !backslash && !single_quote) {
double_quote = !double_quote;
continue;
}
if(parameter_start_pos == std::string::npos)
parameter_start_pos = c;
++parameter_size;
}
if(parameter_start_pos != std::string::npos)
add_parameter();
commands.emplace_back(Command{std::move(directory), std::move(parameters), filesystem::get_absolute_path(file, build_path)});
}
}
catch(...) {
clangmm::CompilationDatabase db(build_path.string());
if(db) {
clangmm::CompileCommands compile_commands({}, db);
for(auto &command : compile_commands.get_commands())
commands.emplace_back(Command{clangmm::to_string(clang_CompileCommand_getDirectory(command.cx_command)),
command.get_arguments(),
filesystem::get_absolute_path(clangmm::to_string(clang_CompileCommand_getFilename(command.cx_command)), build_path)});
}
}
@ -89,46 +41,46 @@ std::vector<std::string> CompileCommands::get_arguments(const boost::filesystem:
auto extension = file_path.extension().string();
bool is_header = CompileCommands::is_header(file_path) || extension.empty(); // Include std C++ headers that are without extensions
// If header file, use source file flags if they are in the same folder
std::vector<boost::filesystem::path> file_paths;
if(is_header && !extension.empty()) {
auto parent_path = file_path.parent_path();
CompileCommands compile_commands(build_path);
for(auto &command : compile_commands.commands) {
if(command.file.parent_path() == parent_path)
file_paths.emplace_back(command.file);
}
}
if(file_paths.empty())
file_paths.emplace_back(file_path);
std::vector<std::string> arguments;
if(!build_path.empty()) {
clangmm::CompilationDatabase db(build_path.string());
if(db) {
for(auto &file_path : file_paths) {
std::vector<std::vector<std::string>> compile_commands_arguments;
// If header file, use source file flags if they are in the same folder
if(is_header && !extension.empty()) {
auto parent_path = file_path.parent_path();
clangmm::CompileCommands compile_commands({}, db);
for(auto &command : compile_commands.get_commands()) {
boost::filesystem::path file = filesystem::get_absolute_path(clangmm::to_string(clang_CompileCommand_getFilename(command.cx_command)), build_path);
if(file.parent_path() == parent_path)
compile_commands_arguments.emplace_back(command.get_arguments());
}
}
if(compile_commands_arguments.empty()) {
clangmm::CompileCommands compile_commands(file_path.string(), db);
auto commands = compile_commands.get_commands();
for(auto &command : commands) {
auto cmd_arguments = command.get_arguments();
bool ignore_next = false;
for(size_t c = 1; c + 1 < cmd_arguments.size(); c++) { // Exclude first and last argument
if(ignore_next)
ignore_next = false;
else if(cmd_arguments[c] == "-o" ||
cmd_arguments[c] == "-x" || // Remove language arguments since some tools add languages not understood by clang
(is_header && cmd_arguments[c] == "-include-pch") || // Header files should not use precompiled headers
cmd_arguments[c] == "-MF") { // Exclude dependency file generation
ignore_next = true;
}
else if(cmd_arguments[c] == "-c") {
}
else if(cmd_arguments[c] == "--") // End of command options
break;
else
arguments.emplace_back(cmd_arguments[c]);
for(auto &command : compile_commands.get_commands())
compile_commands_arguments.emplace_back(command.get_arguments());
}
for(auto &command_arguments : compile_commands_arguments) {
bool ignore_next = false;
for(size_t i = 1; i + 1 < command_arguments.size(); i++) { // Exclude first and last argument
if(ignore_next)
ignore_next = false;
else if(command_arguments[i] == "-o" ||
command_arguments[i] == "-x" || // Remove language arguments since some tools add languages not understood by clang
(is_header && command_arguments[i] == "-include-pch") || // Header files should not use precompiled headers
command_arguments[i] == "-MF") { // Exclude dependency file generation
ignore_next = true;
}
else if(command_arguments[i] == "-c") {
}
else if(command_arguments[i] == "--") // End of command options
break;
else
arguments.emplace_back(command_arguments[i]);
}
}
}

4
src/compile_commands.hpp

@ -8,10 +8,10 @@ public:
class Command {
public:
boost::filesystem::path directory;
std::vector<std::string> parameters;
std::vector<std::string> arguments;
boost::filesystem::path file;
std::vector<std::string> parameter_values(const std::string &parameter_name) const;
std::vector<std::string> get_argument_values(const std::string &argument_name) const;
};
CompileCommands(const boost::filesystem::path &build_path);

2
src/meson.cpp

@ -135,7 +135,7 @@ boost::filesystem::path Meson::get_executable(const boost::filesystem::path &bui
for(auto &command : compile_commands.commands) {
auto source_file = filesystem::get_normal_path(command.file);
auto values = command.parameter_values("-o");
auto values = command.get_argument_values("-o");
if(!values.empty()) {
size_t pos;
if((pos = values[0].find('@')) != std::string::npos) {

16
tests/compile_commands_test.cpp

@ -14,17 +14,11 @@ int main() {
g_assert(compile_commands.commands.at(0).directory == "jucipp/tests/meson_old_test_files/build");
g_assert_cmpuint(compile_commands.commands.size(), ==, 5);
g_assert_cmpuint(compile_commands.commands.size(), ==, 4);
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(0).c_str(), ==, "te's\"t");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(1).c_str(), ==, "te st");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(2).c_str(), ==, "test");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(3).c_str(), ==, "te\\st");
g_assert_cmpstr(compile_commands.commands.at(4).parameters.at(4).c_str(), ==, "te\\\\st");
auto parameter_values = compile_commands.commands.at(0).parameter_values("-o");
g_assert_cmpuint(parameter_values.size(), ==, 1);
g_assert_cmpstr(parameter_values.at(0).c_str(), ==, "hello_lib@sta/main.cpp.o");
auto argument_values = compile_commands.commands.at(0).get_argument_values("-o");
g_assert_cmpuint(argument_values.size(), ==, 1);
g_assert_cmpstr(argument_values.at(0).c_str(), ==, "hello_lib@sta/main.cpp.o");
g_assert(boost::filesystem::canonical(compile_commands.commands.at(0).file) == tests_path / "meson_old_test_files" / "main.cpp");
}
@ -36,6 +30,6 @@ int main() {
g_assert_cmpuint(compile_commands.commands.size(), ==, 1);
g_assert_cmpstr(compile_commands.commands.at(0).parameters.at(2).c_str(), ==, "-Wall");
g_assert_cmpstr(compile_commands.commands.at(0).arguments.at(3).c_str(), ==, "-Wall");
}
}

5
tests/meson_old_test_files/build/compile_commands.json

@ -18,10 +18,5 @@
"directory": "jucipp/tests/meson_old_test_files/build",
"command": "c++ '-Ianother_executable@exe' '-I..' '-I.' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-std=c++11' '-Wall' '-Wextra' '-O0' '-g' '-MMD' '-MQ' 'another_executable@exe/another_file.cpp.o' '-MF' 'another_executable@exe/another_file.cpp.o.d' -o 'another_executable@exe/another_file.cpp.o' -c ../another_file.cpp",
"file": "../another_file.cpp"
},
{
"directory": "jucipp/tests/meson_old_test_files/build",
"command": "'te\\'s\"t' te\\ st test te\\\\st te\\\\\\\\st",
"file": "../parse_test.cpp"
}
]

Loading…
Cancel
Save