Fix false skipping of folder-seperator (#2749)

This commit is contained in:
Dan 2020-09-06 15:35:14 +02:00 committed by GitHub
parent f3fa7a6f5e
commit 7efd84ecaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 160 additions and 100 deletions

View File

@ -162,7 +162,7 @@ void ImportProject::FileSettings::setIncludePaths(const std::string &basepath, c
continue; continue;
if (it.compare(0,2,"%(")==0) if (it.compare(0,2,"%(")==0)
continue; continue;
std::string s(Path::fromNativeSeparators(it)); std::string s(Path::removeQuotationMarks(Path::fromNativeSeparators(it)));
if (s[0] == '/' || (s.size() > 1U && s.compare(1,2,":/") == 0)) { if (s[0] == '/' || (s.size() > 1U && s.compare(1,2,":/") == 0)) {
if (!endsWith(s,'/')) if (!endsWith(s,'/'))
s += '/'; s += '/';
@ -217,13 +217,13 @@ ImportProject::Type ImportProject::import(const std::string &filename, Settings
return ImportProject::Type::UNKNOWN; return ImportProject::Type::UNKNOWN;
} }
static std::string readUntil(const std::string &command, std::string::size_type *pos, const char until[]) static std::string readUntil(const std::string& command, std::string::size_type* pos, const char until[], bool skipBackSlash = true)
{ {
std::string ret; std::string ret;
bool str = false; bool str = false;
while (*pos < command.size() && (str || !std::strchr(until, command[*pos]))) { while (*pos < command.size() && (str || !std::strchr(until, command[*pos]))) {
if (command[*pos] == '\\') if (skipBackSlash && command[*pos] == '\\')
++*pos; ++* pos;
if (*pos < command.size()) if (*pos < command.size())
ret += command[(*pos)++]; ret += command[(*pos)++];
if (endsWith(ret, '\"')) if (endsWith(ret, '\"'))
@ -232,42 +232,35 @@ static std::string readUntil(const std::string &command, std::string::size_type
return ret; return ret;
} }
void ImportProject::FileSettings::parseCommand(const std::string &command) static void skip_whitespaces(const std::string& command, std::string::size_type *pos)
{ {
std::string defs; while (*pos < command.size() && command[*pos] == ' ')
(*pos)++;
}
// Parse command..
std::string::size_type pos = 0; static std::string parseTillNextCommandOpt(const std::string& singleCharOpts, const std::string& command, std::string::size_type *pos)
while (std::string::npos != (pos = command.find(' ',pos))) { {
while (pos < command.size() && command[pos] == ' ') std::string ret;
pos++; *pos = command.find_first_not_of("/-", *pos);
if (pos >= command.size())
break; if (*pos >= command.size())
if (command[pos] != '/' && command[pos] != '-') return ret;
continue;
pos++; const char F = command[*pos];
if (pos >= command.size()) if (std::strchr(singleCharOpts.c_str(), F)) {
break; (*pos)++;
const char F = command[pos++]; return std::string{F};
if (std::strchr("DUI", F)) {
while (pos < command.size() && command[pos] == ' ')
++pos;
} }
const std::string fval = readUntil(command, &pos, " =");
if (F=='D') { ret = readUntil(command, pos, " =");
const std::string defval = readUntil(command, &pos, " "); return ret;
defs += fval; }
if (!defval.empty())
defs += defval; void ImportProject::FileSettings::parseCommandStd(const std::string& command, std::string::size_type *pos, std::string& defs)
defs += ';'; {
} else if (F=='U') std::string def{};
undefs.insert(fval); const std::string stdval = readUntil(command, pos, " ");
else if (F=='I') {
if (std::find(includePaths.begin(), includePaths.end(), fval) == includePaths.end())
includePaths.push_back(fval);
} else if (F=='s' && fval.compare(0,2,"td") == 0) {
++pos;
const std::string stdval = readUntil(command, &pos, " ");
standard = stdval; standard = stdval;
if (standard.compare(0, 3, "c++") || standard.compare(0, 5, "gnu++")) { if (standard.compare(0, 3, "c++") || standard.compare(0, 5, "gnu++")) {
std::string stddef; std::string stddef;
@ -283,61 +276,82 @@ void ImportProject::FileSettings::parseCommand(const std::string &command)
if (stddef.empty()) { if (stddef.empty()) {
// TODO: log error // TODO: log error
continue; } else {
def += "__cplusplus=";
def += stddef;
def += ";";
} }
defs += "__cplusplus=";
defs += stddef;
defs += ";";
} else if (standard.compare(0, 1, "c") || standard.compare(0, 3, "gnu")) {
if (standard == "c90" || standard == "iso9899:1990" || standard == "gnu90" || standard == "iso9899:199409") {
// __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments
continue;
} }
defs += def;
}
std::string stddef; void ImportProject::FileSettings::parseCommandDefine(const std::string& command, std::string::size_type *pos, std::string& defs)
{
const bool skipBackSlash = false;
defs += readUntil(command, pos, " =");
const std::string defval = readUntil(command, pos, " ", skipBackSlash);
if (!defval.empty())
defs += defval;
defs += ';';
}
if (standard == "c99" || standard == "iso9899:1999" || standard == "gnu99") { void ImportProject::FileSettings::parseCommandUndefine(const std::string& command, std::string::size_type *pos)
stddef = "199901L"; {
} else if (standard == "c11" || standard == "iso9899:2011" || standard == "gnu11" || standard == "c1x" || standard == "gnu1x") { const std::string fval = readUntil(command, pos, " ");
stddef = "201112L"; undefs.insert(fval);
} else if (standard == "c17") { }
stddef = "201710L";
}
if (stddef.empty()) { void ImportProject::FileSettings::parseCommandInclude(const std::string& command, std::string::size_type *pos)
// TODO: log error {
continue; const bool skipBackSlash = false;
} const std::string fval = readUntil(command, pos, " ", skipBackSlash);
if (std::find(includePaths.begin(), includePaths.end(), fval) == includePaths.end())
includePaths.push_back(fval);
}
defs += "__STDC_VERSION__="; void ImportProject::FileSettings::parseCommandSystemInclude(const std::string& command, std::string::size_type *pos)
defs += stddef; {
defs += ";"; const bool skipBackSlash = false;
} const std::string isystem = Path::removeQuotationMarks(readUntil(command, pos, " ", skipBackSlash));
} else if (F == 'i' && fval == "system") {
++pos;
const std::string isystem = readUntil(command, &pos, " ");
systemIncludePaths.push_back(isystem); systemIncludePaths.push_back(isystem);
} else if (F=='m') { }
if (fval == "unicode") {
defs += "UNICODE"; void ImportProject::FileSettings::parseCommand(const std::string &command)
defs += ";"; {
} const std::string singleCharCommandOpts = "DUI";
} else if (F=='f') { std::string defs;
if (fval == "pic") {
defs += "__pic__"; std::string::size_type pos = 0;
defs += ";"; while (std::string::npos != (pos = command.find(' ',pos))) {
} else if (fval == "PIC") { skip_whitespaces(command, &pos);
defs += "__PIC__"; if (pos >= command.size())
defs += ";"; break;
} else if (fval == "pie") {
defs += "__pie__"; const auto opt = parseTillNextCommandOpt(singleCharCommandOpts, command, &pos);
defs += ";";
} else if (fval == "PIE") { if (pos >= command.size())
defs += "__PIE__"; break;
defs += ";";
} if (opt=="D")
} parseCommandDefine(command, &pos, defs);
else if (opt=="U")
parseCommandUndefine(command, &pos);
else if (opt=="I")
parseCommandInclude(command, &pos);
else if (opt=="isystem")
parseCommandSystemInclude(command, &pos);
else if (opt=="std")
parseCommandStd(command, &pos, defs);
else if (opt=="municode")
defs += "UNICODE;";
else if (opt=="fpic")
defs += "__pic__;";
else if (opt=="fPIC")
defs += "__PIC__;";
else if (opt=="fpie")
defs += "__pie__;";
else if (opt=="fPIE")
defs += "__PIE__;";
} }
setDefines(defs); setDefines(defs);
} }

View File

@ -77,6 +77,12 @@ public:
bool useMfc; bool useMfc;
void parseCommand(const std::string &command); void parseCommand(const std::string &command);
void parseCommandStd(const std::string& command, std::string::size_type *pos, std::string& defs);
void parseCommandDefine(const std::string& command, std::string::size_type *pos, std::string& defs);
void parseCommandUndefine(const std::string& command, std::string::size_type *pos);
void parseCommandInclude(const std::string& command, std::string::size_type *pos);
void parseCommandSystemInclude(const std::string& command, std::string::size_type *pos);
void setDefines(std::string defs); void setDefines(std::string defs);
void setIncludePaths(const std::string &basepath, const std::list<std::string> &in, std::map<std::string, std::string, cppcheck::stricmp> &variables); void setIncludePaths(const std::string &basepath, const std::list<std::string> &in, std::map<std::string, std::string, cppcheck::stricmp> &variables);
}; };

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(importCompileCommands5); // Windows/CMake/Ninja generated comile_commands.json
TEST_CASE(importCompileCommands6); // Windows/CMake/Ninja generated comile_commands.json with spaces
TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section TEST_CASE(importCompileCommandsArgumentsSection); // Handle arguments section
TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json TEST_CASE(importCompileCommandsNoCommandSection); // gracefully handles malformed json
TEST_CASE(importCppcheckGuiProject); TEST_CASE(importCppcheckGuiProject);
@ -100,7 +102,7 @@ private:
void importCompileCommands1() const { void importCompileCommands1() const {
const char json[] = "[ { \"directory\": \"/tmp\"," const char json[] = "[ { \"directory\": \"/tmp\","
"\"command\": \"gcc -I/tmp -DFILESDIR=\\\\\\\"/usr/local/share/Cppcheck\\\\\\\" -DTEST1 -DTEST2=2 -o /tmp/src.o -c /tmp/src.c\"," "\"command\": \"gcc -I/tmp -DFILESDIR=\\\"/usr/local/share/Cppcheck\\\" -DTEST1 -DTEST2=2 -o /tmp/src.o -c /tmp/src.c\","
"\"file\": \"/tmp/src.c\" } ]"; "\"file\": \"/tmp/src.c\" } ]";
std::istringstream istr(json); std::istringstream istr(json);
TestImporter importer; TestImporter importer;
@ -141,6 +143,44 @@ private:
ASSERT_EQUALS(0, importer.fileSettings.size()); ASSERT_EQUALS(0, importer.fileSettings.size());
} }
void importCompileCommands5() const {
const char json[] =
"[{"
"\"directory\": \"C:/Users/dan/git/build-test-cppcheck-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug\","
"\"command\": \"C:\\\\PROGRA~2\\\\MICROS~1\\\\2019\\\\COMMUN~1\\\\VC\\\\Tools\\\\MSVC\\\\1427~1.291\\\\bin\\\\HostX64\\\\x64\\\\cl.exe /nologo /TP -IC:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src /DWIN32 /D_WINDOWS /GR /EHsc /Zi /Ob0 /Od /RTC1 -MDd -std:c++17 /Fomylib\\\\CMakeFiles\\\\mylib.dir\\\\src\\\\foobar\\\\mylib.cpp.obj /FdTARGET_COMPILE_PDB /FS -c C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src\\\\foobar\\\\mylib.cpp\","
"\"file\": \"C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src\\\\foobar\\\\mylib.cpp\""
"},"
"{"
"\"directory\": \"C:/Users/dan/git/build-test-cppcheck-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug\","
"\"command\": \"C:\\\\PROGRA~2\\\\MICROS~1\\\\2019\\\\COMMUN~1\\\\VC\\\\Tools\\\\MSVC\\\\1427~1.291\\\\bin\\\\HostX64\\\\x64\\\\cl.exe /nologo /TP -IC:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\myapp\\\\src -Imyapp -IC:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src /DWIN32 /D_WINDOWS /GR /EHsc /Zi /Ob0 /Od /RTC1 -MDd -std:c++17 /Fomyapp\\\\CMakeFiles\\\\myapp.dir\\\\src\\\\main.cpp.obj /FdTARGET_COMPILE_PDB /FS -c C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\myapp\\\\src\\\\main.cpp\","
"\"file\": \"C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\myapp\\\\src\\\\main.cpp\""
"}]";
std::istringstream istr(json);
TestImporter importer;
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 {
const char json[] =
"[{"
"\"directory\": \"C:/Users/dan/git/build-test-cppcheck-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug\","
"\"command\": \"C:\\\\PROGRA~2\\\\MICROS~1\\\\2019\\\\COMMUN~1\\\\VC\\\\Tools\\\\MSVC\\\\1427~1.291\\\\bin\\\\HostX64\\\\x64\\\\cl.exe /nologo /TP -IC:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src -I\\\"C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\second src\\\" /DWIN32 /D_WINDOWS /GR /EHsc /Zi /Ob0 /Od /RTC1 -MDd -std:c++17 /Fomylib\\\\CMakeFiles\\\\mylib.dir\\\\src\\\\foobar\\\\mylib.cpp.obj /FdTARGET_COMPILE_PDB /FS -c C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src\\\\foobar\\\\mylib.cpp\","
"\"file\": \"C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src\\\\foobar\\\\mylib.cpp\""
"},"
"{"
"\"directory\": \"C:/Users/dan/git/build-test-cppcheck-Desktop_Qt_5_15_0_MSVC2019_64bit-Debug\","
"\"command\": \"C:\\\\PROGRA~2\\\\MICROS~1\\\\2019\\\\COMMUN~1\\\\VC\\\\Tools\\\\MSVC\\\\1427~1.291\\\\bin\\\\HostX64\\\\x64\\\\cl.exe /nologo /TP -IC:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\myapp\\\\src -Imyapp -IC:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\mylib\\\\src /DWIN32 /D_WINDOWS /GR /EHsc /Zi /Ob0 /Od /RTC1 -MDd -std:c++17 /Fomyapp\\\\CMakeFiles\\\\myapp.dir\\\\src\\\\main.cpp.obj /FdTARGET_COMPILE_PDB /FS -c C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\myapp\\\\src\\\\main.cpp\","
"\"file\": \"C:\\\\Users\\\\dan\\\\git\\\\test-cppcheck\\\\myapp\\\\src\\\\main.cpp\""
"}]";
std::istringstream istr(json);
TestImporter importer;
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());
}
void importCompileCommandsArgumentsSection() const { void importCompileCommandsArgumentsSection() const {
const char json[] = "[ { \"directory\": \"/tmp/\"," const char json[] = "[ { \"directory\": \"/tmp/\","
"\"arguments\": [\"gcc\", \"-c\", \"src.c\"]," "\"arguments\": [\"gcc\", \"-c\", \"src.c\"],"