diff --git a/lib/importproject.cpp b/lib/importproject.cpp index 64f978485..146456684 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -220,21 +220,26 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings static std::string readUntil(const std::string &command, std::string::size_type *pos, const char until[]) { std::string ret; + bool escapedString = false; bool str = false; bool escape = false; for (; *pos < command.size() && (str || !std::strchr(until, command[*pos])); (*pos)++) { - if (escape) { + if (escape) escape = false; - if (!std::strchr("\\\"\'", command[*pos])) - ret += '\\'; - ret += command[*pos]; - } else if (str && command[*pos] == '\\') - escape = true; - else { - if (command[*pos] == '\"') - str = !str; - ret += command[*pos]; - } + else if (command[*pos] == '\\') { + if (str) + escape = true; + else if (command[*pos + 1] == '"') { + if (escapedString) + return ret + "\\\""; + escapedString = true; + ret += "\\\""; + (*pos)++; + continue; + } + } else if (command[*pos] == '\"') + str = !str; + ret += command[*pos]; } return ret; } @@ -246,6 +251,8 @@ static std::string unescape(const std::string &in) for (char c: in) { if (escape) { escape = false; + if (!std::strchr("\\\"\'",c)) + out += "\\"; out += c; } else if (c == '\\') escape = true; @@ -259,8 +266,6 @@ void ImportProject::FileSettings::parseCommand(std::string command) { std::string defs; - command = unescape(command); - // Parse command.. std::string::size_type pos = 0; while (std::string::npos != (pos = command.find(' ',pos))) { @@ -280,8 +285,12 @@ void ImportProject::FileSettings::parseCommand(std::string command) } const std::string fval = readUntil(command, &pos, " ="); if (F=='D') { - const std::string defval = readUntil(command, &pos, " "); + std::string defval = readUntil(command, &pos, " "); defs += fval; + if (defval.size() >= 3 && defval.compare(0,2,"=\"")==0 && defval.back()=='\"') + defval = "=" + unescape(defval.substr(2, defval.size() - 3)); + else if (defval.size() >= 5 && defval.compare(0,3,"=\\\"")==0 && endsWith(defval,"\\\"",2)) + defval = "=\"" + unescape(defval.substr(3, defval.size() - 5)) + "\""; if (!defval.empty()) defs += defval; defs += ';'; diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index 515f1702e..aea5ba890 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -50,6 +50,7 @@ private: TEST_CASE(importCompileCommands5); // Windows/CMake/Ninja generated comile_commands.json TEST_CASE(importCompileCommands6); // Windows/CMake/Ninja generated comile_commands.json with spaces TEST_CASE(importCompileCommands7); // linux: "/home/danielm/cppcheck 2" + TEST_CASE(importCompileCommands8); // Windows: "C:\Users\danielm\cppcheck" TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json TEST_CASE(importCppcheckGuiProject); @@ -153,7 +154,6 @@ private: } void importCompileCommands5() const { - /* TODO I am not sure if these are escaped properly const char json[] = R"([{ "directory": "C:/Users/dan/git/build-test-cppcheck-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug", @@ -170,11 +170,9 @@ private: importer.importCompileCommands(istr); ASSERT_EQUALS(2, importer.fileSettings.size()); ASSERT_EQUALS("C:/Users/dan/git/test-cppcheck/mylib/src/", importer.fileSettings.begin()->includePaths.front()); - */ } void importCompileCommands6() const { - /* TODO I am not sure if these are escaped properly const char json[] = R"([{ "directory": "C:/Users/dan/git/build-test-cppcheck-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug", @@ -191,7 +189,6 @@ private: importer.importCompileCommands(istr); ASSERT_EQUALS(2, importer.fileSettings.size()); ASSERT_EQUALS("C:/Users/dan/git/test-cppcheck/mylib/second src/", importer.fileSettings.begin()->includePaths.front()); - */ } @@ -213,6 +210,24 @@ private: // TODO ASSERT_EQUALS("/home/danielm/cppcheck 2/externals/", importer.fileSettings.begin()->includePaths.back()); } + void importCompileCommands8() const { + // cmake -DFILESDIR="C:\Program Files\Cppcheck" -G"NMake Makefiles" .. + const char json[] = + R"([{ + "directory": "C:/Users/danielm/cppcheck/build/lib", + "command": "C:\\PROGRA~2\\MICROS~2\\2017\\COMMUN~1\\VC\\Tools\\MSVC\\1412~1.258\\bin\\Hostx64\\x64\\cl.exe /nologo /TP -DFILESDIR=\"\\\"C:\\Program Files\\Cppcheck\\\"\" -IC:\\Users\\danielm\\cppcheck\\build\\lib -IC:\\Users\\danielm\\cppcheck\\lib -c C:\\Users\\danielm\\cppcheck\\lib\\astutils.cpp", + "file": "C:/Users/danielm/cppcheck/lib/astutils.cpp" + }])"; + std::istringstream istr(json); + TestImporter importer; + importer.importCompileCommands(istr); + ASSERT_EQUALS(1, importer.fileSettings.size()); + ASSERT_EQUALS("FILESDIR=\"C:\\Program Files\\Cppcheck\"", importer.fileSettings.begin()->defines); + ASSERT_EQUALS(2, importer.fileSettings.begin()->includePaths.size()); + ASSERT_EQUALS("C:/Users/danielm/cppcheck/build/lib/", importer.fileSettings.begin()->includePaths.front()); + ASSERT_EQUALS("C:/Users/danielm/cppcheck/lib/", importer.fileSettings.begin()->includePaths.back()); + } + void importCompileCommandsArgumentsSection() const { const char json[] = "[ { \"directory\": \"/tmp/\"," "\"arguments\": [\"gcc\", \"-c\", \"src.c\"],"