Handle 'arguments' sections in compile_commands.json (#1797)

* Handle 'arguments' sections in compile_commands.json

Previous code assumes 'commands' exists and ill assert if t does not.

* Correct typo checking for "arguments" rather than "commands"

* Use ostringstring rather than stringstream

* Add test deominstrating graceful degradation

* Add test for parsing "arguments" rather than "commands"
This commit is contained in:
bbennetts 2019-04-15 19:03:42 +01:00 committed by Daniel Marjamäki
parent 9a563a7d60
commit 7287ffe781
2 changed files with 47 additions and 2 deletions

View File

@ -30,7 +30,7 @@
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
#include <utility> #include <utility>
#include <sstream>
void ImportProject::ignorePaths(const std::vector<std::string> &ipaths) void ImportProject::ignorePaths(const std::vector<std::string> &ipaths)
{ {
@ -340,7 +340,30 @@ void ImportProject::importCompileCommands(std::istream &istr)
dirpath += '/'; dirpath += '/';
const std::string directory = dirpath; const std::string directory = dirpath;
const std::string command = obj["command"].get<std::string>();
std::ostringstream comm;
if( obj.find( "arguments" ) != obj.end() ) {
if( obj[ "arguments" ].is< picojson::array >() ) {
for( const picojson::value& arg : obj[ "arguments" ].get< picojson::array >() ) {
if( arg.is< std::string >() ) {
comm << arg.get< std::string >() << " ";
}
}
}
else {
return;
}
}
else if( obj.find( "command" ) != obj.end() ) {
if( obj[ "command" ].is< std::string >() ) {
comm << obj[ "command" ].get< std::string >();
}
}
else {
return;
}
const std::string command = comm.str();
const std::string file = Path::fromNativeSeparators(obj["file"].get<std::string>()); const std::string file = Path::fromNativeSeparators(obj["file"].get<std::string>());
// Accept file? // Accept file?

View File

@ -47,6 +47,8 @@ private:
TEST_CASE(importCompileCommands2); // #8563 TEST_CASE(importCompileCommands2); // #8563
TEST_CASE(importCompileCommands3); // check with existing trailing / in directory TEST_CASE(importCompileCommands3); // check with existing trailing / in directory
TEST_CASE(importCompileCommands4); // only accept certain file types TEST_CASE(importCompileCommands4); // only accept certain file types
TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section
TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json
TEST_CASE(importCppcheckGuiProject); TEST_CASE(importCppcheckGuiProject);
} }
@ -138,6 +140,26 @@ private:
ASSERT_EQUALS(0, importer.fileSettings.size()); ASSERT_EQUALS(0, importer.fileSettings.size());
} }
void importCompileCommandsArgumentsSection() const {
const char json[] = "[ { \"directory\": \"/tmp/\","
"\"arguments\": [\"gcc\", \"-c\", \"src.c\"],"
"\"file\": \"src.c\" } ]";
std::istringstream istr(json);
TestImporter importer;
importer.importCompileCommands(istr);
ASSERT_EQUALS(1, importer.fileSettings.size());
ASSERT_EQUALS("/tmp/src.c", importer.fileSettings.begin()->filename);
}
void importCompileCommandsNoCommandSection() const {
const char json[] = "[ { \"directory\": \"/tmp/\","
"\"file\": \"src.mm\" } ]";
std::istringstream istr(json);
TestImporter importer;
importer.importCompileCommands(istr);
ASSERT_EQUALS(0, importer.fileSettings.size());
}
void importCppcheckGuiProject() const { void importCppcheckGuiProject() const {
const char xml[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" const char xml[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<project version=\"1\">\n" "<project version=\"1\">\n"