diff --git a/lib/importproject.cpp b/lib/importproject.cpp index bb57ed16efc..df77691453a 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -256,7 +256,7 @@ static std::string unescape(const std::string &in) return out; } -void ImportProject::fsParseCommand(FileSettings& fs, const std::string& command) +void ImportProject::fsParseCommand(FileSettings& fs, const std::string& command, bool doUnescape) { std::string defs; @@ -281,10 +281,12 @@ void ImportProject::fsParseCommand(FileSettings& fs, const std::string& command) if (F=='D') { std::string defval = readUntil(command, &pos, " "); defs += fval; - if (defval.size() >= 3 && startsWith(defval,"=\"") && defval.back()=='\"') - defval = "=" + unescape(defval.substr(2, defval.size() - 3)); - else if (defval.size() >= 5 && startsWith(defval, "=\\\"") && endsWith(defval, "\\\"")) - defval = "=\"" + unescape(defval.substr(3, defval.size() - 5)) + "\""; + if (doUnescape) { + if (defval.size() >= 3 && startsWith(defval,"=\"") && defval.back()=='\"') + defval = "=" + unescape(defval.substr(2, defval.size() - 3)); + else if (defval.size() >= 5 && startsWith(defval, "=\\\"") && endsWith(defval, "\\\"")) + defval = "=\"" + unescape(defval.substr(3, defval.size() - 5)) + "\""; + } if (!defval.empty()) defs += defval; defs += ';'; @@ -362,8 +364,10 @@ bool ImportProject::importCompileCommands(std::istream &istr) const std::string directory = std::move(dirpath); + bool doUnescape = false; std::string command; if (obj.count("arguments")) { + doUnescape = false; if (obj["arguments"].is()) { for (const picojson::value& arg : obj["arguments"].get()) { if (arg.is()) { @@ -378,6 +382,7 @@ bool ImportProject::importCompileCommands(std::istream &istr) return false; } } else if (obj.count("command")) { + doUnescape = true; if (obj["command"].is()) { command = obj["command"].get(); } else { @@ -413,7 +418,7 @@ bool ImportProject::importCompileCommands(std::istream &istr) else path = Path::simplifyPath(directory + file); FileSettings fs{path, Standards::Language::None, 0}; // file will be identified later on - fsParseCommand(fs, command); // read settings; -D, -I, -U, -std, -m*, -f* + fsParseCommand(fs, command, doUnescape); // read settings; -D, -I, -U, -std, -m*, -f* std::map variables; fsSetIncludePaths(fs, directory, fs.includePaths, variables); // Assign a unique index to each file path. If the file path already exists in the map, diff --git a/lib/importproject.h b/lib/importproject.h index c30dc849670..d377a2793fb 100644 --- a/lib/importproject.h +++ b/lib/importproject.h @@ -69,7 +69,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject { CPPCHECK_GUI }; - static void fsParseCommand(FileSettings& fs, const std::string& command); + static void fsParseCommand(FileSettings& fs, const std::string& command, bool doUnescape); static void fsSetDefines(FileSettings& fs, std::string defs); static void fsSetIncludePaths(FileSettings& fs, const std::string &basepath, const std::list &in, std::map &variables); diff --git a/test/testimportproject.cpp b/test/testimportproject.cpp index 493689f8a0c..6b2b7a4e212 100644 --- a/test/testimportproject.cpp +++ b/test/testimportproject.cpp @@ -65,6 +65,7 @@ class TestImportProject : public TestFixture { TEST_CASE(importCompileCommands11); // include path order TEST_CASE(importCompileCommands12); // #13040: "directory" is parent directory, relative include paths TEST_CASE(importCompileCommands13); // #13333: duplicate file entries + TEST_CASE(importCompileCommands14); // #14156 TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json TEST_CASE(importCompileCommandsDirectoryMissing); // 'directory' field missing @@ -365,6 +366,29 @@ class TestImportProject : public TestFixture { ASSERT_EQUALS(1, fs2.fileIndex); } + void importCompileCommands14() const { // #14156 + REDIRECT; + constexpr char json[] = + R"([{ + "arguments": [ + "/usr/bin/g++", + "-DTFS_LINUX_MODULE_NAME=\"tfs_linux\"", + "-g", + "-c", + "cli/main.cpp" + ], + "directory": "/home/daniel/cppcheck", + "file": "/home/daniel/cppcheck/cli/main.cpp", + "output": "/home/daniel/cppcheck/cli/main.o" + }])"; + std::istringstream istr(json); + TestImporter importer; + ASSERT_EQUALS(true, importer.importCompileCommands(istr)); + ASSERT_EQUALS(1, importer.fileSettings.size()); + const FileSettings &fs = importer.fileSettings.front(); + ASSERT_EQUALS("TFS_LINUX_MODULE_NAME=\"tfs_linux\"", fs.defines); + } + void importCompileCommandsArgumentsSection() const { REDIRECT; constexpr char json[] = "[ { \"directory\": \"/tmp/\","