|
|
|
@ -8,78 +8,30 @@ |
|
|
|
#include <algorithm> |
|
|
|
#include <algorithm> |
|
|
|
#include <regex> |
|
|
|
#include <regex> |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> CompileCommands::Command::parameter_values(const std::string ¶meter_name) const { |
|
|
|
std::vector<std::string> CompileCommands::Command::get_argument_values(const std::string &argument_name) const { |
|
|
|
std::vector<std::string> parameter_values; |
|
|
|
std::vector<std::string> argument_values; |
|
|
|
|
|
|
|
|
|
|
|
bool found_argument = false; |
|
|
|
bool found_argument = false; |
|
|
|
for(auto ¶meter : parameters) { |
|
|
|
for(auto &argument : arguments) { |
|
|
|
if(found_argument) { |
|
|
|
if(found_argument) { |
|
|
|
parameter_values.emplace_back(parameter); |
|
|
|
argument_values.emplace_back(argument); |
|
|
|
found_argument = false; |
|
|
|
found_argument = false; |
|
|
|
} |
|
|
|
} |
|
|
|
else if(parameter == parameter_name) |
|
|
|
else if(argument == argument_name) |
|
|
|
found_argument = true; |
|
|
|
found_argument = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return parameter_values; |
|
|
|
return argument_values; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CompileCommands::CompileCommands(const boost::filesystem::path &build_path) { |
|
|
|
CompileCommands::CompileCommands(const boost::filesystem::path &build_path) { |
|
|
|
try { |
|
|
|
clangmm::CompilationDatabase db(build_path.string()); |
|
|
|
JSON compile_commands(build_path / "compile_commands.json"); |
|
|
|
if(db) { |
|
|
|
for(auto &command : compile_commands.array()) { |
|
|
|
clangmm::CompileCommands compile_commands({}, db); |
|
|
|
boost::filesystem::path directory = command.string("directory"); |
|
|
|
for(auto &command : compile_commands.get_commands()) |
|
|
|
auto parameters_str = command.string("command"); |
|
|
|
commands.emplace_back(Command{clangmm::to_string(clang_CompileCommand_getDirectory(command.cx_command)), |
|
|
|
boost::filesystem::path file = command.string("file"); |
|
|
|
command.get_arguments(), |
|
|
|
|
|
|
|
filesystem::get_absolute_path(clangmm::to_string(clang_CompileCommand_getFilename(command.cx_command)), build_path)}); |
|
|
|
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 = [¶meters, ¶meters_str, ¶meter_start_pos, ¶meter_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(...) { |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -89,46 +41,46 @@ std::vector<std::string> CompileCommands::get_arguments(const boost::filesystem: |
|
|
|
auto extension = file_path.extension().string(); |
|
|
|
auto extension = file_path.extension().string(); |
|
|
|
bool is_header = CompileCommands::is_header(file_path) || extension.empty(); // Include std C++ headers that are without extensions
|
|
|
|
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; |
|
|
|
std::vector<std::string> arguments; |
|
|
|
|
|
|
|
|
|
|
|
if(!build_path.empty()) { |
|
|
|
if(!build_path.empty()) { |
|
|
|
clangmm::CompilationDatabase db(build_path.string()); |
|
|
|
clangmm::CompilationDatabase db(build_path.string()); |
|
|
|
if(db) { |
|
|
|
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); |
|
|
|
clangmm::CompileCommands compile_commands(file_path.string(), db); |
|
|
|
auto commands = compile_commands.get_commands(); |
|
|
|
for(auto &command : compile_commands.get_commands()) |
|
|
|
for(auto &command : commands) { |
|
|
|
compile_commands_arguments.emplace_back(command.get_arguments()); |
|
|
|
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
|
|
|
|
for(auto &command_arguments : compile_commands_arguments) { |
|
|
|
if(ignore_next) |
|
|
|
bool ignore_next = false; |
|
|
|
ignore_next = false; |
|
|
|
for(size_t i = 1; i + 1 < command_arguments.size(); i++) { // Exclude first and last argument
|
|
|
|
else if(cmd_arguments[c] == "-o" || |
|
|
|
if(ignore_next) |
|
|
|
cmd_arguments[c] == "-x" || // Remove language arguments since some tools add languages not understood by clang
|
|
|
|
ignore_next = false; |
|
|
|
(is_header && cmd_arguments[c] == "-include-pch") || // Header files should not use precompiled headers
|
|
|
|
else if(command_arguments[i] == "-o" || |
|
|
|
cmd_arguments[c] == "-MF") { // Exclude dependency file generation
|
|
|
|
command_arguments[i] == "-x" || // Remove language arguments since some tools add languages not understood by clang
|
|
|
|
ignore_next = true; |
|
|
|
(is_header && command_arguments[i] == "-include-pch") || // Header files should not use precompiled headers
|
|
|
|
} |
|
|
|
command_arguments[i] == "-MF") { // Exclude dependency file generation
|
|
|
|
else if(cmd_arguments[c] == "-c") { |
|
|
|
ignore_next = true; |
|
|
|
} |
|
|
|
} |
|
|
|
else if(cmd_arguments[c] == "--") // End of command options
|
|
|
|
else if(command_arguments[i] == "-c") { |
|
|
|
break; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
arguments.emplace_back(cmd_arguments[c]); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else if(command_arguments[i] == "--") // End of command options
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
arguments.emplace_back(command_arguments[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|