Skip to content

Commit 39f3a75

Browse files
authored
fix #14156: import project: compile_commands.json generated by bear with define with string value (#7853)
1 parent 9aae64d commit 39f3a75

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

lib/importproject.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ static std::string unescape(const std::string &in)
256256
return out;
257257
}
258258

259-
void ImportProject::fsParseCommand(FileSettings& fs, const std::string& command)
259+
void ImportProject::fsParseCommand(FileSettings& fs, const std::string& command, bool doUnescape)
260260
{
261261
std::string defs;
262262

@@ -281,10 +281,12 @@ void ImportProject::fsParseCommand(FileSettings& fs, const std::string& command)
281281
if (F=='D') {
282282
std::string defval = readUntil(command, &pos, " ");
283283
defs += fval;
284-
if (defval.size() >= 3 && startsWith(defval,"=\"") && defval.back()=='\"')
285-
defval = "=" + unescape(defval.substr(2, defval.size() - 3));
286-
else if (defval.size() >= 5 && startsWith(defval, "=\\\"") && endsWith(defval, "\\\""))
287-
defval = "=\"" + unescape(defval.substr(3, defval.size() - 5)) + "\"";
284+
if (doUnescape) {
285+
if (defval.size() >= 3 && startsWith(defval,"=\"") && defval.back()=='\"')
286+
defval = "=" + unescape(defval.substr(2, defval.size() - 3));
287+
else if (defval.size() >= 5 && startsWith(defval, "=\\\"") && endsWith(defval, "\\\""))
288+
defval = "=\"" + unescape(defval.substr(3, defval.size() - 5)) + "\"";
289+
}
288290
if (!defval.empty())
289291
defs += defval;
290292
defs += ';';
@@ -362,8 +364,10 @@ bool ImportProject::importCompileCommands(std::istream &istr)
362364

363365
const std::string directory = std::move(dirpath);
364366

367+
bool doUnescape = false;
365368
std::string command;
366369
if (obj.count("arguments")) {
370+
doUnescape = false;
367371
if (obj["arguments"].is<picojson::array>()) {
368372
for (const picojson::value& arg : obj["arguments"].get<picojson::array>()) {
369373
if (arg.is<std::string>()) {
@@ -378,6 +382,7 @@ bool ImportProject::importCompileCommands(std::istream &istr)
378382
return false;
379383
}
380384
} else if (obj.count("command")) {
385+
doUnescape = true;
381386
if (obj["command"].is<std::string>()) {
382387
command = obj["command"].get<std::string>();
383388
} else {
@@ -413,7 +418,7 @@ bool ImportProject::importCompileCommands(std::istream &istr)
413418
else
414419
path = Path::simplifyPath(directory + file);
415420
FileSettings fs{path, Standards::Language::None, 0}; // file will be identified later on
416-
fsParseCommand(fs, command); // read settings; -D, -I, -U, -std, -m*, -f*
421+
fsParseCommand(fs, command, doUnescape); // read settings; -D, -I, -U, -std, -m*, -f*
417422
std::map<std::string, std::string, cppcheck::stricmp> variables;
418423
fsSetIncludePaths(fs, directory, fs.includePaths, variables);
419424
// Assign a unique index to each file path. If the file path already exists in the map,

lib/importproject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class CPPCHECKLIB WARN_UNUSED ImportProject {
6969
CPPCHECK_GUI
7070
};
7171

72-
static void fsParseCommand(FileSettings& fs, const std::string& command);
72+
static void fsParseCommand(FileSettings& fs, const std::string& command, bool doUnescape);
7373
static void fsSetDefines(FileSettings& fs, std::string defs);
7474
static void fsSetIncludePaths(FileSettings& fs, const std::string &basepath, const std::list<std::string> &in, std::map<std::string, std::string, cppcheck::stricmp> &variables);
7575

test/testimportproject.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class TestImportProject : public TestFixture {
6565
TEST_CASE(importCompileCommands11); // include path order
6666
TEST_CASE(importCompileCommands12); // #13040: "directory" is parent directory, relative include paths
6767
TEST_CASE(importCompileCommands13); // #13333: duplicate file entries
68+
TEST_CASE(importCompileCommands14); // #14156
6869
TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section
6970
TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json
7071
TEST_CASE(importCompileCommandsDirectoryMissing); // 'directory' field missing
@@ -365,6 +366,29 @@ class TestImportProject : public TestFixture {
365366
ASSERT_EQUALS(1, fs2.fileIndex);
366367
}
367368

369+
void importCompileCommands14() const { // #14156
370+
REDIRECT;
371+
constexpr char json[] =
372+
R"([{
373+
"arguments": [
374+
"/usr/bin/g++",
375+
"-DTFS_LINUX_MODULE_NAME=\"tfs_linux\"",
376+
"-g",
377+
"-c",
378+
"cli/main.cpp"
379+
],
380+
"directory": "/home/daniel/cppcheck",
381+
"file": "/home/daniel/cppcheck/cli/main.cpp",
382+
"output": "/home/daniel/cppcheck/cli/main.o"
383+
}])";
384+
std::istringstream istr(json);
385+
TestImporter importer;
386+
ASSERT_EQUALS(true, importer.importCompileCommands(istr));
387+
ASSERT_EQUALS(1, importer.fileSettings.size());
388+
const FileSettings &fs = importer.fileSettings.front();
389+
ASSERT_EQUALS("TFS_LINUX_MODULE_NAME=\"tfs_linux\"", fs.defines);
390+
}
391+
368392
void importCompileCommandsArgumentsSection() const {
369393
REDIRECT;
370394
constexpr char json[] = "[ { \"directory\": \"/tmp/\","

0 commit comments

Comments
 (0)